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 7389561fbb63b9100d70db967b4579144af463fe..61ad7a766a68aeba29e64108a1aa05ada9609a62 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,19 +61,22 @@ 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::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())); |
@@ -73,7 +91,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")))); |
} |
// static |
@@ -88,15 +107,17 @@ scoped_ptr<DriveFileSyncService> DriveFileSyncService::CreateForTesting( |
DriveFileSyncService::DriveFileSyncService( |
scoped_ptr<DriveFileSyncClient> sync_client, |
scoped_ptr<DriveMetadataStore> metadata_store) |
- : 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())); |
sync_client_ = sync_client.Pass(); |
metadata_store_ = metadata_store.Pass(); |
- DidInitializeMetadataStore(GetToken(FROM_HERE), |
- fileapi::SYNC_STATUS_OK, false); |
+ DidInitializeMetadataStore( |
+ GetToken(FROM_HERE, TASK_TYPE_NONE, "Drive initialization for testing"), |
+ fileapi::SYNC_STATUS_OK, false); |
} |
DriveFileSyncService::~DriveFileSyncService() { |
@@ -115,6 +136,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(), |
@@ -146,30 +168,82 @@ void DriveFileSyncService::DidGetSyncRootDirectory( |
} |
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; |
+ |
+ // Errors which could make the service temporarily unavailable. |
+ case fileapi::SYNC_STATUS_RETRY: |
+ case fileapi::SYNC_STATUS_NETWORK_ERROR: |
+ case fileapi::SYNC_STATUS_AUTHENTICATION_FAILED: |
+ 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; |
} |
} |
@@ -184,7 +258,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, |
@@ -192,14 +267,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; |
@@ -238,7 +315,7 @@ void DriveFileSyncService::DidGetDirectoryForOrigin( |
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, |
@@ -309,7 +386,8 @@ void DriveFileSyncService::ApplyLocalChange( |
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, |
@@ -335,6 +413,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, |