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 da61e9ad3114ab98a058138a31f42fcf2c9a6e46..6e60df465dceb37a25199e09d37a76233f643932 100644 |
--- a/chrome/browser/sync_file_system/drive_file_sync_service.cc |
+++ b/chrome/browser/sync_file_system/drive_file_sync_service.cc |
@@ -30,13 +30,28 @@ const char DriveFileSyncService::kServiceName[] = "drive"; |
class DriveFileSyncService::TaskToken { |
public: |
explicit TaskToken(const base::WeakPtr<DriveFileSyncService>& sync_service) |
- : sync_service_(sync_service) { |
+ : sync_service_(sync_service), |
+ task_type_(TASK_TYPE_NONE) { |
} |
- void set_location(const tracked_objects::Location& from_here) { |
- from_here_ = from_here; |
+ void ResetTask(const tracked_objects::Location& location) { |
+ location_ = location; |
+ task_type_ = TASK_TYPE_NONE; |
+ description_.clear(); |
} |
+ void UpdateTask(const tracked_objects::Location& location, |
+ TaskType task_type, |
+ const std::string& description) { |
+ location_ = location; |
+ task_type_ = task_type; |
+ description_ = description; |
+ } |
+ |
+ const tracked_objects::Location& location() const { return location_; } |
+ TaskType task_type() const { return task_type_; } |
+ const std::string& description() const { return description_; } |
+ |
~TaskToken() { |
// All task on DriveFileSyncService must hold TaskToken instance to ensure |
// no other tasks are running. Also, as soon as a task finishes to work, |
@@ -46,18 +61,19 @@ class DriveFileSyncService::TaskToken { |
DCHECK(!sync_service_); |
if (sync_service_) { |
LOG(ERROR) << "Unexpected TaskToken deletion from: " |
- << from_here_.ToString(); |
+ << location_.ToString() << " while: " << description_; |
} |
} |
private: |
- tracked_objects::Location from_here_; |
base::WeakPtr<DriveFileSyncService> sync_service_; |
+ tracked_objects::Location location_; |
+ TaskType task_type_; |
+ std::string description_; |
DISALLOW_COPY_AND_ASSIGN(TaskToken); |
}; |
- |
DriveFileSyncService::RemoteChange::RemoteChange() |
: changestamp(0), |
change(fileapi::FileChange::FILE_CHANGE_ADD_OR_UPDATE, |
@@ -89,23 +105,9 @@ bool DriveFileSyncService::RemoteChangeComparator::operator()( |
return false; |
} |
-// Called by CreateForTesting. |
-DriveFileSyncService::DriveFileSyncService( |
- scoped_ptr<DriveFileSyncClient> sync_client, |
- scoped_ptr<DriveMetadataStore> metadata_store) |
- : status_(fileapi::SYNC_STATUS_OK), |
- largest_changestamp_(0), |
- weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
- token_.reset(new TaskToken(weak_factory_.GetWeakPtr())); |
- sync_client_ = sync_client.Pass(); |
- metadata_store_ = metadata_store.Pass(); |
- |
- DidInitializeMetadataStore(GetToken(FROM_HERE), |
- fileapi::SYNC_STATUS_OK, false); |
-} |
- |
DriveFileSyncService::DriveFileSyncService(Profile* profile) |
- : status_(fileapi::SYNC_STATUS_OK), |
+ : last_operation_status_(fileapi::SYNC_STATUS_OK), |
+ state_(REMOTE_SERVICE_OK), |
largest_changestamp_(0), |
weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
token_.reset(new TaskToken(weak_factory_.GetWeakPtr())); |
@@ -120,7 +122,8 @@ DriveFileSyncService::DriveFileSyncService(Profile* profile) |
metadata_store_->Initialize( |
base::Bind(&DriveFileSyncService::DidInitializeMetadataStore, |
weak_factory_.GetWeakPtr(), |
- base::Passed(GetToken(FROM_HERE)))); |
+ base::Passed(GetToken(FROM_HERE, TASK_TYPE_DATABASE, |
+ "Metadata database initialization")))); |
} |
DriveFileSyncService::~DriveFileSyncService() { |
@@ -145,7 +148,8 @@ void DriveFileSyncService::RemoveObserver(Observer* observer) { |
void DriveFileSyncService::RegisterOriginForTrackingChanges( |
const GURL& origin, |
const fileapi::SyncStatusCallback& callback) { |
- scoped_ptr<TaskToken> token(GetToken(FROM_HERE)); |
+ scoped_ptr<TaskToken> token(GetToken( |
+ FROM_HERE, TASK_TYPE_DRIVE, "Retrieving origin metadata")); |
if (!token) { |
pending_tasks_.push_back(base::Bind( |
&DriveFileSyncService::RegisterOriginForTrackingChanges, |
@@ -153,14 +157,16 @@ void DriveFileSyncService::RegisterOriginForTrackingChanges( |
return; |
} |
- if (status_ != fileapi::SYNC_STATUS_OK) { |
- NotifyTaskDone(status_, token.Pass()); |
- callback.Run(status_); |
+ if (state_ == REMOTE_SERVICE_DISABLED) { |
+ token->ResetTask(FROM_HERE); |
+ NotifyTaskDone(last_operation_status_, token.Pass()); |
+ callback.Run(last_operation_status_); |
return; |
} |
if (metadata_store_->IsIncrementalSyncOrigin(origin) || |
metadata_store_->IsBatchSyncOrigin(origin)) { |
+ token->ResetTask(FROM_HERE); |
NotifyTaskDone(fileapi::SYNC_STATUS_OK, token.Pass()); |
callback.Run(fileapi::SYNC_STATUS_OK); |
return; |
@@ -177,7 +183,7 @@ void DriveFileSyncService::RegisterOriginForTrackingChanges( |
void DriveFileSyncService::UnregisterOriginForTrackingChanges( |
const GURL& origin, |
const fileapi::SyncStatusCallback& callback) { |
- scoped_ptr<TaskToken> token(GetToken(FROM_HERE)); |
+ scoped_ptr<TaskToken> token(GetToken(FROM_HERE, TASK_TYPE_DATABASE, "")); |
if (!token) { |
pending_tasks_.push_back(base::Bind( |
&DriveFileSyncService::UnregisterOriginForTrackingChanges, |
@@ -237,31 +243,104 @@ void DriveFileSyncService::ApplyLocalChange( |
callback.Run(fileapi::SYNC_STATUS_FAILED); |
} |
+// Called by CreateForTesting. |
+DriveFileSyncService::DriveFileSyncService( |
+ scoped_ptr<DriveFileSyncClient> sync_client, |
+ scoped_ptr<DriveMetadataStore> metadata_store) |
+ : last_operation_status_(fileapi::SYNC_STATUS_OK), |
+ state_(REMOTE_SERVICE_OK), |
+ largest_changestamp_(0), |
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
+ token_.reset(new TaskToken(weak_factory_.GetWeakPtr())); |
+ sync_client_ = sync_client.Pass(); |
+ metadata_store_ = metadata_store.Pass(); |
+ |
+ DidInitializeMetadataStore( |
+ GetToken(FROM_HERE, TASK_TYPE_NONE, "Drive initialization for testing"), |
+ fileapi::SYNC_STATUS_OK, false); |
+} |
+ |
scoped_ptr<DriveFileSyncService::TaskToken> DriveFileSyncService::GetToken( |
- const tracked_objects::Location& from_here) { |
+ const tracked_objects::Location& from_here, |
+ TaskType task_type, |
+ const std::string& description) { |
if (!token_) |
return scoped_ptr<TaskToken>(); |
- token_->set_location(from_here); |
+ token_->UpdateTask(from_here, task_type, description); |
return token_.Pass(); |
} |
void DriveFileSyncService::NotifyTaskDone(fileapi::SyncStatusCode status, |
scoped_ptr<TaskToken> token) { |
DCHECK(token); |
- bool status_changed = status_ != status; |
- status_ = status; |
+ last_operation_status_ = status; |
token_ = token.Pass(); |
- token_->set_location(tracked_objects::Location()); |
+ if (token_->task_type() != TASK_TYPE_NONE) { |
+ RemoteServiceState old_state = state_; |
+ UpdateServiceState(); |
+ |
+ // Notify remote sync service state for healthy running updates (OK to OK |
+ // state transition) and for any state changes. |
+ if ((state_ == REMOTE_SERVICE_OK && !token_->description().empty()) || |
+ old_state != state_) { |
+ FOR_EACH_OBSERVER(Observer, observers_, |
+ OnRemoteServiceStateUpdated(state_, |
+ token_->description())); |
+ } |
+ } |
+ |
+ token_->ResetTask(FROM_HERE); |
if (status == fileapi::SYNC_STATUS_OK && !pending_tasks_.empty()) { |
base::Closure closure = pending_tasks_.front(); |
pending_tasks_.pop_front(); |
closure.Run(); |
} |
+} |
- if (status_changed) { |
- // TODO(tzik): Refine the status to track the error. |
- FOR_EACH_OBSERVER(Observer, observers_, OnRemoteSyncStatusChanged(status)); |
+void DriveFileSyncService::UpdateServiceState() { |
+ switch (last_operation_status_) { |
+ // Possible regular operation errors. |
+ case fileapi::SYNC_STATUS_OK: |
+ case fileapi::SYNC_STATUS_FILE_BUSY: |
+ case fileapi::SYNC_STATUS_HAS_CONFLICT: |
+ case fileapi::SYNC_STATUS_NOT_A_CONFLICT: |
+ case fileapi::SYNC_STATUS_NO_CHANGE_TO_SYNC: |
+ case fileapi::SYNC_FILE_ERROR_NOT_FOUND: |
+ case fileapi::SYNC_FILE_ERROR_FAILED: |
+ case fileapi::SYNC_FILE_ERROR_NO_SPACE: |
+ // If the service type was DRIVE and the status was ok, the state |
+ // should be migrated to OK state. |
+ if (token_->task_type() == TASK_TYPE_DRIVE) |
+ state_ = REMOTE_SERVICE_OK; |
+ break; |
+ |
+ // Authentication error. |
+ case fileapi::SYNC_STATUS_AUTHENTICATION_FAILED: |
+ state_ = REMOTE_SERVICE_AUTHENTICATION_REQUIRED; |
+ break; |
+ |
+ // Errors which could make the service temporarily unavailable. |
+ case fileapi::SYNC_STATUS_RETRY: |
+ case fileapi::SYNC_STATUS_NETWORK_ERROR: |
+ state_ = REMOTE_SERVICE_TEMPORARY_UNAVAILABLE; |
+ break; |
+ |
+ // Errors which would require manual user intervention to resolve. |
+ case fileapi::SYNC_DATABASE_ERROR_CORRUPTION: |
+ case fileapi::SYNC_DATABASE_ERROR_IO_ERROR: |
+ case fileapi::SYNC_DATABASE_ERROR_FAILED: |
+ case fileapi::SYNC_STATUS_ABORT: |
+ case fileapi::SYNC_STATUS_FAILED: |
+ state_ = REMOTE_SERVICE_DISABLED; |
+ break; |
+ |
+ // Unexpected status code. They should be explicitly added to one of the |
+ // above three cases. |
+ default: |
+ NOTREACHED(); |
+ state_ = REMOTE_SERVICE_DISABLED; |
+ break; |
} |
} |
@@ -278,6 +357,7 @@ void DriveFileSyncService::DidInitializeMetadataStore( |
DCHECK(metadata_store_->batch_sync_origins().empty()); |
DCHECK(metadata_store_->incremental_sync_origins().empty()); |
+ token->UpdateTask(FROM_HERE, TASK_TYPE_DRIVE, "Retrieving drive root"); |
sync_client_->GetDriveDirectoryForSyncRoot( |
base::Bind(&DriveFileSyncService::DidGetSyncRootDirectory, |
weak_factory_.GetWeakPtr(), |
@@ -311,7 +391,8 @@ void DriveFileSyncService::DidGetSyncRootDirectory( |
void DriveFileSyncService::StartBatchSyncForOrigin( |
const GURL& origin, |
const std::string& resource_id) { |
- scoped_ptr<TaskToken> token(GetToken(FROM_HERE)); |
+ scoped_ptr<TaskToken> token( |
+ GetToken(FROM_HERE, TASK_TYPE_DRIVE, "Retrieving largest changestamp")); |
if (!token) { |
pending_tasks_.push_back(base::Bind( |
&DriveFileSyncService::StartBatchSyncForOrigin, |
@@ -359,6 +440,8 @@ void DriveFileSyncService::DidGetLargestChangeStampForBatchSync( |
return; |
} |
+ DCHECK(token); |
+ token->UpdateTask(FROM_HERE, TASK_TYPE_DRIVE, "Retrieving remote files"); |
sync_client_->ListFiles( |
resource_id, |
base::Bind(&DriveFileSyncService::DidGetDirectoryContentForBatchSync, |