Index: chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc |
diff --git a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc |
index 003622cea4621b11b04340040a0f284008c57774..26485121764a2d966cc996faf81400e4dcf2d1f1 100644 |
--- a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc |
+++ b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.cc |
@@ -106,15 +106,6 @@ RemoteToLocalSyncer::~RemoteToLocalSyncer() { |
void RemoteToLocalSyncer::RunPreflight(scoped_ptr<SyncTaskToken> token) { |
token->InitializeTaskLog("Remote -> Local"); |
- scoped_ptr<TaskBlocker> task_blocker(new TaskBlocker); |
- task_blocker->exclusive = true; |
- SyncTaskManager::UpdateTaskBlocker( |
- token.Pass(), task_blocker.Pass(), |
- base::Bind(&RemoteToLocalSyncer::RunExclusive, |
- weak_ptr_factory_.GetWeakPtr())); |
-} |
- |
-void RemoteToLocalSyncer::RunExclusive(scoped_ptr<SyncTaskToken> token) { |
if (!drive_service() || !metadata_database() || !remote_change_processor()) { |
token->RecordLog("Context not ready."); |
SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_FAILED); |
@@ -146,7 +137,11 @@ void RemoteToLocalSyncer::ResolveRemoteChange(scoped_ptr<SyncTaskToken> token) { |
NOTREACHED(); |
} |
token->RecordLog("Missing remote metadata case."); |
- HandleMissingRemoteMetadata(token.Pass()); |
+ |
+ MoveToBackground( |
+ token.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::HandleMissingRemoteMetadata, |
+ weak_ptr_factory_.GetWeakPtr())); |
return; |
} |
@@ -183,7 +178,8 @@ void RemoteToLocalSyncer::ResolveRemoteChange(scoped_ptr<SyncTaskToken> token) { |
synced_details.title() != remote_details.title() || |
remote_details.parent_folder_ids_size()) { |
token->RecordLog("Sync-root deletion."); |
- HandleSyncRootDeletion(token.Pass()); |
+ sync_root_deletion_ = true; |
+ SyncCompleted(token.Pass(), SYNC_STATUS_OK); |
return; |
} |
token->RecordLog("Trivial sync-root change."); |
@@ -194,10 +190,20 @@ void RemoteToLocalSyncer::ResolveRemoteChange(scoped_ptr<SyncTaskToken> token) { |
DCHECK_NE(dirty_tracker_->tracker_id(), |
metadata_database()->GetSyncRootTrackerID()); |
+ if (!BuildFileSystemURL(metadata_database(), *dirty_tracker_, &url_)) { |
+ NOTREACHED(); |
+ SyncCompleted(token.Pass(), SYNC_STATUS_FAILED); |
+ return; |
+ } |
+ |
+ DCHECK(url_.is_valid()); |
+ |
if (remote_details.missing()) { |
if (!synced_details.missing()) { |
token->RecordLog("Remote file deletion."); |
- HandleDeletion(token.Pass()); |
+ MoveToBackground(token.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::HandleDeletion, |
+ weak_ptr_factory_.GetWeakPtr())); |
return; |
} |
@@ -238,9 +244,10 @@ void RemoteToLocalSyncer::ResolveRemoteChange(scoped_ptr<SyncTaskToken> token) { |
if (synced_details.title() != remote_details.title()) { |
// Handle rename as deletion + addition. |
token->RecordLog("Detected file rename."); |
- Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion, |
- weak_ptr_factory_.GetWeakPtr(), |
- base::Passed(&token))); |
+ |
+ MoveToBackground(token.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::HandleFileMove, |
+ weak_ptr_factory_.GetWeakPtr())); |
return; |
} |
DCHECK_EQ(synced_details.title(), remote_details.title()); |
@@ -258,28 +265,35 @@ void RemoteToLocalSyncer::ResolveRemoteChange(scoped_ptr<SyncTaskToken> token) { |
if (!HasFolderAsParent(remote_details, parent_tracker.file_id())) { |
// Handle reorganize as deletion + addition. |
token->RecordLog("Detected file reorganize."); |
- Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion, |
- weak_ptr_factory_.GetWeakPtr(), |
- base::Passed(&token))); |
+ |
+ MoveToBackground(token.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::HandleFileMove, |
+ weak_ptr_factory_.GetWeakPtr())); |
return; |
} |
if (synced_details.file_kind() == FILE_KIND_FILE) { |
if (synced_details.md5() != remote_details.md5()) { |
token->RecordLog("Detected file content update."); |
- HandleContentUpdate(token.Pass()); |
+ MoveToBackground(token.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::HandleContentUpdate, |
+ weak_ptr_factory_.GetWeakPtr())); |
return; |
} |
} else { |
DCHECK_EQ(FILE_KIND_FOLDER, synced_details.file_kind()); |
if (synced_details.missing()) { |
token->RecordLog("Detected folder update."); |
- HandleFolderUpdate(token.Pass()); |
+ MoveToBackground(token.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::HandleFolderUpdate, |
+ weak_ptr_factory_.GetWeakPtr())); |
return; |
} |
if (dirty_tracker_->needs_folder_listing()) { |
token->RecordLog("Needs listing folder."); |
- ListFolderContent(token.Pass()); |
+ MoveToBackground(token.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::ListFolderContent, |
+ weak_ptr_factory_.GetWeakPtr())); |
return; |
} |
SyncCompleted(token.Pass(), SYNC_STATUS_OK); |
@@ -290,6 +304,88 @@ void RemoteToLocalSyncer::ResolveRemoteChange(scoped_ptr<SyncTaskToken> token) { |
SyncCompleted(token.Pass(), SYNC_STATUS_OK); |
} |
+void RemoteToLocalSyncer::MoveToBackground(scoped_ptr<SyncTaskToken> token, |
+ const Continuation& continuation) { |
+ DCHECK(dirty_tracker_); |
+ |
+ scoped_ptr<TaskBlocker> blocker(new TaskBlocker); |
+ blocker->app_id = dirty_tracker_->app_id(); |
+ if (url_.is_valid()) |
+ blocker->paths.push_back(url_.path()); |
+ blocker->file_ids.push_back(dirty_tracker_->file_id()); |
+ blocker->tracker_ids.push_back(dirty_tracker_->tracker_id()); |
+ |
+ SyncTaskManager::UpdateTaskBlocker( |
+ token.Pass(), blocker.Pass(), |
+ base::Bind(&RemoteToLocalSyncer::ContinueAsBackgroundTask, |
+ weak_ptr_factory_.GetWeakPtr(), continuation)); |
+} |
+ |
+void RemoteToLocalSyncer::ContinueAsBackgroundTask( |
+ const Continuation& continuation, |
+ scoped_ptr<SyncTaskToken> token) { |
+ DCHECK(dirty_tracker_); |
+ |
+ // The SyncTask runs as a background task beyond this point. |
+ // Not that any task can run between MoveToBackground() and |
+ // ContinueAsBackgroundTask(), so we need to make sure other tasks didn't |
+ // affect to the current RemoteToLocalSyncer task. |
+ // |
+ // - For LocalToRemoteSyncer, it may update or delete any of FileTracker and |
+ // FileMetadata. When it updates FileMetadata or FileDetais in FileTracker, |
nhiroki
2014/09/16 08:42:27
s/FileDetais/FileDetails/
tzik
2014/09/24 06:01:49
Done.
|
+ // it also updates |change_id|. So, ensure the target FileTracker and |
+ // FileMetadata exist and their |change_id|s are not updated. |
+ // - For ListChangesTask, it may update FileMetadata together with |change_id| |
+ // and may delete FileTracker. |
+ // - For UnininstallAppTask, it may delete FileMetadata and FileTracker. |
nhiroki
2014/09/16 08:42:27
s/UnininstallAppTask/UninstallAppTask/
tzik
2014/09/24 06:01:49
Done.
|
+ // Check if FileTracker still exists. |
+ // - For other RemoteToLocalSyncer, it may delete the FileTracker of parent. |
+ // Note that since RemoteToLocalSyncer demotes the target FileTracker first, |
+ // any other RemoteToLocalSyncer does not run for current |dirty_tracker_|. |
+ // - Others, SyncEngineInitializer and RegisterAppTask doesn't affect to |
+ |
+ FileTracker latest_dirty_tracker; |
+ if (!metadata_database()->FindTrackerByTrackerID( |
+ dirty_tracker_->tracker_id(), &latest_dirty_tracker) || |
+ dirty_tracker_->active() != latest_dirty_tracker.active() || |
+ !latest_dirty_tracker.dirty()) { |
+ SyncCompleted(token.Pass(), SYNC_STATUS_RETRY); |
+ return; |
+ } |
+ |
+ int64 current_change_id = kint64min; |
+ int64 latest_change_id = kint64min; |
+ if (dirty_tracker_->has_synced_details()) |
+ current_change_id = dirty_tracker_->synced_details().change_id(); |
+ if (latest_dirty_tracker.has_synced_details()) |
+ latest_change_id = latest_dirty_tracker.synced_details().change_id(); |
+ if (current_change_id != latest_change_id) { |
+ SyncCompleted(token.Pass(), SYNC_STATUS_RETRY); |
+ return; |
+ } |
+ |
+ FileMetadata latest_file_metadata; |
+ if (metadata_database()->FindFileByFileID(dirty_tracker_->file_id(), |
+ &latest_file_metadata)) { |
+ if (!remote_metadata_) { |
+ SyncCompleted(token.Pass(), SYNC_STATUS_RETRY); |
+ return; |
+ } |
+ |
+ if (remote_metadata_->details().change_id() != |
+ latest_file_metadata.details().change_id()) { |
nhiroki
2014/09/16 08:42:27
nit: You may need a 4-space indent.
tzik
2014/09/24 06:01:49
Done.
I introduced local variable for them.
|
+ SyncCompleted(token.Pass(), SYNC_STATUS_RETRY); |
+ return; |
+ } |
+ } else { |
+ if (remote_metadata_) { |
+ SyncCompleted(token.Pass(), SYNC_STATUS_RETRY); |
+ return; |
+ } |
+ } |
+ continuation.Run(token.Pass()); |
+} |
+ |
void RemoteToLocalSyncer::HandleMissingRemoteMetadata( |
scoped_ptr<SyncTaskToken> token) { |
DCHECK(dirty_tracker_); |
@@ -444,12 +540,6 @@ void RemoteToLocalSyncer::DidPrepareForFolderUpdate( |
CreateFolder(token.Pass()); |
} |
-void RemoteToLocalSyncer::HandleSyncRootDeletion( |
- scoped_ptr<SyncTaskToken> token) { |
- sync_root_deletion_ = true; |
- SyncCompleted(token.Pass(), SYNC_STATUS_OK); |
-} |
- |
void RemoteToLocalSyncer::HandleDeletion( |
scoped_ptr<SyncTaskToken> token) { |
DCHECK(dirty_tracker_); |
@@ -467,6 +557,21 @@ void RemoteToLocalSyncer::HandleDeletion( |
base::Passed(&token))); |
} |
+void RemoteToLocalSyncer::HandleFileMove(scoped_ptr<SyncTaskToken> token) { |
+ DCHECK(dirty_tracker_); |
+ DCHECK(dirty_tracker_->active()); |
+ DCHECK(!HasDisabledAppRoot(metadata_database(), *dirty_tracker_)); |
+ DCHECK(dirty_tracker_->has_synced_details()); |
+ |
+ DCHECK(remote_metadata_); |
+ DCHECK(remote_metadata_->has_details()); |
+ DCHECK(!remote_metadata_->details().missing()); |
+ |
+ Prepare(base::Bind(&RemoteToLocalSyncer::DidPrepareForDeletion, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ base::Passed(&token))); |
+} |
+ |
void RemoteToLocalSyncer::DidPrepareForDeletion( |
scoped_ptr<SyncTaskToken> token, |
SyncStatusCode status) { |
@@ -639,9 +744,6 @@ void RemoteToLocalSyncer::FinalizeSync(scoped_ptr<SyncTaskToken> token, |
} |
void RemoteToLocalSyncer::Prepare(const SyncStatusCallback& callback) { |
- bool should_success = BuildFileSystemURL( |
- metadata_database(), *dirty_tracker_, &url_); |
- DCHECK(should_success); |
DCHECK(url_.is_valid()); |
remote_change_processor()->PrepareForProcessRemoteChange( |
url_, |