summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-25 18:24:10 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-25 18:24:10 +0000
commit89c42ab7cf12cbc07af1fc0e0921527e3e8b323c (patch)
tree2baebdd186c2a6d58f7901b4fe06513ed5911262
parenta54c078e2575f386a8427c8bcd6fb61fdebaf747 (diff)
downloadchromium_src-89c42ab7cf12cbc07af1fc0e0921527e3e8b323c.zip
chromium_src-89c42ab7cf12cbc07af1fc0e0921527e3e8b323c.tar.gz
chromium_src-89c42ab7cf12cbc07af1fc0e0921527e3e8b323c.tar.bz2
SyncFS: Reset resource_id in metadata when remote directory is deleted
Based on tzik@'s patch: https://codereview.chromium.org/12983006/ (Patch set 1 is the original change) - Resets sync_root_resource_id to empty when remote sync root folder is deleted - Resets origin directory ID to empty when remote origin folder is deleted - Runs EnsureOriginRootDirectory() in RegisterOrigin and ApplyLocalChange - Handles not-found errors in LocalSync gracefully BUG=177626 TEST=manual (see below) NOTRY=true 1a. launch sample app, create some files, delete the origin folder on Drive (both a. while app is running, and b. after a restart while app is not running) 1b. do the same with 1a but delete the sync root directory on Drive. 2. confirm local files are also deleted by sync 3. add some more new files in the sample app 4. see if the remote origin folder is re-created and the new files are sync'ed Review URL: https://chromiumcodereview.appspot.com/12967013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190443 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/sync_file_system/drive_file_sync_service.cc383
-rw-r--r--chrome/browser/sync_file_system/drive_file_sync_service.h49
-rw-r--r--chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc66
-rw-r--r--chrome/browser/sync_file_system/drive_metadata_store.cc90
-rw-r--r--chrome/browser/sync_file_system/drive_metadata_store.h12
-rw-r--r--chrome/browser/sync_file_system/drive_metadata_store_unittest.cc14
6 files changed, 405 insertions, 209 deletions
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service.cc b/chrome/browser/sync_file_system/drive_file_sync_service.cc
index b77d829..20f3bb4 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/drive_file_sync_service.cc
@@ -89,9 +89,8 @@ void DidHandleUnregisteredOrigin(const GURL& origin, SyncStatusCode status) {
}
FileChange CreateFileChange(bool is_deleted) {
- if (is_deleted) {
+ if (is_deleted)
return FileChange(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_UNKNOWN);
- }
return FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE);
}
@@ -392,30 +391,17 @@ void DriveFileSyncService::RegisterOriginForTrackingChanges(
return;
}
- if (metadata_store_->sync_root_directory().empty()) {
- GetSyncRootDirectory(
- token.Pass(),
- base::Bind(&DriveFileSyncService::DidGetSyncRootForRegisterOrigin,
- AsWeakPtr(), origin, callback));
- return;
- }
- sync_client_->EnsureSyncRootIsNotInMyDrive(
- metadata_store_->sync_root_directory());
-
- if (metadata_store_->IsIncrementalSyncOrigin(origin) ||
- metadata_store_->IsBatchSyncOrigin(origin)) {
+ DCHECK(!metadata_store_->IsOriginDisabled(origin));
+ if (!metadata_store_->GetResourceIdForOrigin(origin).empty()) {
token->ResetTask(FROM_HERE);
NotifyTaskDone(SYNC_STATUS_OK, token.Pass());
callback.Run(SYNC_STATUS_OK);
return;
}
- DCHECK(!metadata_store_->IsOriginDisabled(origin));
- DCHECK(!metadata_store_->sync_root_directory().empty());
- sync_client_->GetDriveDirectoryForOrigin(
- metadata_store_->sync_root_directory(), origin,
- base::Bind(&DriveFileSyncService::DidGetDriveDirectoryForOrigin,
- AsWeakPtr(), base::Passed(&token), origin, callback));
+ EnsureOriginRootDirectory(
+ origin, base::Bind(&DriveFileSyncService::DidGetDriveDirectoryForOrigin,
+ AsWeakPtr(), base::Passed(&token), origin, callback));
}
void DriveFileSyncService::UnregisterOriginForTrackingChanges(
@@ -510,18 +496,19 @@ void DriveFileSyncService::UninstallOrigin(
return;
}
- // If origin is not in metadata_store_ then it means the extension was never
- // run and thus no origin directory on the remote drive was created.
- if (!metadata_store_->IsBatchSyncOrigin(origin) &&
- !metadata_store_->IsIncrementalSyncOrigin(origin) &&
- !metadata_store_->IsOriginDisabled(origin)) {
+ std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
+
+ // An empty resource_id indicates either one of following two cases:
+ // 1) origin is not in metadata_store_ because the extension was never
+ // run and thus no origin directory on the remote drive was created.
+ // 2) origin or sync root folder is deleted on Drive.
+ if (resource_id.empty()) {
callback.Run(SYNC_STATUS_OK);
return;
}
// Convert origin's directory GURL to ResourceID and delete it. Expected MD5
// is empty to force delete (i.e. skip conflict resolution).
- std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
sync_client_->DeleteFile(
resource_id,
std::string(),
@@ -684,64 +671,13 @@ void DriveFileSyncService::ApplyLocalChange(
scoped_ptr<ApplyLocalChangeParam> param(new ApplyLocalChangeParam(
token.Pass(), url,
local_file_change, local_file_path, local_file_metadata, callback));
- DriveFileSyncService::LocalSyncOperationType operation =
+ LocalSyncOperationType operation =
ResolveLocalSyncOperationType(local_file_change, url, param.get());
- DriveMetadata& drive_metadata = param->drive_metadata;
-
- DVLOG(1) << "ApplyLocalChange for " << url.DebugString()
- << " local_change:" << local_file_change.DebugString()
- << " ==> operation:" << operation;
- switch (operation) {
- case LOCAL_SYNC_OPERATION_ADD: {
- sync_client_->UploadNewFile(
- metadata_store_->GetResourceIdForOrigin(url.origin()),
- local_file_path,
- url.path().AsUTF8Unsafe(),
- base::Bind(&DriveFileSyncService::DidUploadNewFileForLocalSync,
- AsWeakPtr(), base::Passed(&param)));
- return;
- }
- case LOCAL_SYNC_OPERATION_UPDATE: {
- DCHECK(param->has_drive_metadata);
- sync_client_->UploadExistingFile(
- drive_metadata.resource_id(),
- drive_metadata.md5_checksum(),
- local_file_path,
- base::Bind(&DriveFileSyncService::DidUploadExistingFileForLocalSync,
- AsWeakPtr(), base::Passed(&param)));
- return;
- }
- case LOCAL_SYNC_OPERATION_DELETE: {
- DCHECK(param->has_drive_metadata);
- sync_client_->DeleteFile(
- drive_metadata.resource_id(),
- drive_metadata.md5_checksum(),
- base::Bind(&DriveFileSyncService::DidDeleteFileForLocalSync,
- AsWeakPtr(), base::Passed(&param)));
- return;
- }
- case LOCAL_SYNC_OPERATION_NONE_CONFLICTED:
- // The file is already conflicted.
- HandleConflictForLocalSync(param.Pass());
- return;
- case LOCAL_SYNC_OPERATION_NONE:
- FinalizeLocalSync(param->token.Pass(), callback, SYNC_STATUS_OK);
- return;
- case LOCAL_SYNC_OPERATION_CONFLICT:
- HandleConflictForLocalSync(param.Pass());
- return;
- case LOCAL_SYNC_OPERATION_RESOLVE_TO_REMOTE: {
- ResolveConflictToRemoteForLocalSync(param.Pass());
- return;
- }
- case LOCAL_SYNC_OPERATION_FAIL: {
- FinalizeLocalSync(param->token.Pass(), callback, SYNC_STATUS_FAILED);
- return;
- }
- }
- NOTREACHED();
- FinalizeLocalSync(param->token.Pass(), callback, SYNC_STATUS_FAILED);
+ EnsureOriginRootDirectory(
+ url.origin(),
+ base::Bind(&DriveFileSyncService::ApplyLocalChangeInternal,
+ AsWeakPtr(), base::Passed(&param), operation));
}
void DriveFileSyncService::OnAuthenticated() {
@@ -828,6 +764,8 @@ void DriveFileSyncService::NotifyTaskDone(SyncStatusCode status,
last_operation_status_ = status;
token_ = token.Pass();
TRACE_EVENT_ASYNC_END0("Sync FileSystem", "GetToken", this);
+ if (status != SYNC_STATUS_OK)
+ DVLOG(2) << "DriveFileSyncService Task failed: " << status;
if (token_->task_type() != TASK_TYPE_NONE) {
DVLOG(2) << "NotifyTaskDone: " << token_->description()
@@ -950,14 +888,6 @@ void DriveFileSyncService::DidInitializeMetadataStore(
pending_batch_sync_origins_.insert(itr->first);
}
- if (metadata_store_->sync_root_directory().empty()) {
- // It's ok to fail, so we pass EmptyResourceIdCallback here.
- GetSyncRootDirectory(token.Pass(), base::Bind(&EmptyStatusCallback));
- return;
- }
- sync_client_->EnsureSyncRootIsNotInMyDrive(
- metadata_store_->sync_root_directory());
-
DriveMetadataStore::URLAndResourceIdList to_be_fetched_files;
status = metadata_store_->GetToBeFetchedFiles(&to_be_fetched_files);
DCHECK_EQ(SYNC_STATUS_OK, status);
@@ -970,6 +900,9 @@ void DriveFileSyncService::DidInitializeMetadataStore(
AppendFetchChange(url.origin(), url.path(), resource_id);
}
+ if (!sync_root_resource_id().empty())
+ sync_client_->EnsureSyncRootIsNotInMyDrive(sync_root_resource_id());
+
NotifyTaskDone(status, token.Pass());
RegisterDriveNotifications();
}
@@ -1031,50 +964,6 @@ void DriveFileSyncService::UpdateRegisteredOrigins() {
}
}
-void DriveFileSyncService::GetSyncRootDirectory(
- scoped_ptr<TaskToken> token,
- const SyncStatusCallback& callback) {
- DCHECK(metadata_store_->sync_root_directory().empty());
- DCHECK(metadata_store_->batch_sync_origins().empty());
- DCHECK(metadata_store_->incremental_sync_origins().empty());
- DCHECK(metadata_store_->disabled_origins().empty());
-
- token->UpdateTask(FROM_HERE, TASK_TYPE_DRIVE, "Retrieving drive root");
- sync_client_->GetDriveDirectoryForSyncRoot(
- base::Bind(&DriveFileSyncService::DidGetSyncRootDirectory,
- AsWeakPtr(), base::Passed(&token), callback));
-}
-
-void DriveFileSyncService::DidGetSyncRootDirectory(
- scoped_ptr<TaskToken> token,
- const SyncStatusCallback& callback,
- google_apis::GDataErrorCode error,
- const std::string& sync_root_resource_id) {
- SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
- if (error != google_apis::HTTP_SUCCESS &&
- error != google_apis::HTTP_CREATED) {
- NotifyTaskDone(status, token.Pass());
- callback.Run(status);
- return;
- }
-
- metadata_store_->SetSyncRootDirectory(sync_root_resource_id);
-
- NotifyTaskDone(SYNC_STATUS_OK, token.Pass());
- callback.Run(status);
-}
-
-void DriveFileSyncService::DidGetSyncRootForRegisterOrigin(
- const GURL& origin,
- const SyncStatusCallback& callback,
- SyncStatusCode status) {
- if (status != SYNC_STATUS_OK) {
- callback.Run(status);
- return;
- }
- RegisterOriginForTrackingChanges(origin, callback);
-}
-
void DriveFileSyncService::StartBatchSyncForOrigin(
const GURL& origin,
const std::string& resource_id) {
@@ -1097,19 +986,19 @@ void DriveFileSyncService::DidGetDriveDirectoryForOrigin(
scoped_ptr<TaskToken> token,
const GURL& origin,
const SyncStatusCallback& callback,
- google_apis::GDataErrorCode error,
+ SyncStatusCode status,
const std::string& resource_id) {
- if (error != google_apis::HTTP_SUCCESS &&
- error != google_apis::HTTP_CREATED) {
- SyncStatusCode status =
- GDataErrorCodeToSyncStatusCodeWrapper(error);
+ if (status != SYNC_STATUS_OK) {
NotifyTaskDone(status, token.Pass());
callback.Run(status);
return;
}
- metadata_store_->AddBatchSyncOrigin(origin, resource_id);
- pending_batch_sync_origins_.insert(origin);
+ // Add this origin to batch sync origin if it hasn't been already.
+ if (!metadata_store_->IsKnownOrigin(origin)) {
+ metadata_store_->AddBatchSyncOrigin(origin, resource_id);
+ pending_batch_sync_origins_.insert(origin);
+ }
NotifyTaskDone(SYNC_STATUS_OK, token.Pass());
callback.Run(SYNC_STATUS_OK);
@@ -1234,6 +1123,78 @@ void DriveFileSyncService::DidGetRemoteFileMetadata(
entry->updated_time()));
}
+void DriveFileSyncService::ApplyLocalChangeInternal(
+ scoped_ptr<ApplyLocalChangeParam> param,
+ LocalSyncOperationType operation,
+ SyncStatusCode status,
+ const std::string& origin_resource_id) {
+ if (status != SYNC_STATUS_OK) {
+ FinalizeLocalSync(param->token.Pass(), param->callback, status);
+ return;
+ }
+
+ const FileSystemURL& url = param->url;
+ const FileChange& local_file_change = param->local_change;
+ const base::FilePath& local_file_path = param->local_path;
+ DriveMetadata& drive_metadata = param->drive_metadata;
+ const SyncStatusCallback& callback = param->callback;
+
+ DVLOG(1) << "ApplyLocalChange for " << url.DebugString()
+ << " local_change:" << local_file_change.DebugString()
+ << " ==> operation:" << operation;
+
+ switch (operation) {
+ case LOCAL_SYNC_OPERATION_ADD: {
+ sync_client_->UploadNewFile(
+ origin_resource_id,
+ local_file_path,
+ url.path().AsUTF8Unsafe(),
+ base::Bind(&DriveFileSyncService::DidUploadNewFileForLocalSync,
+ AsWeakPtr(), base::Passed(&param)));
+ return;
+ }
+ case LOCAL_SYNC_OPERATION_UPDATE: {
+ DCHECK(param->has_drive_metadata);
+ sync_client_->UploadExistingFile(
+ drive_metadata.resource_id(),
+ drive_metadata.md5_checksum(),
+ local_file_path,
+ base::Bind(&DriveFileSyncService::DidUploadExistingFileForLocalSync,
+ AsWeakPtr(), base::Passed(&param)));
+ return;
+ }
+ case LOCAL_SYNC_OPERATION_DELETE: {
+ DCHECK(param->has_drive_metadata);
+ sync_client_->DeleteFile(
+ drive_metadata.resource_id(),
+ drive_metadata.md5_checksum(),
+ base::Bind(&DriveFileSyncService::DidDeleteFileForLocalSync,
+ AsWeakPtr(), base::Passed(&param)));
+ return;
+ }
+ case LOCAL_SYNC_OPERATION_NONE_CONFLICTED:
+ // The file is already conflicted.
+ HandleConflictForLocalSync(param.Pass());
+ return;
+ case LOCAL_SYNC_OPERATION_NONE:
+ FinalizeLocalSync(param->token.Pass(), callback, SYNC_STATUS_OK);
+ return;
+ case LOCAL_SYNC_OPERATION_CONFLICT:
+ HandleConflictForLocalSync(param.Pass());
+ return;
+ case LOCAL_SYNC_OPERATION_RESOLVE_TO_REMOTE: {
+ ResolveConflictToRemoteForLocalSync(param.Pass());
+ return;
+ }
+ case LOCAL_SYNC_OPERATION_FAIL: {
+ FinalizeLocalSync(param->token.Pass(), callback, SYNC_STATUS_FAILED);
+ return;
+ }
+ }
+ NOTREACHED();
+ FinalizeLocalSync(param->token.Pass(), callback, SYNC_STATUS_FAILED);
+}
+
DriveFileSyncService::LocalSyncOperationType
DriveFileSyncService::ResolveLocalSyncOperationType(
const FileChange& local_file_change,
@@ -1399,6 +1360,16 @@ void DriveFileSyncService::DidUploadExistingFileForLocalSync(
google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
return;
}
+ case google_apis::HTTP_NOT_FOUND: {
+ const base::FilePath& local_file_path = param->local_path;
+ sync_client_->UploadNewFile(
+ metadata_store_->GetResourceIdForOrigin(url.origin()),
+ local_file_path,
+ url.path().AsUTF8Unsafe(),
+ base::Bind(&DriveFileSyncService::DidUploadNewFileForLocalSync,
+ AsWeakPtr(), base::Passed(&param)));
+ return;
+ }
default: {
const SyncStatusCode status =
GDataErrorCodeToSyncStatusCodeWrapper(error);
@@ -1434,6 +1405,10 @@ void DriveFileSyncService::DidDeleteFileForLocalSync(
SYNC_ACTION_DELETED,
SYNC_DIRECTION_LOCAL_TO_REMOTE);
return;
+ case google_apis::HTTP_NOT_FOUND:
+ DidApplyLocalChange(param.Pass(),
+ google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
+ return;
default: {
const SyncStatusCode status =
GDataErrorCodeToSyncStatusCodeWrapper(error);
@@ -2177,6 +2152,7 @@ void DriveFileSyncService::MaybeStartFetchChanges() {
GURL origin = *pending_batch_sync_origins_.begin();
pending_batch_sync_origins_.erase(pending_batch_sync_origins_.begin());
std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
+ DCHECK(!resource_id.empty());
StartBatchSyncForOrigin(origin, resource_id);
}
return;
@@ -2217,16 +2193,30 @@ void DriveFileSyncService::DidFetchChangesForIncrementalSync(
return;
}
+ bool reset_sync_root = false;
+ std::set<GURL> reset_origins;
+
typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator;
for (iterator itr = changes->entries().begin();
itr != changes->entries().end(); ++itr) {
const google_apis::ResourceEntry& entry = **itr;
- // TODO(tzik): Handle rename/delete of the sync root directory and the
- // directory for a origin.
- // http://crbug.com/177626
- HandleSyncRootDirectoryChange(entry);
- HandleOriginRootDirectoryChange(entry);
+ if (entry.deleted()) {
+ // Check if the sync root or origin root folder is deleted.
+ // (We reset resource_id after the for loop so that we can handle
+ // recursive delete for the origin (at least in this feed)
+ // while GetOriginForEntry for the origin still works.)
+ if (entry.resource_id() == sync_root_resource_id()) {
+ reset_sync_root = true;
+ continue;
+ }
+ GURL origin;
+ if (metadata_store_->GetOriginByOriginRootDirectoryId(
+ entry.resource_id(), &origin)) {
+ reset_origins.insert(origin);
+ continue;
+ }
+ }
GURL origin;
if (!GetOriginForEntry(entry, &origin))
@@ -2240,6 +2230,17 @@ void DriveFileSyncService::DidFetchChangesForIncrementalSync(
REMOTE_SYNC_TYPE_INCREMENTAL) || has_new_changes;
}
+ if (reset_sync_root) {
+ LOG(WARNING) << "Detected unexpected SyncRoot deletion.";
+ metadata_store_->SetSyncRootDirectory(std::string());
+ }
+ for (std::set<GURL>::iterator itr = reset_origins.begin();
+ itr != reset_origins.end(); ++itr) {
+ LOG(WARNING) << "Detected unexpected OriginRoot deletion:" << itr->spec();
+ pending_batch_sync_origins_.erase(*itr);
+ metadata_store_->SetOriginRootDirectory(*itr, std::string());
+ }
+
GURL next_feed;
if (changes->GetNextFeedURL(&next_feed)) {
sync_client_->ContinueListing(
@@ -2263,24 +2264,6 @@ void DriveFileSyncService::DidFetchChangesForIncrementalSync(
NotifyTaskDone(SYNC_STATUS_OK, token.Pass());
}
-void DriveFileSyncService::HandleSyncRootDirectoryChange(
- const google_apis::ResourceEntry& entry) {
- if (entry.resource_id() != metadata_store_->sync_root_directory())
- return;
-
- NOTIMPLEMENTED();
-}
-
-void DriveFileSyncService::HandleOriginRootDirectoryChange(
- const google_apis::ResourceEntry& entry) {
- GURL origin;
- if (!metadata_store_->GetOriginByOriginRootDirectoryId(
- entry.resource_id(), &origin))
- return;
-
- NOTIMPLEMENTED();
-}
-
bool DriveFileSyncService::GetOriginForEntry(
const google_apis::ResourceEntry& entry,
GURL* origin_out) {
@@ -2296,6 +2279,8 @@ bool DriveFileSyncService::GetOriginForEntry(
!metadata_store_->IsIncrementalSyncOrigin(origin))
continue;
std::string resource_id(metadata_store_->GetResourceIdForOrigin(origin));
+ if (resource_id.empty())
+ continue;
GURL resource_link(sync_client_->ResourceIdToResourceLink(resource_id));
if ((*itr)->href().GetOrigin() != resource_link.GetOrigin() ||
(*itr)->href().path() != resource_link.path())
@@ -2416,4 +2401,74 @@ void DriveFileSyncService::NotifyObserversFileStatusChanged(
OnFileStatusChanged(url, sync_status, action_taken, direction));
}
+void DriveFileSyncService::EnsureSyncRootDirectory(
+ const ResourceIdCallback& callback) {
+ if (!sync_root_resource_id().empty()) {
+ callback.Run(SYNC_STATUS_OK, sync_root_resource_id());
+ return;
+ }
+
+ sync_client_->GetDriveDirectoryForSyncRoot(base::Bind(
+ &DriveFileSyncService::DidEnsureSyncRoot, AsWeakPtr(), callback));
+}
+
+void DriveFileSyncService::DidEnsureSyncRoot(
+ const ResourceIdCallback& callback,
+ google_apis::GDataErrorCode error,
+ const std::string& sync_root_resource_id) {
+ SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
+ if (status == SYNC_STATUS_OK)
+ metadata_store_->SetSyncRootDirectory(sync_root_resource_id);
+ callback.Run(status, sync_root_resource_id);
+}
+
+void DriveFileSyncService::EnsureOriginRootDirectory(
+ const GURL& origin,
+ const ResourceIdCallback& callback) {
+ std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
+ if (!resource_id.empty()) {
+ callback.Run(SYNC_STATUS_OK, resource_id);
+ return;
+ }
+
+ EnsureSyncRootDirectory(base::Bind(
+ &DriveFileSyncService::DidEnsureSyncRootForOriginRoot,
+ AsWeakPtr(), origin, callback));
+}
+
+void DriveFileSyncService::DidEnsureSyncRootForOriginRoot(
+ const GURL& origin,
+ const ResourceIdCallback& callback,
+ SyncStatusCode status,
+ const std::string& sync_root_resource_id) {
+ if (status != SYNC_STATUS_OK) {
+ callback.Run(status, std::string());
+ return;
+ }
+
+ sync_client_->GetDriveDirectoryForOrigin(
+ sync_root_resource_id, origin,
+ base::Bind(&DriveFileSyncService::DidEnsureOriginRoot,
+ AsWeakPtr(), origin, callback));
+}
+
+void DriveFileSyncService::DidEnsureOriginRoot(
+ const GURL& origin,
+ const ResourceIdCallback& callback,
+ google_apis::GDataErrorCode error,
+ const std::string& resource_id) {
+ SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
+ if (status == SYNC_STATUS_OK &&
+ metadata_store_->IsKnownOrigin(origin)) {
+ metadata_store_->SetOriginRootDirectory(origin, resource_id);
+ if (metadata_store_->IsBatchSyncOrigin(origin))
+ pending_batch_sync_origins_.insert(origin);
+ }
+ callback.Run(status, resource_id);
+}
+
+std::string DriveFileSyncService::sync_root_resource_id() {
+ return metadata_store_->sync_root_directory();
+}
+
} // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service.h b/chrome/browser/sync_file_system/drive_file_sync_service.h
index 6eaa4aa..5dc6928 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_service.h
+++ b/chrome/browser/sync_file_system/drive_file_sync_service.h
@@ -207,6 +207,9 @@ class DriveFileSyncService
typedef base::Callback<void(const base::Time& time,
SyncStatusCode status)> UpdatedTimeCallback;
+ typedef base::Callback<
+ void(SyncStatusCode status,
+ const std::string& resource_id)> ResourceIdCallback;
DriveFileSyncService(Profile* profile,
const base::FilePath& base_dir,
@@ -233,6 +236,11 @@ class DriveFileSyncService
// Resolves LocalSync operation type. If non-null |param| is given
// the method also populates param->has_drive_metadata and
// param->drive_metadata fields.
+ void ApplyLocalChangeInternal(
+ scoped_ptr<ApplyLocalChangeParam> param,
+ LocalSyncOperationType operation,
+ SyncStatusCode status,
+ const std::string& resource_id);
LocalSyncOperationType ResolveLocalSyncOperationType(
const FileChange& local_file_change,
const fileapi::FileSystemURL& url,
@@ -272,28 +280,32 @@ class DriveFileSyncService
SyncStatusCode status);
void ResolveConflictToRemoteForLocalSync(
scoped_ptr<ApplyLocalChangeParam> param);
+ void DidEnsureOriginRootForUploadNewFile(
+ scoped_ptr<ApplyLocalChangeParam> param,
+ SyncStatusCode status,
+ const std::string& parent_resource_id);
void DidInitializeMetadataStore(scoped_ptr<TaskToken> token,
SyncStatusCode status,
bool created);
void UpdateRegisteredOrigins();
- void GetSyncRootDirectory(scoped_ptr<TaskToken> token,
- const SyncStatusCallback& callback);
- void DidGetSyncRootDirectory(scoped_ptr<TaskToken> token,
- const SyncStatusCallback& callback,
- google_apis::GDataErrorCode error,
- const std::string& sync_root_resource_id);
void DidGetSyncRootForRegisterOrigin(
+ scoped_ptr<TaskToken> token,
const GURL& origin,
const SyncStatusCallback& callback,
- SyncStatusCode status);
+ google_apis::GDataErrorCode error,
+ const std::string& sync_root_resource_id);
void StartBatchSyncForOrigin(const GURL& origin,
const std::string& resource_id);
+ void GetDriveDirectoryForOrigin(scoped_ptr<TaskToken> token,
+ const GURL& origin,
+ const SyncStatusCallback& callback,
+ const std::string& sync_root_resource_id);
void DidGetDriveDirectoryForOrigin(scoped_ptr<TaskToken> token,
const GURL& origin,
const SyncStatusCallback& callback,
- google_apis::GDataErrorCode error,
+ SyncStatusCode status,
const std::string& resource_id);
void DidUninstallOrigin(scoped_ptr<TaskToken> token,
const GURL& origin,
@@ -432,6 +444,27 @@ class DriveFileSyncService
void HandleSyncRootDirectoryChange(const google_apis::ResourceEntry& entry);
void HandleOriginRootDirectoryChange(const google_apis::ResourceEntry& entry);
+ void EnsureSyncRootDirectory(const ResourceIdCallback& callback);
+ void DidEnsureSyncRoot(const ResourceIdCallback& callback,
+ google_apis::GDataErrorCode error,
+ const std::string& sync_root_resource_id);
+ void EnsureOriginRootDirectory(const GURL& origin,
+ const ResourceIdCallback& callback);
+ void DidEnsureSyncRootForOriginRoot(const GURL& origin,
+ const ResourceIdCallback& callback,
+ SyncStatusCode status,
+ const std::string& sync_root_resource_id);
+ void DidEnsureOriginRoot(const GURL& origin,
+ const ResourceIdCallback& callback,
+ google_apis::GDataErrorCode error,
+ const std::string& resource_id);
+
+ // This function returns Resouce ID for the sync root directory if available.
+ // Returns an empty string 1) when the resource ID has not been initialized
+ // yet, and 2) after the service has detected the remote sync root folder was
+ // removed.
+ std::string sync_root_resource_id();
+
scoped_ptr<DriveMetadataStore> metadata_store_;
scoped_ptr<DriveFileSyncClientInterface> sync_client_;
diff --git a/chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc b/chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc
index fe6882c..2096bad 100644
--- a/chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_file_sync_service_mock_unittest.cc
@@ -38,6 +38,7 @@
using ::testing::AnyNumber;
using ::testing::AtLeast;
+using ::testing::AtMost;
using ::testing::InSequence;
using ::testing::Return;
using ::testing::Sequence;
@@ -76,6 +77,13 @@ void DidUpdateEntry(SyncStatusCode status) {
EXPECT_EQ(SYNC_STATUS_OK, status);
}
+void DidGetSyncRoot(bool* done,
+ SyncStatusCode status,
+ const std::string& resource_id) {
+ EXPECT_FALSE(*done);
+ *done = true;
+}
+
void ExpectEqStatus(bool* done,
SyncStatusCode expected,
SyncStatusCode actual) {
@@ -470,7 +478,7 @@ class DriveFileSyncServiceMockTest : public testing::Test {
const std::string& query,
const std::string& search_directory) {
scoped_ptr<Value> result_value(LoadJSONFile(
- result_mock_json_name));
+ result_mock_json_name));
scoped_ptr<google_apis::ResourceList> result(
google_apis::ResourceList::ExtractAndParse(*result_value));
EXPECT_CALL(*mock_drive_service(),
@@ -482,10 +490,18 @@ class DriveFileSyncServiceMockTest : public testing::Test {
}
void SetUpDriveServiceExpectCallsForGetSyncRoot() {
- SetUpDriveServiceExpectCallsForGetResourceList(
- "chromeos/sync_file_system/sync_root_found.json",
- FormatTitleQuery(kSyncRootDirectoryName),
- std::string());
+ scoped_ptr<Value> result_value(LoadJSONFile(
+ "chromeos/sync_file_system/sync_root_found.json"));
+ scoped_ptr<google_apis::ResourceList> result(
+ google_apis::ResourceList::ExtractAndParse(*result_value));
+ EXPECT_CALL(*mock_drive_service(), GetResourceList(
+ GURL(), 0, FormatTitleQuery(kSyncRootDirectoryName),
+ false, std::string(), _))
+ .Times(AtMost(1))
+ .WillOnce(InvokeGetResourceListCallback5(
+ google_apis::HTTP_SUCCESS,
+ base::Passed(&result)))
+ .RetiresOnSaturation();
}
void SetUpDriveServiceExpectCallsForGetAboutResource() {
@@ -564,26 +580,6 @@ class DriveFileSyncServiceMockTest : public testing::Test {
#if !defined(OS_ANDROID)
-TEST_F(DriveFileSyncServiceMockTest, GetSyncRoot) {
- SetUpDriveServiceExpectCallsForGetSyncRoot();
-
- EXPECT_CALL(*mock_remote_observer(),
- OnRemoteServiceStateUpdated(REMOTE_SERVICE_OK, _))
- .Times(1);
- EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(0))
- .Times(AnyNumber());
-
- SetUpDriveSyncService(true);
- message_loop()->RunUntilIdle();
-
- EXPECT_EQ("folder:sync_root_resource_id",
- metadata_store()->sync_root_directory());
-
- EXPECT_EQ(0u, metadata_store()->batch_sync_origins().size());
- EXPECT_EQ(0u, metadata_store()->incremental_sync_origins().size());
- EXPECT_EQ(0u, pending_changes().size());
-}
-
TEST_F(DriveFileSyncServiceMockTest, BatchSyncOnInitialization) {
const GURL kOrigin1 = ExtensionNameToGURL(FPL("example1"));
const GURL kOrigin2 = ExtensionNameToGURL(FPL("example2"));
@@ -604,7 +600,9 @@ TEST_F(DriveFileSyncServiceMockTest, BatchSyncOnInitialization) {
EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(3))
.InSequence(change_queue_seq);
- InSequence sequence;
+ EXPECT_CALL(*mock_remote_observer(),
+ OnRemoteServiceStateUpdated(REMOTE_SERVICE_OK, _))
+ .Times(AnyNumber());
SetUpDriveServiceExpectCallsForGetAboutResource();
SetUpDriveServiceExpectCallsForGetResourceList(
@@ -614,7 +612,7 @@ TEST_F(DriveFileSyncServiceMockTest, BatchSyncOnInitialization) {
EXPECT_CALL(*mock_remote_observer(),
OnRemoteServiceStateUpdated(REMOTE_SERVICE_OK, _))
- .Times(1);
+ .Times(AnyNumber());
SetUpDriveSyncService(true);
message_loop()->RunUntilIdle();
@@ -642,6 +640,10 @@ TEST_F(DriveFileSyncServiceMockTest, RegisterNewOrigin) {
EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(0))
.Times(AnyNumber());
+ // Expect to call GetResourceList for the sync root from
+ // RegisterOriginForTrackingChanges.
+ SetUpDriveServiceExpectCallsForGetSyncRoot();
+
SetUpDriveServiceExpectCallsForGetResourceList(
"chromeos/sync_file_system/origin_directory_found.json",
FormatTitleQuery(DriveFileSyncClient::OriginToDirectoryTitle(kOrigin)),
@@ -693,6 +695,10 @@ TEST_F(DriveFileSyncServiceMockTest, RegisterExistingOrigin) {
InSequence sequence;
+ // Expect to call GetResourceList for the sync root from
+ // RegisterOriginForTrackingChanges.
+ SetUpDriveServiceExpectCallsForGetSyncRoot();
+
// We already have a directory for the origin.
SetUpDriveServiceExpectCallsForGetResourceList(
"chromeos/sync_file_system/origin_directory_found.json",
@@ -781,7 +787,7 @@ TEST_F(DriveFileSyncServiceMockTest, ResolveLocalSyncOperationType) {
EXPECT_CALL(*mock_remote_observer(),
OnRemoteServiceStateUpdated(REMOTE_SERVICE_OK, _))
- .Times(1);
+ .Times(AnyNumber());
EXPECT_CALL(*mock_remote_observer(), OnRemoteChangeQueueUpdated(_))
.Times(AnyNumber());
@@ -1009,6 +1015,10 @@ TEST_F(DriveFileSyncServiceMockTest, RegisterOriginWithSyncDisabled) {
InSequence sequence;
+ // Expect to call GetResourceList for the sync root from
+ // RegisterOriginForTrackingChanges.
+ SetUpDriveServiceExpectCallsForGetSyncRoot();
+
SetUpDriveServiceExpectCallsForGetResourceList(
"chromeos/sync_file_system/origin_directory_found.json",
FormatTitleQuery(DriveFileSyncClient::OriginToDirectoryTitle(kOrigin)),
diff --git a/chrome/browser/sync_file_system/drive_metadata_store.cc b/chrome/browser/sync_file_system/drive_metadata_store.cc
index 7bb9027..255e5a8 100644
--- a/chrome/browser/sync_file_system/drive_metadata_store.cc
+++ b/chrome/browser/sync_file_system/drive_metadata_store.cc
@@ -91,10 +91,26 @@ void MetadataKeyToOriginAndPath(const std::string& metadata_key,
key_body.substr(separator_position + 1));
}
+bool UpdateResourceIdMap(ResourceIdByOrigin* map,
+ const GURL& origin,
+ const std::string& resource_id) {
+ ResourceIdByOrigin::iterator found = map->find(origin);
+ if (found == map->end())
+ return false;
+ found->second = resource_id;
+ return true;
+}
+
} // namespace
class DriveMetadataDB {
public:
+ enum OriginSyncType {
+ BATCH_SYNC_ORIGIN,
+ INCREMENTAL_SYNC_ORIGIN,
+ DISABLED_ORIGIN
+ };
+
typedef DriveMetadataStore::MetadataMap MetadataMap;
DriveMetadataDB(const base::FilePath& base_dir,
@@ -110,6 +126,9 @@ class DriveMetadataDB {
SyncStatusCode SetLargestChangestamp(int64 largest_changestamp);
SyncStatusCode SetSyncRootDirectory(const std::string& resource_id);
SyncStatusCode GetSyncRootDirectory(std::string* resource_id);
+ SyncStatusCode SetOriginRootDirectory(const GURL& origin,
+ OriginSyncType sync_type,
+ const std::string& resource_id);
SyncStatusCode UpdateEntry(const FileSystemURL& url,
const DriveMetadata& metadata);
SyncStatusCode DeleteEntry(const FileSystemURL& url);
@@ -183,6 +202,21 @@ SyncStatusCode InitializeDBOnFileThread(DriveMetadataDB* db,
return db->ReadContents(contents);
}
+std::string CreateKeyForOriginRoot(const GURL& origin,
+ DriveMetadataDB::OriginSyncType sync_type) {
+ DCHECK(origin.is_valid());
+ switch (sync_type) {
+ case DriveMetadataDB::BATCH_SYNC_ORIGIN:
+ return kDriveBatchSyncOriginKeyPrefix + origin.spec();
+ case DriveMetadataDB::INCREMENTAL_SYNC_ORIGIN:
+ return kDriveIncrementalSyncOriginKeyPrefix + origin.spec();
+ case DriveMetadataDB::DISABLED_ORIGIN:
+ return kDriveDisabledOriginKeyPrefix + origin.spec();
+ }
+ NOTREACHED();
+ return std::string();
+}
+
// Returns a key string for the given batch sync origin.
// For example, when |origin| is "http://www.example.com",
// returns "BSYNC_ORIGIN: http://www.example.com".
@@ -458,8 +492,6 @@ SyncStatusCode DriveMetadataStore::ReadEntry(const FileSystemURL& url,
void DriveMetadataStore::SetSyncRootDirectory(const std::string& resource_id) {
DCHECK(CalledOnValidThread());
- DCHECK(!resource_id.empty());
- DCHECK(sync_root_directory_resource_id_.empty());
sync_root_directory_resource_id_ = resource_id;
@@ -471,6 +503,35 @@ void DriveMetadataStore::SetSyncRootDirectory(const std::string& resource_id) {
base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr()));
}
+void DriveMetadataStore::SetOriginRootDirectory(
+ const GURL& origin,
+ const std::string& resource_id) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(IsKnownOrigin(origin));
+
+ DriveMetadataDB::OriginSyncType sync_type;
+ if (UpdateResourceIdMap(&batch_sync_origins_, origin, resource_id))
+ sync_type = DriveMetadataDB::BATCH_SYNC_ORIGIN;
+ else if (UpdateResourceIdMap(&incremental_sync_origins_, origin, resource_id))
+ sync_type = DriveMetadataDB::INCREMENTAL_SYNC_ORIGIN;
+ else if (UpdateResourceIdMap(&disabled_origins_, origin, resource_id))
+ sync_type = DriveMetadataDB::DISABLED_ORIGIN;
+ else
+ return;
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_, FROM_HERE,
+ base::Bind(&DriveMetadataDB::SetOriginRootDirectory,
+ base::Unretained(db_.get()), origin, sync_type, resource_id),
+ base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr()));
+}
+
+bool DriveMetadataStore::IsKnownOrigin(const GURL& origin) const {
+ DCHECK(CalledOnValidThread());
+ return IsBatchSyncOrigin(origin) ||
+ IsIncrementalSyncOrigin(origin) ||
+ IsOriginDisabled(origin);
+}
+
bool DriveMetadataStore::IsBatchSyncOrigin(const GURL& origin) const {
DCHECK(CalledOnValidThread());
return ContainsKey(batch_sync_origins_, origin);
@@ -680,9 +741,12 @@ SyncStatusCode DriveMetadataStore::GetToBeFetchedFiles(
std::string DriveMetadataStore::GetResourceIdForOrigin(
const GURL& origin) const {
DCHECK(CalledOnValidThread());
- DCHECK(IsBatchSyncOrigin(origin) ||
- IsIncrementalSyncOrigin(origin) ||
- IsOriginDisabled(origin));
+
+ // If we don't have valid root directory (this could be reset even after
+ // initialized) just return empty string, as the origin directories
+ // in the root directory must have become invalid now too.
+ if (sync_root_directory().empty())
+ return std::string();
ResourceIdByOrigin::const_iterator found =
incremental_sync_origins_.find(origin);
@@ -697,7 +761,6 @@ std::string DriveMetadataStore::GetResourceIdForOrigin(
if (found != disabled_origins_.end())
return found->second;
- NOTREACHED();
return std::string();
}
@@ -935,6 +998,21 @@ SyncStatusCode DriveMetadataDB::SetSyncRootDirectory(
return LevelDBStatusToSyncStatusCode(status);
}
+SyncStatusCode DriveMetadataDB::SetOriginRootDirectory(
+ const GURL& origin,
+ OriginSyncType sync_type,
+ const std::string& resource_id) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(db_.get());
+
+ std::string key = CreateKeyForOriginRoot(origin, sync_type);
+ if (key.empty())
+ return SYNC_DATABASE_ERROR_FAILED;
+
+ leveldb::Status status = db_->Put(leveldb::WriteOptions(), key, resource_id);
+ return LevelDBStatusToSyncStatusCode(status);
+}
+
SyncStatusCode DriveMetadataDB::GetSyncRootDirectory(std::string* resource_id) {
DCHECK(CalledOnValidThread());
DCHECK(db_.get());
diff --git a/chrome/browser/sync_file_system/drive_metadata_store.h b/chrome/browser/sync_file_system/drive_metadata_store.h
index 16771ee..b11269d 100644
--- a/chrome/browser/sync_file_system/drive_metadata_store.h
+++ b/chrome/browser/sync_file_system/drive_metadata_store.h
@@ -73,6 +73,10 @@ class DriveMetadataStore
SyncStatusCode ReadEntry(const fileapi::FileSystemURL& url,
DriveMetadata* metadata) const;
+ // Returns true if |origin| is a batch sync origin, a incremental sync origin
+ // or a disabled origin.
+ bool IsKnownOrigin(const GURL& origin) const;
+
// Returns true if |origin| is a batch sync origin, i.e. the origin's entire
// file list hasn't been fully fetched and processed yet.
bool IsBatchSyncOrigin(const GURL& origin) const;
@@ -105,8 +109,9 @@ class DriveMetadataStore
// Sets the directory identified by |resource_id| as the sync data directory.
// All data for the Sync FileSystem should be store into the directory.
- // It is invalid to overwrite the directory.
void SetSyncRootDirectory(const std::string& resource_id);
+ void SetOriginRootDirectory(const GURL& origin,
+ const std::string& resource_id);
// Returns a set of URLs for files in conflict.
SyncStatusCode GetConflictURLs(
@@ -115,8 +120,9 @@ class DriveMetadataStore
// Returns a set of URLs and Resource IDs for files to be fetched.
SyncStatusCode GetToBeFetchedFiles(URLAndResourceIdList* list) const;
- // Returns resource id for |origin|. |origin| must be a batch sync origin or
- // an incremental sync origin.
+ // Returns resource id for |origin|.
+ // This may return an empty string if |origin| is not a batch, incremental
+ // or disabled origin.
std::string GetResourceIdForOrigin(const GURL& origin) const;
const std::string& sync_root_directory() const {
diff --git a/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc b/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc
index d9a8a9c..2d761b71 100644
--- a/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_metadata_store_unittest.cc
@@ -603,6 +603,7 @@ TEST_F(DriveMetadataStoreTest, GetResourceIdForOrigin) {
InitializeDatabase();
EXPECT_EQ(SYNC_STATUS_OK, SetLargestChangeStamp(1));
+ metadata_store()->SetSyncRootDirectory("root");
metadata_store()->AddBatchSyncOrigin(kOrigin1, kResourceId1);
metadata_store()->AddBatchSyncOrigin(kOrigin2, kResourceId2);
@@ -621,6 +622,19 @@ TEST_F(DriveMetadataStoreTest, GetResourceIdForOrigin) {
EXPECT_EQ(kResourceId2, metadata_store()->GetResourceIdForOrigin(kOrigin2));
EXPECT_EQ(kResourceId3, metadata_store()->GetResourceIdForOrigin(kOrigin3));
+ // Resetting the root directory resource ID to empty makes any
+ // GetResourceIdForOrigin return an empty resource ID too, regardless of
+ // whether they are known origin or not.
+ metadata_store()->SetSyncRootDirectory(std::string());
+ EXPECT_TRUE(metadata_store()->GetResourceIdForOrigin(kOrigin1).empty());
+ EXPECT_TRUE(metadata_store()->GetResourceIdForOrigin(kOrigin2).empty());
+ EXPECT_TRUE(metadata_store()->GetResourceIdForOrigin(kOrigin3).empty());
+
+ // Make sure they're still known origins.
+ EXPECT_TRUE(metadata_store()->IsKnownOrigin(kOrigin1));
+ EXPECT_TRUE(metadata_store()->IsKnownOrigin(kOrigin2));
+ EXPECT_TRUE(metadata_store()->IsKnownOrigin(kOrigin3));
+
VerifyReverseMap();
}