Chromium Code Reviews| 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 |