| 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
|
| deleted file mode 100644
|
| index e5ca372a89e91deb6f8f67adeb39be955a02caa6..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/chromeos/drive/sync_client.cc
|
| +++ /dev/null
|
| @@ -1,491 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/chromeos/drive/sync_client.h"
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/thread_task_runner_handle.h"
|
| -#include "chrome/browser/chromeos/drive/sync/entry_update_performer.h"
|
| -#include "components/drive/drive.pb.h"
|
| -#include "components/drive/file_cache.h"
|
| -#include "components/drive/file_system/download_operation.h"
|
| -#include "components/drive/file_system/operation_delegate.h"
|
| -#include "components/drive/file_system_core_util.h"
|
| -#include "components/drive/job_scheduler.h"
|
| -#include "google_apis/drive/task_util.h"
|
| -
|
| -namespace drive {
|
| -namespace internal {
|
| -
|
| -namespace {
|
| -
|
| -// The delay constant is used to delay processing a sync task. We should not
|
| -// process SyncTasks immediately for the following reasons:
|
| -//
|
| -// 1) For fetching, the user may accidentally click on "Make available
|
| -// offline" checkbox on a file, and immediately cancel it in a second.
|
| -// It's a waste to fetch the file in this case.
|
| -//
|
| -// 2) For uploading, file writing via HTML5 file system API is performed in
|
| -// two steps: 1) truncate a file to 0 bytes, 2) write contents. We
|
| -// shouldn't start uploading right after the step 1). Besides, the user
|
| -// may edit the same file repeatedly in a short period of time.
|
| -//
|
| -// TODO(satorux): We should find a way to handle the upload case more nicely,
|
| -// and shorten the delay. crbug.com/134774
|
| -const int kDelaySeconds = 1;
|
| -
|
| -// The delay constant is used to delay retrying a sync task on server errors.
|
| -const int kLongDelaySeconds = 600;
|
| -
|
| -// Iterates entries and appends IDs to |to_fetch| if the file is pinned but not
|
| -// fetched (not present locally), to |to_update| if the file needs update.
|
| -void CollectBacklog(ResourceMetadata* metadata,
|
| - std::vector<std::string>* to_fetch,
|
| - std::vector<std::string>* to_update) {
|
| - DCHECK(to_fetch);
|
| - DCHECK(to_update);
|
| -
|
| - scoped_ptr<ResourceMetadata::Iterator> it = metadata->GetIterator();
|
| - for (; !it->IsAtEnd(); it->Advance()) {
|
| - const std::string& local_id = it->GetID();
|
| - const ResourceEntry& entry = it->GetValue();
|
| - if (entry.parent_local_id() == util::kDriveTrashDirLocalId) {
|
| - to_update->push_back(local_id);
|
| - continue;
|
| - }
|
| -
|
| - bool should_update = false;
|
| - switch (entry.metadata_edit_state()) {
|
| - case ResourceEntry::CLEAN:
|
| - break;
|
| - case ResourceEntry::SYNCING:
|
| - case ResourceEntry::DIRTY:
|
| - should_update = true;
|
| - break;
|
| - }
|
| -
|
| - if (entry.file_specific_info().cache_state().is_pinned() &&
|
| - !entry.file_specific_info().cache_state().is_present())
|
| - to_fetch->push_back(local_id);
|
| -
|
| - if (entry.file_specific_info().cache_state().is_dirty())
|
| - should_update = true;
|
| -
|
| - if (should_update)
|
| - to_update->push_back(local_id);
|
| - }
|
| - DCHECK(!it->HasError());
|
| -}
|
| -
|
| -// Iterates cache entries and collects IDs of ones with obsolete cache files.
|
| -void CheckExistingPinnedFiles(ResourceMetadata* metadata,
|
| - FileCache* cache,
|
| - std::vector<std::string>* local_ids) {
|
| - scoped_ptr<ResourceMetadata::Iterator> it = metadata->GetIterator();
|
| - for (; !it->IsAtEnd(); it->Advance()) {
|
| - const ResourceEntry& entry = it->GetValue();
|
| - const FileCacheEntry& cache_state =
|
| - entry.file_specific_info().cache_state();
|
| - const std::string& local_id = it->GetID();
|
| - if (!cache_state.is_pinned() || !cache_state.is_present())
|
| - continue;
|
| -
|
| - // If MD5s don't match, it indicates the local cache file is stale, unless
|
| - // the file is dirty (the MD5 is "local"). We should never re-fetch the
|
| - // file when we have a locally modified version.
|
| - if (entry.file_specific_info().md5() == cache_state.md5() ||
|
| - cache_state.is_dirty())
|
| - continue;
|
| -
|
| - FileError error = cache->Remove(local_id);
|
| - if (error != FILE_ERROR_OK) {
|
| - LOG(WARNING) << "Failed to remove cache entry: " << local_id;
|
| - continue;
|
| - }
|
| -
|
| - error = cache->Pin(local_id);
|
| - if (error != FILE_ERROR_OK) {
|
| - LOG(WARNING) << "Failed to pin cache entry: " << local_id;
|
| - continue;
|
| - }
|
| -
|
| - local_ids->push_back(local_id);
|
| - }
|
| - DCHECK(!it->HasError());
|
| -}
|
| -
|
| -// Gets the parent entry of the entry specified by the ID.
|
| -FileError GetParentResourceEntry(ResourceMetadata* metadata,
|
| - const std::string& local_id,
|
| - ResourceEntry* parent) {
|
| - ResourceEntry entry;
|
| - FileError error = metadata->GetResourceEntryById(local_id, &entry);
|
| - if (error != FILE_ERROR_OK)
|
| - return error;
|
| - return metadata->GetResourceEntryById(entry.parent_local_id(), parent);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -SyncClient::SyncTask::SyncTask()
|
| - : state(SUSPENDED), context(BACKGROUND), should_run_again(false) {}
|
| -SyncClient::SyncTask::~SyncTask() {}
|
| -
|
| -SyncClient::SyncClient(base::SequencedTaskRunner* blocking_task_runner,
|
| - file_system::OperationDelegate* delegate,
|
| - JobScheduler* scheduler,
|
| - ResourceMetadata* metadata,
|
| - FileCache* cache,
|
| - LoaderController* loader_controller,
|
| - const base::FilePath& temporary_file_directory)
|
| - : blocking_task_runner_(blocking_task_runner),
|
| - operation_delegate_(delegate),
|
| - metadata_(metadata),
|
| - cache_(cache),
|
| - download_operation_(new file_system::DownloadOperation(
|
| - blocking_task_runner,
|
| - delegate,
|
| - scheduler,
|
| - metadata,
|
| - cache,
|
| - temporary_file_directory)),
|
| - entry_update_performer_(new EntryUpdatePerformer(blocking_task_runner,
|
| - delegate,
|
| - scheduler,
|
| - metadata,
|
| - cache,
|
| - loader_controller)),
|
| - delay_(base::TimeDelta::FromSeconds(kDelaySeconds)),
|
| - long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)),
|
| - weak_ptr_factory_(this) {
|
| -}
|
| -
|
| -SyncClient::~SyncClient() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -}
|
| -
|
| -void SyncClient::StartProcessingBacklog() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - std::vector<std::string>* to_fetch = new std::vector<std::string>;
|
| - std::vector<std::string>* to_update = new std::vector<std::string>;
|
| - blocking_task_runner_->PostTaskAndReply(
|
| - FROM_HERE,
|
| - base::Bind(&CollectBacklog, metadata_, to_fetch, to_update),
|
| - base::Bind(&SyncClient::OnGetLocalIdsOfBacklog,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - base::Owned(to_fetch),
|
| - base::Owned(to_update)));
|
| -}
|
| -
|
| -void SyncClient::StartCheckingExistingPinnedFiles() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - std::vector<std::string>* local_ids = new std::vector<std::string>;
|
| - blocking_task_runner_->PostTaskAndReply(
|
| - FROM_HERE,
|
| - base::Bind(&CheckExistingPinnedFiles,
|
| - metadata_,
|
| - cache_,
|
| - local_ids),
|
| - base::Bind(&SyncClient::AddFetchTasks,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - base::Owned(local_ids)));
|
| -}
|
| -
|
| -void SyncClient::AddFetchTask(const std::string& local_id) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - AddFetchTaskInternal(local_id, delay_);
|
| -}
|
| -
|
| -void SyncClient::RemoveFetchTask(const std::string& local_id) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(FETCH, local_id));
|
| - if (it == tasks_.end())
|
| - return;
|
| -
|
| - SyncTask* task = &it->second;
|
| - switch (task->state) {
|
| - case SUSPENDED:
|
| - case PENDING:
|
| - OnTaskComplete(FETCH, local_id, FILE_ERROR_ABORT);
|
| - break;
|
| - case RUNNING:
|
| - if (!task->cancel_closure.is_null())
|
| - task->cancel_closure.Run();
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void SyncClient::AddUpdateTask(const ClientContext& context,
|
| - const std::string& local_id) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - AddUpdateTaskInternal(context, local_id, delay_);
|
| -}
|
| -
|
| -bool SyncClient:: WaitForUpdateTaskToComplete(
|
| - const std::string& local_id,
|
| - const FileOperationCallback& callback) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(UPDATE, local_id));
|
| - if (it == tasks_.end())
|
| - return false;
|
| -
|
| - SyncTask* task = &it->second;
|
| - task->waiting_callbacks.push_back(callback);
|
| - return true;
|
| -}
|
| -
|
| -base::Closure SyncClient::PerformFetchTask(const std::string& local_id,
|
| - const ClientContext& context) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - return download_operation_->EnsureFileDownloadedByLocalId(
|
| - local_id,
|
| - 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(thread_checker_.CalledOnValidThread());
|
| -
|
| - 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(thread_checker_.CalledOnValidThread());
|
| - 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(thread_checker_.CalledOnValidThread());
|
| -
|
| - SyncTask task;
|
| - 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);
|
| -}
|
| -
|
| -void SyncClient::AddTask(const SyncTasks::key_type& key,
|
| - const SyncTask& task,
|
| - const base::TimeDelta& delay) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - 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.
|
| - return;
|
| - case RUNNING:
|
| - // Something has changed since the task started. Schedule rerun.
|
| - it->second.should_run_again = true;
|
| - return;
|
| - }
|
| - } else {
|
| - tasks_[key] = task;
|
| - }
|
| - DCHECK_EQ(PENDING, task.state);
|
| - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(), key),
|
| - delay);
|
| -}
|
| -
|
| -void SyncClient::StartTask(const SyncTasks::key_type& key) {
|
| - ResourceEntry* parent = new ResourceEntry;
|
| - base::PostTaskAndReplyWithResult(
|
| - blocking_task_runner_.get(),
|
| - FROM_HERE,
|
| - base::Bind(&GetParentResourceEntry, metadata_, key.second, parent),
|
| - base::Bind(&SyncClient::StartTaskAfterGetParentResourceEntry,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - key,
|
| - base::Owned(parent)));
|
| -}
|
| -
|
| -void SyncClient::StartTaskAfterGetParentResourceEntry(
|
| - const SyncTasks::key_type& key,
|
| - const ResourceEntry* parent,
|
| - FileError error) {
|
| - const SyncType type = key.first;
|
| - const std::string& local_id = key.second;
|
| - SyncTasks::iterator it = tasks_.find(key);
|
| - if (it == tasks_.end())
|
| - return;
|
| -
|
| - SyncTask* task = &it->second;
|
| - switch (task->state) {
|
| - case SUSPENDED:
|
| - case PENDING:
|
| - break;
|
| - case RUNNING: // Do nothing.
|
| - return;
|
| - }
|
| -
|
| - if (error != FILE_ERROR_OK) {
|
| - OnTaskComplete(type, local_id, error);
|
| - return;
|
| - }
|
| -
|
| - if (type == UPDATE &&
|
| - parent->resource_id().empty() &&
|
| - parent->local_id() != util::kDriveTrashDirLocalId) {
|
| - // Parent entry needs to be synced to get a resource ID.
|
| - // Suspend the task and register it as a dependent task of the parent.
|
| - const SyncTasks::key_type key_parent(type, parent->local_id());
|
| - SyncTasks::iterator it_parent = tasks_.find(key_parent);
|
| - if (it_parent == tasks_.end()) {
|
| - OnTaskComplete(type, local_id, FILE_ERROR_INVALID_OPERATION);
|
| - LOG(WARNING) << "Parent task not found: type = " << type << ", id = "
|
| - << local_id << ", parent_id = " << parent->local_id();
|
| - return;
|
| - }
|
| - task->state = SUSPENDED;
|
| - it_parent->second.dependent_tasks.push_back(key);
|
| - return;
|
| - }
|
| -
|
| - // Run the task.
|
| - task->state = RUNNING;
|
| - task->cancel_closure = task->task.Run(task->context);
|
| -}
|
| -
|
| -void SyncClient::OnGetLocalIdsOfBacklog(
|
| - const std::vector<std::string>* to_fetch,
|
| - const std::vector<std::string>* to_update) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // Give priority to upload tasks over fetch tasks, so that dirty files are
|
| - // uploaded as soon as possible.
|
| - for (size_t i = 0; i < to_update->size(); ++i) {
|
| - const std::string& local_id = (*to_update)[i];
|
| - DVLOG(1) << "Queuing to update: " << local_id;
|
| - AddUpdateTask(ClientContext(BACKGROUND), local_id);
|
| - }
|
| -
|
| - for (size_t i = 0; i < to_fetch->size(); ++i) {
|
| - const std::string& local_id = (*to_fetch)[i];
|
| - DVLOG(1) << "Queuing to fetch: " << local_id;
|
| - AddFetchTaskInternal(local_id, delay_);
|
| - }
|
| -}
|
| -
|
| -void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - for (size_t i = 0; i < local_ids->size(); ++i)
|
| - AddFetchTask((*local_ids)[i]);
|
| -}
|
| -
|
| -void SyncClient::OnTaskComplete(SyncType type,
|
| - const std::string& local_id,
|
| - FileError error) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - const SyncTasks::key_type key(type, local_id);
|
| - SyncTasks::iterator it = tasks_.find(key);
|
| - DCHECK(it != tasks_.end());
|
| -
|
| - 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_delegate_->OnDriveSyncError(
|
| - file_system::DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE, local_id);
|
| - break;
|
| - default:
|
| - operation_delegate_->OnDriveSyncError(
|
| - file_system::DRIVE_SYNC_ERROR_MISC, local_id);
|
| - LOG(WARNING) << "Failed: type = " << type << ", id = " << local_id
|
| - << ": " << FileErrorToString(error);
|
| - }
|
| -
|
| - for (size_t i = 0; i < it->second.waiting_callbacks.size(); ++i) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(it->second.waiting_callbacks[i], error));
|
| - }
|
| - it->second.waiting_callbacks.clear();
|
| -
|
| - 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;
|
| - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(), key),
|
| - retry_delay);
|
| - } else {
|
| - for (size_t i = 0; i < it->second.dependent_tasks.size(); ++i)
|
| - StartTask(it->second.dependent_tasks[i]);
|
| - tasks_.erase(it);
|
| - }
|
| -}
|
| -
|
| -void SyncClient::OnFetchFileComplete(const std::string& local_id,
|
| - FileError error,
|
| - const base::FilePath& local_path,
|
| - scoped_ptr<ResourceEntry> entry) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - 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_.get(),
|
| - FROM_HERE,
|
| - base::Bind(&FileCache::Unpin, base::Unretained(cache_), local_id),
|
| - base::Bind(&util::EmptyFileOperationCallback));
|
| - }
|
| -}
|
| -
|
| -} // namespace internal
|
| -} // namespace drive
|
|
|