Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Unified Diff: chrome/browser/chromeos/drive/sync_client.cc

Issue 391343002: Keep sync tasks alive as long as it's not finished (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/drive/sync_client.cc
diff --git a/chrome/browser/chromeos/drive/sync_client.cc b/chrome/browser/chromeos/drive/sync_client.cc
index a7852012bc44c4fcce12a5f836e7429d18b8cb80..95a36c4f27aec143624dde5db922a0397968014c 100644
--- a/chrome/browser/chromeos/drive/sync_client.cc
+++ b/chrome/browser/chromeos/drive/sync_client.cc
@@ -121,15 +121,10 @@ void CheckExistingPinnedFiles(ResourceMetadata* metadata,
DCHECK(!it->HasError());
}
-// Runs the task and returns a dummy cancel closure.
-base::Closure RunTaskAndReturnDummyCancelClosure(const base::Closure& task) {
- task.Run();
- return base::Closure();
-}
-
} // namespace
-SyncClient::SyncTask::SyncTask() : state(PENDING), should_run_again(false) {}
+SyncClient::SyncTask::SyncTask()
+ : state(SUSPENDED), context(BACKGROUND), should_run_again(false) {}
SyncClient::SyncTask::~SyncTask() {}
SyncClient::SyncClient(base::SequencedTaskRunner* blocking_task_runner,
@@ -209,8 +204,9 @@ void SyncClient::RemoveFetchTask(const std::string& local_id) {
SyncTask* task = &it->second;
switch (task->state) {
+ case SUSPENDED:
case PENDING:
- tasks_.erase(it);
+ OnTaskComplete(FETCH, local_id, FILE_ERROR_ABORT);
break;
case RUNNING:
if (!task->cancel_closure.is_null())
@@ -225,37 +221,56 @@ void SyncClient::AddUpdateTask(const ClientContext& context,
AddUpdateTaskInternal(context, local_id, delay_);
}
-void SyncClient::AddFetchTaskInternal(const std::string& local_id,
- const base::TimeDelta& delay) {
+base::Closure SyncClient::PerformFetchTask(const std::string& local_id,
+ const ClientContext& context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- SyncTask task;
- task.task = base::Bind(
- &file_system::DownloadOperation::EnsureFileDownloadedByLocalId,
- base::Unretained(download_operation_.get()),
+ return download_operation_->EnsureFileDownloadedByLocalId(
local_id,
- ClientContext(BACKGROUND),
+ context,
GetFileContentInitializedCallback(),
google_apis::GetContentCallback(),
base::Bind(&SyncClient::OnFetchFileComplete,
weak_ptr_factory_.GetWeakPtr(),
local_id));
+}
+
+void SyncClient::AddFetchTaskInternal(const std::string& local_id,
+ const base::TimeDelta& delay) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ SyncTask task;
+ task.state = PENDING;
+ task.context = ClientContext(BACKGROUND);
+ task.task = base::Bind(&SyncClient::PerformFetchTask,
+ base::Unretained(this),
+ local_id);
AddTask(SyncTasks::key_type(FETCH, local_id), task, delay);
}
+base::Closure SyncClient::PerformUpdateTask(const std::string& local_id,
+ const ClientContext& context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ entry_update_performer_->UpdateEntry(
+ local_id,
+ context,
+ base::Bind(&SyncClient::OnTaskComplete,
+ weak_ptr_factory_.GetWeakPtr(),
+ UPDATE,
+ local_id));
+ return base::Closure();
+}
+
void SyncClient::AddUpdateTaskInternal(const ClientContext& context,
const std::string& local_id,
const base::TimeDelta& delay) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
SyncTask task;
- task.task = base::Bind(
- &RunTaskAndReturnDummyCancelClosure,
- base::Bind(&EntryUpdatePerformer::UpdateEntry,
- base::Unretained(entry_update_performer_.get()),
- local_id,
- context,
- base::Bind(&SyncClient::OnUpdateComplete,
- weak_ptr_factory_.GetWeakPtr(),
- local_id)));
+ task.state = PENDING;
+ task.context = context;
+ task.task = base::Bind(&SyncClient::PerformUpdateTask,
+ base::Unretained(this),
+ local_id);
AddTask(SyncTasks::key_type(UPDATE, local_id), task, delay);
}
@@ -267,20 +282,22 @@ void SyncClient::AddTask(const SyncTasks::key_type& key,
SyncTasks::iterator it = tasks_.find(key);
if (it != tasks_.end()) {
switch (it->second.state) {
+ case SUSPENDED:
+ // Activate the task.
+ it->second.state = PENDING;
+ break;
case PENDING:
// The same task will run, do nothing.
- break;
+ return;
case RUNNING:
// Something has changed since the task started. Schedule rerun.
it->second.should_run_again = true;
- break;
+ return;
}
- return;
+ } else {
+ tasks_[key] = task;
}
-
DCHECK_EQ(PENDING, task.state);
- tasks_[key] = task;
-
base::MessageLoopProxy::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(), key),
@@ -294,9 +311,10 @@ void SyncClient::StartTask(const SyncTasks::key_type& key) {
SyncTask* task = &it->second;
switch (task->state) {
+ case SUSPENDED:
case PENDING:
task->state = RUNNING;
- task->cancel_closure = task->task.Run();
+ task->cancel_closure = task->task.Run(task->context);
break;
case RUNNING: // Do nothing.
break;
@@ -330,22 +348,77 @@ void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) {
AddFetchTask((*local_ids)[i]);
}
-bool SyncClient::OnTaskComplete(SyncType type, const std::string& local_id) {
+void SyncClient::OnTaskComplete(SyncType type,
+ const std::string& local_id,
+ FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const SyncTasks::key_type key(type, local_id);
SyncTasks::iterator it = tasks_.find(key);
DCHECK(it != tasks_.end());
+ bool should_erase_task = true;
+ base::TimeDelta retry_delay = base::TimeDelta::FromSeconds(0);
+
+ switch (error) {
+ case FILE_ERROR_OK:
+ DVLOG(1) << "Completed: type = " << type << ", id = " << local_id;
+ break;
+ case FILE_ERROR_ABORT:
+ // Ignore it because this is caused by user's cancel operations.
+ break;
+ case FILE_ERROR_NO_CONNECTION:
+ // Run the task again so that we'll retry once the connection is back.
+ it->second.should_run_again = true;
+ it->second.context = ClientContext(BACKGROUND);
+ break;
+ case FILE_ERROR_SERVICE_UNAVAILABLE:
+ // Run the task again so that we'll retry once the service is back.
+ it->second.should_run_again = true;
+ it->second.context = ClientContext(BACKGROUND);
+ retry_delay = long_delay_;
+ operation_observer_->OnDriveSyncError(
+ file_system::DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE, local_id);
+ break;
+ case FILE_ERROR_PARENT_NEEDS_TO_BE_SYNCED: {
+ // Suspend the task and register it as a dependent task of the parent.
+ should_erase_task = false;
+ it->second.state = SUSPENDED;
+ ResourceEntry* entry = new ResourceEntry;
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&ResourceMetadata::GetResourceEntryById,
+ base::Unretained(metadata_),
+ local_id,
+ entry),
+ base::Bind(&SyncClient::AddDependentTask,
+ weak_ptr_factory_.GetWeakPtr(),
+ type,
+ local_id,
+ base::Owned(entry)));
+ break;
+ }
+ default:
+ operation_observer_->OnDriveSyncError(
+ file_system::DRIVE_SYNC_ERROR_MISC, local_id);
+ LOG(WARNING) << "Failed: type = " << type << ", id = " << local_id
+ << ": " << FileErrorToString(error);
+ }
+
if (it->second.should_run_again) {
DVLOG(1) << "Running again: type = " << type << ", id = " << local_id;
+ it->second.state = PENDING;
it->second.should_run_again = false;
- it->second.task.Run();
- return false;
+ base::MessageLoopProxy::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(), key),
+ retry_delay);
+ } else if (should_erase_task) {
+ for (size_t i = 0; i < it->second.dependent_tasks.size(); ++i)
+ StartTask(it->second.dependent_tasks[i]);
+ tasks_.erase(it);
}
-
- tasks_.erase(it);
- return true;
}
void SyncClient::OnFetchFileComplete(const std::string& local_id,
@@ -353,103 +426,37 @@ void SyncClient::OnFetchFileComplete(const std::string& local_id,
const base::FilePath& local_path,
scoped_ptr<ResourceEntry> entry) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!OnTaskComplete(FETCH, local_id))
- return;
-
- if (error == FILE_ERROR_OK) {
- DVLOG(1) << "Fetched " << local_id << ": " << local_path.value();
- } else {
- switch (error) {
- case FILE_ERROR_ABORT:
- // If user cancels download, unpin the file so that we do not sync the
- // file again.
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_,
- FROM_HERE,
- base::Bind(&FileCache::Unpin, base::Unretained(cache_), local_id),
- base::Bind(&util::EmptyFileOperationCallback));
- break;
- case FILE_ERROR_NO_CONNECTION:
- // Add the task again so that we'll retry once the connection is back.
- AddFetchTaskInternal(local_id, delay_);
- break;
- case FILE_ERROR_SERVICE_UNAVAILABLE:
- // Add the task again so that we'll retry once the service is back.
- AddFetchTaskInternal(local_id, long_delay_);
- operation_observer_->OnDriveSyncError(
- file_system::DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE,
- local_id);
- break;
- default:
- operation_observer_->OnDriveSyncError(
- file_system::DRIVE_SYNC_ERROR_MISC,
- local_id);
- LOG(WARNING) << "Failed to fetch " << local_id
- << ": " << FileErrorToString(error);
- }
+ OnTaskComplete(FETCH, local_id, error);
+ if (error == FILE_ERROR_ABORT) {
+ // If user cancels download, unpin the file so that we do not sync the file
+ // again.
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&FileCache::Unpin, base::Unretained(cache_), local_id),
+ base::Bind(&util::EmptyFileOperationCallback));
}
}
-void SyncClient::OnUpdateComplete(const std::string& local_id,
+void SyncClient::AddDependentTask(SyncType type,
+ const std::string& local_id,
+ const ResourceEntry* entry,
FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!OnTaskComplete(UPDATE, local_id))
+ if (error != FILE_ERROR_OK) {
+ OnTaskComplete(type, local_id, error);
return;
-
- if (error == FILE_ERROR_OK) {
- DVLOG(1) << "Updated " << local_id;
-
- // Add update tasks for child entries which may be waiting for the parent to
- // be updated.
- ResourceEntryVector* entries = new ResourceEntryVector;
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_.get(),
- FROM_HERE,
- base::Bind(&ResourceMetadata::ReadDirectoryById,
- base::Unretained(metadata_), local_id, entries),
- base::Bind(&SyncClient::AddChildUpdateTasks,
- weak_ptr_factory_.GetWeakPtr(), base::Owned(entries)));
- } else {
- switch (error) {
- case FILE_ERROR_ABORT:
- // Ignore it because this is caused by user's cancel operations.
- break;
- case FILE_ERROR_NO_CONNECTION:
- // Add the task again so that we'll retry once the connection is back.
- AddUpdateTaskInternal(ClientContext(BACKGROUND), local_id,
- base::TimeDelta::FromSeconds(0));
- break;
- case FILE_ERROR_SERVICE_UNAVAILABLE:
- // Add the task again so that we'll retry once the service is back.
- AddUpdateTaskInternal(ClientContext(BACKGROUND), local_id, long_delay_);
- operation_observer_->OnDriveSyncError(
- file_system::DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE,
- local_id);
- break;
- default:
- operation_observer_->OnDriveSyncError(
- file_system::DRIVE_SYNC_ERROR_MISC,
- local_id);
- LOG(WARNING) << "Failed to update " << local_id << ": "
- << FileErrorToString(error);
- }
}
-}
-void SyncClient::AddChildUpdateTasks(const ResourceEntryVector* entries,
- FileError error) {
- if (error != FILE_ERROR_OK)
+ const SyncTasks::key_type key_parent(type, entry->parent_local_id());
+ SyncTasks::iterator it_parent = tasks_.find(key_parent);
+ if (it_parent == tasks_.end()) {
kinaba 2014/07/17 06:07:46 Can't there be a danger that the parent task has c
hashimoto 2014/07/18 06:12:16 Extremely good catch. Changed EntryUpdatePerformer
+ OnTaskComplete(type, local_id, FILE_ERROR_NOT_FOUND);
return;
-
- for (size_t i = 0; i < entries->size(); ++i) {
- const ResourceEntry& entry = (*entries)[i];
- if (entry.metadata_edit_state() != ResourceEntry::CLEAN) {
- AddUpdateTaskInternal(ClientContext(BACKGROUND), entry.local_id(),
- base::TimeDelta::FromSeconds(0));
- }
}
+
+ it_parent->second.dependent_tasks.push_back(
+ SyncTasks::key_type(type, local_id));
}
} // namespace internal

Powered by Google App Engine
This is Rietveld 408576698