Chromium Code Reviews| Index: chrome/browser/sync_file_system/drive_file_sync_service.cc |
| 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 fa49969163c897d8a49f7d2b343360284b340161..e1efa606df3dc9f86453540d668b8bec9c6d4129 100644 |
| --- a/chrome/browser/sync_file_system/drive_file_sync_service.cc |
| +++ b/chrome/browser/sync_file_system/drive_file_sync_service.cc |
| @@ -21,8 +21,9 @@ |
| #include "chrome/browser/sync_file_system/drive_metadata_store.h" |
| #include "chrome/browser/sync_file_system/remote_change_processor.h" |
| #include "chrome/browser/sync_file_system/sync_file_system.pb.h" |
| +#include "chrome/common/extensions/extension.h" |
| #include "content/public/browser/browser_thread.h" |
| -#include "net/base/escape.h" |
| +#include "extensions/common/constants.h" |
| #include "webkit/fileapi/file_system_url.h" |
| #include "webkit/fileapi/syncable/sync_file_metadata.h" |
| #include "webkit/fileapi/syncable/sync_file_type.h" |
| @@ -35,6 +36,9 @@ namespace { |
| const FilePath::CharType kTempDirName[] = FILE_PATH_LITERAL("tmp"); |
| const FilePath::CharType kSyncFileSystemDir[] = |
| FILE_PATH_LITERAL("Sync FileSystem"); |
| +const int64 kMinimumPollingDelaySeconds = 10; |
| +const int64 kMaximumPollingDelaySeconds = 60 * 60; // 1 hour |
| +const double kDelayMultiplier = 2; |
| bool CreateTemporaryFile(const FilePath& dir_path, FilePath* temp_file) { |
| return file_util::CreateDirectory(dir_path) && |
| @@ -99,11 +103,11 @@ class DriveFileSyncService::TaskToken { |
| // it must return the token to DriveFileSyncService. |
| // Destroying a token with valid |sync_service_| indicates the token was |
| // dropped by a task without returning. |
| - DCHECK(!sync_service_); |
| if (sync_service_) { |
| LOG(ERROR) << "Unexpected TaskToken deletion from: " |
| << location_.ToString() << " while: " << description_; |
| } |
| + DCHECK(!sync_service_); |
| } |
| private: |
| @@ -202,7 +206,9 @@ bool DriveFileSyncService::RemoteChangeComparator::operator()( |
| DriveFileSyncService::DriveFileSyncService(Profile* profile) |
| : last_operation_status_(fileapi::SYNC_STATUS_OK), |
| state_(REMOTE_SERVICE_OK), |
| - largest_changestamp_(0), |
| + largest_fetched_changestamp_(0), |
| + polling_delay_(base::TimeDelta::FromSeconds(kMinimumPollingDelaySeconds)), |
| + polling_enabled_(true), |
| weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| temporary_file_dir_ = |
| profile->GetPath().Append(kSyncFileSystemDir).Append(kTempDirName); |
| @@ -248,6 +254,7 @@ void DriveFileSyncService::RemoveObserver(Observer* observer) { |
| void DriveFileSyncService::RegisterOriginForTrackingChanges( |
| const GURL& origin, |
| const fileapi::SyncStatusCallback& callback) { |
| + DCHECK(origin.SchemeIs(extensions::kExtensionScheme)); |
| scoped_ptr<TaskToken> token(GetToken( |
| FROM_HERE, TASK_TYPE_DRIVE, "Retrieving origin metadata")); |
| if (!token) { |
| @@ -423,7 +430,7 @@ void DriveFileSyncService::ApplyLocalChange( |
| sync_client_->UploadNewFile( |
| metadata_store_->GetResourceIdForOrigin(url.origin()), |
| local_file_path, |
| - net::EscapePath(url.path().AsUTF8Unsafe()), |
| + url.path().AsUTF8Unsafe(), |
| local_file_metadata.size, |
| base::Bind(&DriveFileSyncService::DidUploadNewFile, |
| AsWeakPtr(), base::Passed(&token), url, callback)); |
| @@ -503,7 +510,8 @@ DriveFileSyncService::DriveFileSyncService( |
| scoped_ptr<DriveMetadataStore> metadata_store) |
| : last_operation_status_(fileapi::SYNC_STATUS_OK), |
| state_(REMOTE_SERVICE_OK), |
| - largest_changestamp_(0), |
| + largest_fetched_changestamp_(0), |
| + polling_enabled_(false), |
| weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| temporary_file_dir_ = base_dir.Append(kTempDirName); |
| @@ -532,7 +540,6 @@ void DriveFileSyncService::NotifyTaskDone(fileapi::SyncStatusCode status, |
| last_operation_status_ = status; |
| token_ = token.Pass(); |
| - RemoteServiceState old_state = state_; |
| if (token_->task_type() != TASK_TYPE_NONE) { |
| DVLOG(1) << "NotifyTaskDone: " << token_->description() |
| << ": finished with status=" << status |
| @@ -557,8 +564,14 @@ void DriveFileSyncService::NotifyTaskDone(fileapi::SyncStatusCode status, |
| return; |
| } |
| - if (state_ != REMOTE_SERVICE_OK || old_state == state_) |
| + if (state_ != REMOTE_SERVICE_OK) { |
| + if (state_ == REMOTE_SERVICE_TEMPORARY_UNAVAILABLE) { |
|
kinuko
2012/12/04 05:18:30
Should we also check the same conditions as line 5
tzik
2012/12/04 06:32:32
Done.
|
| + polling_delay_ = |
| + base::TimeDelta::FromSeconds(kMaximumPollingDelaySeconds); |
| + SchedulePolling(); |
| + } |
| return; |
| + } |
| // If the state has become OK and we have any pending batch sync origins |
| // restart batch sync for them. |
| @@ -567,7 +580,17 @@ void DriveFileSyncService::NotifyTaskDone(fileapi::SyncStatusCode status, |
| pending_batch_sync_origins_.erase(pending_batch_sync_origins_.begin()); |
| std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin); |
| StartBatchSyncForOrigin(origin, resource_id); |
| + return; |
| } |
| + |
| + // Notify observer of the right timing to run ProcessRemoteChange. |
| + FOR_EACH_OBSERVER(Observer, observers_, |
| + OnRemoteChangeAvailable(pending_changes_.size())); |
| + |
| + if (!metadata_store_->incremental_sync_origins().empty() && |
| + pending_changes_.empty() && |
| + polling_enabled_) |
| + SchedulePolling(); |
| } |
| void DriveFileSyncService::UpdateServiceState() { |
| @@ -629,6 +652,8 @@ void DriveFileSyncService::DidInitializeMetadataStore( |
| return; |
| } |
| + largest_fetched_changestamp_ = metadata_store_->GetLargestChangeStamp(); |
| + |
| if (metadata_store_->sync_root_directory().empty()) { |
| GetSyncRootDirectory(token.Pass(), base::Bind(&EmptyStatusCallback)); |
| return; |
| @@ -739,6 +764,13 @@ void DriveFileSyncService::DidGetLargestChangeStampForBatchSync( |
| return; |
| } |
| + if (metadata_store_->incremental_sync_origins().empty()) { |
| + largest_fetched_changestamp_ = largest_changestamp; |
| + metadata_store_->SetLargestChangeStamp( |
| + largest_changestamp, |
| + base::Bind(&EmptyStatusCallback)); |
| + } |
| + |
| DCHECK(token); |
| token->UpdateTask(FROM_HERE, TASK_TYPE_DRIVE, "Retrieving remote files"); |
| sync_client_->ListFiles( |
| @@ -764,7 +796,7 @@ void DriveFileSyncService::DidGetDirectoryContentForBatchSync( |
| typedef ScopedVector<google_apis::DocumentEntry>::const_iterator iterator; |
| for (iterator itr = feed->entries().begin(); |
| itr != feed->entries().end(); ++itr) { |
| - AppendNewRemoteChange(origin, *itr, largest_changestamp, |
| + AppendNewRemoteChange(origin, **itr, largest_changestamp, |
| REMOTE_SYNC_TYPE_BATCH); |
| } |
| @@ -869,7 +901,7 @@ void DriveFileSyncService::DidApplyLocalChange( |
| const fileapi::SyncStatusCallback& callback, |
| fileapi::SyncStatusCode status) { |
| if (status == fileapi::SYNC_STATUS_OK) { |
| - CancelRemoteChange(url); |
| + RemoveRemoteChange(url); |
| NotifyTaskDone(GDataErrorCodeToSyncStatusCodeWrapper(error), token.Pass()); |
| callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error)); |
| return; |
| @@ -1004,6 +1036,7 @@ void DriveFileSyncService::DidPrepareForProcessRemoteChange( |
| bool missing_db_entry = (status != fileapi::SYNC_STATUS_OK); |
| if (missing_db_entry) { |
| param->drive_metadata.set_resource_id(param->remote_change.resource_id); |
| + param->drive_metadata.set_md5_checksum(std::string()); |
| param->drive_metadata.set_conflicted(false); |
| } |
| bool missing_local_file = |
| @@ -1083,8 +1116,10 @@ void DriveFileSyncService::DidPrepareForProcessRemoteChange( |
| } |
| DCHECK(!missing_local_file); |
| param->operation_type = fileapi::SYNC_OPERATION_DELETE; |
| + |
| + const fileapi::FileChange& file_change = param->remote_change.change; |
| param->processor->ApplyRemoteChange( |
| - param->remote_change.change, FilePath(), url, |
| + file_change, FilePath(), url, |
| base::Bind(&DriveFileSyncService::DidApplyRemoteChange, AsWeakPtr(), |
| base::Passed(¶m))); |
| return; |
| @@ -1123,13 +1158,11 @@ void DriveFileSyncService::DidGetTemporaryFileForDownload( |
| return; |
| } |
| - DriveMetadata metadata; |
| - metadata_store_->ReadEntry(param->remote_change.url, &metadata); |
| - |
| const FilePath& temporary_file_path = param->temporary_file_path; |
| std::string resource_id = param->remote_change.resource_id; |
| + const DriveMetadata& drive_metadata = param->drive_metadata; |
| sync_client_->DownloadFile( |
| - resource_id, metadata.md5_checksum(), |
| + resource_id, drive_metadata.md5_checksum(), |
| temporary_file_path, |
| base::Bind(&DriveFileSyncService::DidDownloadFile, |
| AsWeakPtr(), base::Passed(¶m))); |
| @@ -1151,7 +1184,7 @@ void DriveFileSyncService::DidDownloadFile( |
| return; |
| } |
| - param->md5_checksum = md5_checksum; |
| + param->drive_metadata.set_md5_checksum(md5_checksum); |
| const fileapi::FileChange& change = param->remote_change.change; |
| const FilePath& temporary_file_path = param->temporary_file_path; |
| const fileapi::FileSystemURL& url = param->remote_change.url; |
| @@ -1175,13 +1208,12 @@ void DriveFileSyncService::DidApplyRemoteChange( |
| return; |
| } |
| - DriveMetadata metadata; |
| - metadata.set_resource_id(param->remote_change.resource_id); |
| - metadata.set_md5_checksum(param->md5_checksum); |
| - metadata.set_conflicted(false); |
| + const DriveMetadata& drive_metadata = param->drive_metadata; |
| + param->drive_metadata.set_resource_id(param->remote_change.resource_id); |
| + param->drive_metadata.set_conflicted(false); |
| metadata_store_->UpdateEntry( |
| - url, metadata, |
| + url, drive_metadata, |
| base::Bind(&DriveFileSyncService::CompleteRemoteSync, |
| AsWeakPtr(), base::Passed(¶m))); |
| } |
| @@ -1203,7 +1235,7 @@ void DriveFileSyncService::CompleteRemoteSync( |
| return; |
| } |
| - CancelRemoteChange(param->remote_change.url); |
| + RemoveRemoteChange(param->remote_change.url); |
| GURL origin = param->remote_change.url.origin(); |
| if (metadata_store_->IsIncrementalSyncOrigin(origin)) { |
| @@ -1244,11 +1276,11 @@ void DriveFileSyncService::FinalizeRemoteSync( |
| void DriveFileSyncService::AppendNewRemoteChange( |
| const GURL& origin, |
| - google_apis::DocumentEntry* entry, |
| + const google_apis::DocumentEntry& entry, |
| int64 changestamp, |
| RemoteSyncType sync_type) { |
| // TODO(tzik): Normalize the path here. |
| - FilePath path = FilePath::FromUTF8Unsafe(UTF16ToUTF8(entry->title())); |
| + FilePath path = FilePath::FromUTF8Unsafe(UTF16ToUTF8(entry.title())); |
| PathToChange* path_to_change = &url_to_change_[origin]; |
| PathToChange::iterator found = path_to_change->find(path); |
| @@ -1263,12 +1295,12 @@ void DriveFileSyncService::AppendNewRemoteChange( |
| fileapi::FileChange::ChangeType change_type; |
| fileapi::SyncFileType file_type; |
| - if (entry->deleted()) { |
| + if (entry.deleted()) { |
| change_type = fileapi::FileChange::FILE_CHANGE_DELETE; |
| file_type = fileapi::SYNC_FILE_TYPE_UNKNOWN; |
| } else { |
| change_type = fileapi::FileChange::FILE_CHANGE_ADD_OR_UPDATE; |
| - if (entry->kind() == google_apis::ENTRY_KIND_FOLDER) |
| + if (entry.is_folder()) |
| file_type = fileapi::SYNC_FILE_TYPE_DIRECTORY; |
| else |
| file_type = fileapi::SYNC_FILE_TYPE_FILE; |
| @@ -1281,11 +1313,11 @@ void DriveFileSyncService::AppendNewRemoteChange( |
| DCHECK(inserted_to_queue.second); |
| (*path_to_change)[path] = RemoteChange( |
| - changestamp, entry->resource_id(), url, file_change, |
| + changestamp, entry.resource_id(), url, file_change, |
| inserted_to_queue.first); |
| } |
| -void DriveFileSyncService::CancelRemoteChange( |
| +void DriveFileSyncService::RemoveRemoteChange( |
| const fileapi::FileSystemURL& url) { |
| URLToChange::iterator found_origin = url_to_change_.find(url.origin()); |
| if (found_origin == url_to_change_.end()) |
| @@ -1301,14 +1333,10 @@ void DriveFileSyncService::CancelRemoteChange( |
| if (path_to_change->empty()) |
| url_to_change_.erase(found_origin); |
| - MaybeMarkAsIncrementalSyncOrigin(url.origin()); |
| -} |
| - |
| -void DriveFileSyncService::MaybeMarkAsIncrementalSyncOrigin( |
| - const GURL& origin) { |
| - if (metadata_store_->IsBatchSyncOrigin(origin) && |
| - !ContainsKey(url_to_change_, origin)) |
| - metadata_store_->MoveBatchSyncOriginToIncremental(origin); |
| + if (metadata_store_->IsBatchSyncOrigin(url.origin()) && |
| + !ContainsKey(url_to_change_, url.origin())) { |
| + metadata_store_->MoveBatchSyncOriginToIncremental(url.origin()); |
| + } |
| } |
| bool DriveFileSyncService::GetPendingChangeForFileSystemURL( |
| @@ -1326,6 +1354,116 @@ bool DriveFileSyncService::GetPendingChangeForFileSystemURL( |
| return true; |
| } |
| +void DriveFileSyncService::FetchChangesForIncrementalSync() { |
| + scoped_ptr<TaskToken> token(GetToken(FROM_HERE, TASK_TYPE_DRIVE, |
| + "Fetching remote change list")); |
| + if (!token) { |
| + pending_tasks_.push_back(base::Bind( |
| + &DriveFileSyncService::FetchChangesForIncrementalSync, AsWeakPtr())); |
| + return; |
| + } |
| + |
| + if (metadata_store_->incremental_sync_origins().empty()) { |
| + NotifyTaskDone(fileapi::SYNC_STATUS_OK, token.Pass()); |
| + return; |
| + } |
| + |
| + sync_client_->ListChanges( |
| + largest_fetched_changestamp_, |
| + base::Bind(&DriveFileSyncService::DidFetchChangesForIncrementalSync, |
| + AsWeakPtr(), base::Passed(&token))); |
| +} |
| + |
| +void DriveFileSyncService::DidFetchChangesForIncrementalSync( |
| + scoped_ptr<TaskToken> token, |
| + google_apis::GDataErrorCode error, |
| + scoped_ptr<google_apis::DocumentFeed> changes) { |
| + if (error != google_apis::HTTP_SUCCESS) { |
| + NotifyTaskDone(fileapi::SYNC_STATUS_FAILED, token.Pass()); |
|
kinuko
2012/12/04 05:18:30
GDataErrorCodeToSyncStatusCodeWrapper(error) ?
tzik
2012/12/04 06:32:32
Done.
|
| + return; |
| + } |
| + |
| + typedef ScopedVector<google_apis::DocumentEntry>::const_iterator iterator; |
| + for (iterator itr = changes->entries().begin(); |
| + itr != changes->entries().end(); ++itr) { |
| + const google_apis::DocumentEntry& entry = **itr; |
| + GURL origin; |
| + if (!GetOriginForEntry(entry, &origin)) |
| + continue; |
| + |
| + AppendNewRemoteChange(origin, entry, entry.changestamp(), |
| + REMOTE_SYNC_TYPE_INCREMENTAL); |
| + } |
| + |
| + GURL next_feed; |
| + if (changes->GetNextFeedURL(&next_feed)) { |
| + sync_client_->ContinueListing( |
| + next_feed, |
| + base::Bind(&DriveFileSyncService::DidFetchChangesForIncrementalSync, |
| + AsWeakPtr(), base::Passed(&token))); |
| + return; |
| + } |
| + |
| + largest_fetched_changestamp_ = changes->largest_changestamp(); |
| + |
| + if (changes->start_index() == 0 && changes->entries().empty()) { |
| + // If this set of changes is the first feed and it's empty, update |
| + // the polling delay to wait longer. |
| + base::TimeDelta max_delay( |
| + base::TimeDelta::FromSeconds(kMaximumPollingDelaySeconds)); |
| + |
| + polling_delay_ = base::TimeDelta::FromInternalValue(static_cast<int64>( |
| + kDelayMultiplier * polling_delay_.ToInternalValue())); |
| + if (polling_delay_ >= max_delay) |
| + polling_delay_ = max_delay; |
| + } else { |
| + polling_delay_ = base::TimeDelta::FromSeconds( |
| + kMinimumPollingDelaySeconds); |
|
kinuko
2012/12/04 05:18:30
nit: this code is totally ok but just keeping poll
tzik
2012/12/04 06:32:32
Done.
|
| + } |
| + |
| + NotifyTaskDone(fileapi::SYNC_STATUS_OK, token.Pass()); |
| +} |
| + |
| +bool DriveFileSyncService::GetOriginForEntry( |
| + const google_apis::DocumentEntry& entry, |
| + GURL* origin_out) { |
| + typedef ScopedVector<google_apis::Link>::const_iterator iterator; |
| + for (iterator itr = entry.links().begin(); |
| + itr != entry.links().end(); ++itr) { |
| + if ((*itr)->type() != google_apis::Link::LINK_PARENT) |
| + continue; |
| + GURL origin(UTF16ToUTF8((*itr)->title())); |
| + if (!origin.is_valid()) |
| + continue; |
| + |
| + if (!metadata_store_->IsBatchSyncOrigin(origin) && |
| + !metadata_store_->IsIncrementalSyncOrigin(origin)) |
| + continue; |
| + std::string resource_id(metadata_store_->GetResourceIdForOrigin(origin)); |
| + GURL resource_link(sync_client_->ResourceIdToResourceLink(resource_id)); |
| + if ((*itr)->href().GetOrigin() != resource_link.GetOrigin() || |
| + (*itr)->href().path() != resource_link.path()) |
| + continue; |
| + |
| + *origin_out = origin; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +void DriveFileSyncService::SchedulePolling() { |
| + if (polling_timer_.IsRunning()) |
| + return; |
| + |
| + DVLOG(1) << "Polling scheduled" |
| + << " (delay:" << polling_delay_.InSeconds() << ")"; |
| + |
| + polling_timer_.Start( |
| + FROM_HERE, polling_delay_, |
| + base::Bind(&DriveFileSyncService::FetchChangesForIncrementalSync, |
| + AsWeakPtr())); |
| +} |
| + |
| fileapi::SyncStatusCode |
| DriveFileSyncService::GDataErrorCodeToSyncStatusCodeWrapper( |
| google_apis::GDataErrorCode error) const { |