diff options
author | lipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-31 21:56:34 +0000 |
---|---|---|
committer | lipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-31 21:56:34 +0000 |
commit | be0af86bae56ca50bbeadffc0da1848d56f30995 (patch) | |
tree | 50cbc411a8e0279574a226c0919fa9aa7b3fc936 | |
parent | 0a23c8f93d334d4d67cd332ced96e998cada64f6 (diff) | |
download | chromium_src-be0af86bae56ca50bbeadffc0da1848d56f30995.zip chromium_src-be0af86bae56ca50bbeadffc0da1848d56f30995.tar.gz chromium_src-be0af86bae56ca50bbeadffc0da1848d56f30995.tar.bz2 |
Server directed error handling backend code.
BUG=94007, 70276
TEST=sync_integration_tests.exe
Review URL: http://codereview.chromium.org/7621085
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99051 0039d316-1c4b-4281-b951-d872f2087c98
18 files changed, 401 insertions, 26 deletions
diff --git a/chrome/browser/sync/engine/sync_scheduler.cc b/chrome/browser/sync/engine/sync_scheduler.cc index 394fb82..3f86049 100644 --- a/chrome/browser/sync/engine/sync_scheduler.cc +++ b/chrome/browser/sync/engine/sync_scheduler.cc @@ -29,6 +29,41 @@ using syncable::ModelTypePayloadMap; using syncable::ModelTypeBitSet; using sync_pb::GetUpdatesCallerInfo; +namespace { +bool ShouldRequestEarlyExit( + const browser_sync::SyncProtocolError& error) { + switch (error.error_type) { + case browser_sync::SYNC_SUCCESS: + case browser_sync::MIGRATION_DONE: + case browser_sync::THROTTLED: + case browser_sync::TRANSIENT_ERROR: + return false; + case browser_sync::NOT_MY_BIRTHDAY: + case browser_sync::CLEAR_PENDING: + // If we send terminate sync early then |sync_cycle_ended| notification + // would not be sent. If there were no actions then |ACTIONABLE_ERROR| + // notification wouldnt be sent either. Then the UI layer would be left + // waiting forever. So assert we would send something. + DCHECK(error.action != browser_sync::UNKNOWN_ACTION); + return true; + case browser_sync::INVALID_CREDENTIAL: + // The notification for this is handled by PostAndProcessHeaders|. + // Server does no have to send any action for this. + return true; + // Make the default a NOTREACHED. So if a new error is introduced we + // think about its expected functionality. + default: + NOTREACHED(); + return false; + } +} + +bool IsActionableError( + const browser_sync::SyncProtocolError& error) { + return (error.action != browser_sync::UNKNOWN_ACTION); +} +} // namespace + SyncScheduler::DelayProvider::DelayProvider() {} SyncScheduler::DelayProvider::~DelayProvider() {} @@ -1080,6 +1115,28 @@ void SyncScheduler::OnShouldStopSyncingPermanently() { Notify(SyncEngineEvent::STOP_SYNCING_PERMANENTLY); } +void SyncScheduler::OnActionableError( + const sessions::SyncSessionSnapshot& snap) { + DCHECK_EQ(MessageLoop::current(), sync_loop_); + SVLOG(2) << "OnActionableError"; + SyncEngineEvent event(SyncEngineEvent::ACTIONABLE_ERROR); + sessions::SyncSessionSnapshot snapshot(snap); + event.snapshot = &snapshot; + session_context_->NotifyListeners(event); +} + +void SyncScheduler::OnSyncProtocolError( + const sessions::SyncSessionSnapshot& snapshot) { + DCHECK_EQ(MessageLoop::current(), sync_loop_); + if (ShouldRequestEarlyExit(snapshot.errors.sync_protocol_error)) { + SVLOG(2) << "Sync Scheduler requesting early exit."; + syncer_->RequestEarlyExit(); // Thread-safe. + } + if (IsActionableError(snapshot.errors.sync_protocol_error)) + OnActionableError(snapshot); +} + + void SyncScheduler::OnServerConnectionEvent( const ServerConnectionEvent& event) { DCHECK_EQ(MessageLoop::current(), sync_loop_); diff --git a/chrome/browser/sync/engine/sync_scheduler.h b/chrome/browser/sync/engine/sync_scheduler.h index 5deb360..1c0c9f9 100644 --- a/chrome/browser/sync/engine/sync_scheduler.h +++ b/chrome/browser/sync/engine/sync_scheduler.h @@ -120,6 +120,8 @@ class SyncScheduler : public sessions::SyncSession::Delegate, virtual void OnReceivedSessionsCommitDelay( const base::TimeDelta& new_delay) OVERRIDE; virtual void OnShouldStopSyncingPermanently() OVERRIDE; + virtual void OnSyncProtocolError( + const sessions::SyncSessionSnapshot& snapshot) OVERRIDE; // ServerConnectionEventListener implementation. // TODO(tim): schedule a nudge when valid connection detected? in 1 minute? @@ -352,6 +354,9 @@ class SyncScheduler : public sessions::SyncSession::Delegate, // the client starts up and does not need to perform an initial sync. void SendInitialSnapshot(); + virtual void OnActionableError(const sessions::SyncSessionSnapshot& snapshot); + + ScopedRunnableMethodFactory<SyncScheduler> method_factory_; // Used for logging. diff --git a/chrome/browser/sync/engine/syncer_proto_util.cc b/chrome/browser/sync/engine/syncer_proto_util.cc index 61f64fa..1597eb6d 100644 --- a/chrome/browser/sync/engine/syncer_proto_util.cc +++ b/chrome/browser/sync/engine/syncer_proto_util.cc @@ -12,12 +12,14 @@ #include "chrome/browser/sync/engine/syncer_util.h" #include "chrome/browser/sync/protocol/service_constants.h" #include "chrome/browser/sync/protocol/sync.pb.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/sessions/sync_session.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/syncable/syncable-inl.h" #include "chrome/browser/sync/syncable/syncable.h" +using browser_sync::SyncProtocolErrorType; using std::string; using std::stringstream; using syncable::BASE_VERSION; @@ -100,6 +102,9 @@ bool SyncerProtoUtil::VerifyResponseBirthday(syncable::Directory* dir, std::string local_birthday = dir->store_birthday(); + // TODO(lipalani) : Remove this check here. When the new implementation + // becomes the default this check should go away. This is handled by the + // switch case in the new implementation. if (response->error_code() == ClientToServerResponse::CLEAR_PENDING || response->error_code() == ClientToServerResponse::NOT_MY_BIRTHDAY) { // Birthday verification failures result in stopping sync and deleting @@ -211,6 +216,67 @@ bool IsVeryFirstGetUpdates(const ClientToServerMessage& message) { return true; } +SyncProtocolErrorType ConvertSyncProtocolErrorTypePBToLocalType( + const sync_pb::ClientToServerResponse::ErrorType& error_type) { + switch (error_type) { + case ClientToServerResponse::SUCCESS: + return browser_sync::SYNC_SUCCESS; + case ClientToServerResponse::NOT_MY_BIRTHDAY: + return browser_sync::NOT_MY_BIRTHDAY; + case ClientToServerResponse::THROTTLED: + return browser_sync::THROTTLED; + case ClientToServerResponse::CLEAR_PENDING: + return browser_sync::CLEAR_PENDING; + case ClientToServerResponse::TRANSIENT_ERROR: + return browser_sync::TRANSIENT_ERROR; + case ClientToServerResponse::MIGRATION_DONE: + return browser_sync::MIGRATION_DONE; + case ClientToServerResponse::UNKNOWN: + return browser_sync::UNKNOWN_ERROR; + case ClientToServerResponse::USER_NOT_ACTIVATED: + case ClientToServerResponse::AUTH_INVALID: + case ClientToServerResponse::ACCESS_DENIED: + return browser_sync::INVALID_CREDENTIAL; + default: + NOTREACHED(); + return browser_sync::UNKNOWN_ERROR; + } +} + +browser_sync::ClientAction ConvertClientActionPBToLocalClientAction( + const sync_pb::ClientToServerResponse::Error::Action& action) { + switch (action) { + case ClientToServerResponse::Error::UPGRADE_CLIENT: + return browser_sync::UPGRADE_CLIENT; + case ClientToServerResponse::Error::CLEAR_USER_DATA_AND_RESYNC: + return browser_sync::CLEAR_USER_DATA_AND_RESYNC; + case ClientToServerResponse::Error::ENABLE_SYNC_ON_ACCOUNT: + return browser_sync::ENABLE_SYNC_ON_ACCOUNT; + case ClientToServerResponse::Error::STOP_AND_RESTART_SYNC: + return browser_sync::STOP_AND_RESTART_SYNC; + case ClientToServerResponse::Error::DISABLE_SYNC_ON_CLIENT: + return browser_sync::DISABLE_SYNC_ON_CLIENT; + case ClientToServerResponse::Error::UNKNOWN_ACTION: + return browser_sync::UNKNOWN_ACTION; + default: + NOTREACHED(); + return browser_sync::UNKNOWN_ACTION; + } +} + +browser_sync::SyncProtocolError ConvertErrorPBToLocalType( + const sync_pb::ClientToServerResponse::Error& error) { + browser_sync::SyncProtocolError sync_protocol_error; + sync_protocol_error.error_type = ConvertSyncProtocolErrorTypePBToLocalType( + error.error_type()); + sync_protocol_error.error_description = error.error_description(); + sync_protocol_error.url = error.url(); + sync_protocol_error.action = ConvertClientActionPBToLocalClientAction( + error.action()); + + return sync_protocol_error; +} + } // namespace // static @@ -234,6 +300,55 @@ bool SyncerProtoUtil::PostClientToServerMessage( msg, response)) return false; + if (response->has_error()) { + // We are talking to a server that is capable of sending the |error| tag. + browser_sync::SyncProtocolError sync_protocol_error = + ConvertErrorPBToLocalType(response->error()); + + // Birthday mismatch overrides any error that is sent by the server. + if (!VerifyResponseBirthday(dir, response)) { + sync_protocol_error.error_type = browser_sync::NOT_MY_BIRTHDAY; + sync_protocol_error.action = + browser_sync::DISABLE_SYNC_ON_CLIENT; + } + + // Now set the error into the status so the layers above us could read it. + sessions::StatusController* status = session->status_controller(); + status->set_sync_protocol_error(sync_protocol_error); + + // Inform the delegate of the error we got. + session->delegate()->OnSyncProtocolError(session->TakeSnapshot()); + + // Now do any special handling for the error type and decide on the return + // value. + switch (sync_protocol_error.error_type) { + case browser_sync::UNKNOWN_ERROR: + LOG(WARNING) << "Sync protocol out-of-date. The server is using a more " + << "recent version."; + return false; + case browser_sync::SYNC_SUCCESS: + LogResponseProfilingData(*response); + return true; + case browser_sync::THROTTLED: + LOG(WARNING) << "Client silenced by server."; + session->delegate()->OnSilencedUntil(base::TimeTicks::Now() + + GetThrottleDelay(*response)); + return false; + case browser_sync::TRANSIENT_ERROR: + return false; + case browser_sync::MIGRATION_DONE: + HandleMigrationDoneResponse(response, session); + return false; + default: + NOTREACHED(); + return false; + } + } + + // TODO(lipalani): Plug this legacy implementation to the new error framework. + // New implementation code would have returned before by now. This is waiting + // on the frontend code being implemented. Otherwise ripping this would break + // sync. if (!VerifyResponseBirthday(dir, response)) { session->status_controller()->set_syncer_stuck(true); session->delegate()->OnShouldStopSyncingPermanently(); diff --git a/chrome/browser/sync/engine/syncer_types.h b/chrome/browser/sync/engine/syncer_types.h index 99e4dc3..54d4b3e 100644 --- a/chrome/browser/sync/engine/syncer_types.h +++ b/chrome/browser/sync/engine/syncer_types.h @@ -105,6 +105,10 @@ struct SyncEngineEvent { // server data have failed or succeeded. CLEAR_SERVER_DATA_SUCCEEDED, CLEAR_SERVER_DATA_FAILED, + + // This event is sent when we receive an actionable error. It is upto + // the listeners to figure out the action to take using the snapshot sent. + ACTIONABLE_ERROR, }; explicit SyncEngineEvent(EventCause cause); diff --git a/chrome/browser/sync/engine/syncer_unittest.cc b/chrome/browser/sync/engine/syncer_unittest.cc index 0d5e8c6..2810db1 100644 --- a/chrome/browser/sync/engine/syncer_unittest.cc +++ b/chrome/browser/sync/engine/syncer_unittest.cc @@ -126,6 +126,9 @@ class SyncerTest : public testing::Test, } virtual void OnShouldStopSyncingPermanently() OVERRIDE { } + virtual void OnSyncProtocolError( + const sessions::SyncSessionSnapshot& snapshot) OVERRIDE { + } // ModelSafeWorkerRegistrar implementation. virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) OVERRIDE { @@ -2140,7 +2143,7 @@ TEST_F(SyncerTest, DeletingEntryInFolder) { } syncer_->SyncShare(session_.get(), SYNCER_BEGIN, SYNCER_END); StatusController* status(session_->status_controller()); - EXPECT_TRUE(0 == status->error_counters().num_conflicting_commits); + EXPECT_TRUE(0 == status->error().num_conflicting_commits); } TEST_F(SyncerTest, DeletingEntryWithLocalEdits) { diff --git a/chrome/browser/sync/protocol/sync.proto b/chrome/browser/sync/protocol/sync.proto index ae118ce..cb4be4f 100644 --- a/chrome/browser/sync/protocol/sync.proto +++ b/chrome/browser/sync/protocol/sync.proto @@ -627,13 +627,34 @@ message ClientToServerResponse { // out-of-date client parses a value it doesn't // recognize. } + + message Error { + optional ErrorType error_type = 1 [default = UNKNOWN]; + optional string error_description = 2; + optional string url = 3; + enum Action { + UPGRADE_CLIENT = 0; // Upgrade the client to latest version. + CLEAR_USER_DATA_AND_RESYNC = 1; // Clear user data from dashboard and + // setup sync again. + ENABLE_SYNC_ON_ACCOUNT = 2; // The administrator needs to enable sync + // on the account. + STOP_AND_RESTART_SYNC = 3; // Stop sync and set up sync again. + DISABLE_SYNC_ON_CLIENT = 4; // Wipe the client of all sync data and + // stop syncing. + UNKNOWN_ACTION = 5; // This is the default. + } + optional Action action = 4 [default = UNKNOWN_ACTION]; + } + + optional Error error = 13; + // Up until protocol_version 24, the default was SUCCESS which made it // impossible to add new enum values since older clients would parse any // out-of-range value as SUCCESS. Starting with 25, unless explicitly set, // the error_code will be UNKNOWN so that clients know when they're // out-of-date. Note also that when using protocol_version < 25, // TRANSIENT_ERROR is not supported. Instead, the server sends back a HTTP - // 400 error code. + // 400 error code. This is deprecated now. optional ErrorType error_code = 4 [default = UNKNOWN]; optional string error_message = 5; diff --git a/chrome/browser/sync/protocol/sync_protocol_error.cc b/chrome/browser/sync/protocol/sync_protocol_error.cc new file mode 100644 index 0000000..7727f41 --- /dev/null +++ b/chrome/browser/sync/protocol/sync_protocol_error.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2011 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/sync/protocol/sync_protocol_error.h" + +#include <string> + +#include "base/logging.h" +#include "base/values.h" + +namespace browser_sync { +#define ENUM_CASE(x) case x: return #x; break; + +const char* GetSyncErrorTypeString(SyncProtocolErrorType type) { + switch (type) { + ENUM_CASE(SYNC_SUCCESS); + ENUM_CASE(NOT_MY_BIRTHDAY); + ENUM_CASE(THROTTLED); + ENUM_CASE(CLEAR_PENDING); + ENUM_CASE(TRANSIENT_ERROR); + ENUM_CASE(NON_RETRIABLE_ERROR); + ENUM_CASE(MIGRATION_DONE); + ENUM_CASE(INVALID_CREDENTIAL); + ENUM_CASE(UNKNOWN_ERROR); + } + NOTREACHED(); + return ""; +} + +const char* GetClientActionString(ClientAction action) { + switch (action) { + ENUM_CASE(UPGRADE_CLIENT); + ENUM_CASE(CLEAR_USER_DATA_AND_RESYNC); + ENUM_CASE(ENABLE_SYNC_ON_ACCOUNT); + ENUM_CASE(STOP_AND_RESTART_SYNC); + ENUM_CASE(DISABLE_SYNC_ON_CLIENT); + ENUM_CASE(UNKNOWN_ACTION); + } + NOTREACHED(); + return ""; +} + +SyncProtocolError::SyncProtocolError() + : error_type(UNKNOWN_ERROR), + action(UNKNOWN_ACTION) { +} + +SyncProtocolError::~SyncProtocolError() { +} + +DictionaryValue* SyncProtocolError::ToValue() const { + DictionaryValue* value = new DictionaryValue(); + value->SetString("ErrorType", + GetSyncErrorTypeString(error_type)); + value->SetString("ErrorDescription", error_description); + value->SetString("url", url); + value->SetString("action", GetClientActionString(action)); + return value; +} + +} // namespace browser_sync + diff --git a/chrome/browser/sync/protocol/sync_protocol_error.h b/chrome/browser/sync/protocol/sync_protocol_error.h new file mode 100644 index 0000000..fd7e1cb --- /dev/null +++ b/chrome/browser/sync/protocol/sync_protocol_error.h @@ -0,0 +1,76 @@ +// Copyright (c) 2011 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. +#ifndef CHROME_BROWSER_SYNC_PROTOCOL_SYNC_PROTOCOL_ERROR_H_ +#define CHROME_BROWSER_SYNC_PROTOCOL_SYNC_PROTOCOL_ERROR_H_ +#pragma once + +#include <string> + +#include "base/values.h" + +namespace browser_sync{ + +enum SyncProtocolErrorType { + // Success case. + SYNC_SUCCESS, + + // Birthday does not match that of the server. + NOT_MY_BIRTHDAY, + + // Server is busy. Try later. + THROTTLED, + + // Clear user data is being currently executed by the server. + CLEAR_PENDING, + + // Server cannot service the request now. + TRANSIENT_ERROR, + + // Server does not wish the client to retry any more until the action has + // been taken. + NON_RETRIABLE_ERROR, + + // Indicates the datatypes have been migrated and the client should resync + // them to get the latest progress markers. + MIGRATION_DONE, + + // Invalid Credential. + INVALID_CREDENTIAL, + + // The default value. + UNKNOWN_ERROR +}; + +enum ClientAction { + // Upgrade the client to latest version. + UPGRADE_CLIENT, + + // Clear user data and setup sync again. + CLEAR_USER_DATA_AND_RESYNC, + + // Set the bit on the account to enable sync. + ENABLE_SYNC_ON_ACCOUNT, + + // Stop sync and restart sync. + STOP_AND_RESTART_SYNC, + + // Wipe this client of any sync data. + DISABLE_SYNC_ON_CLIENT, + + // The default. No action. + UNKNOWN_ACTION +}; + +struct SyncProtocolError { + SyncProtocolErrorType error_type; + std::string error_description; + std::string url; + ClientAction action; + SyncProtocolError(); + ~SyncProtocolError(); + DictionaryValue* ToValue() const; +}; +} // namespace browser_sync +#endif // CHROME_BROWSER_SYNC_PROTOCOL_SYNC_PROTOCOL_ERROR_H_ + diff --git a/chrome/browser/sync/sessions/session_state.cc b/chrome/browser/sync/sessions/session_state.cc index 96aafe5..f37c9f7 100644 --- a/chrome/browser/sync/sessions/session_state.cc +++ b/chrome/browser/sync/sessions/session_state.cc @@ -382,7 +382,7 @@ bool UpdateProgress::HasConflictingUpdates() const { AllModelTypeState::AllModelTypeState(bool* dirty_flag) : unsynced_handles(dirty_flag), syncer_status(dirty_flag), - error_counters(dirty_flag), + error(dirty_flag), num_server_changes_remaining(dirty_flag, 0), commit_set(ModelSafeRoutingInfo()) { } diff --git a/chrome/browser/sync/sessions/session_state.h b/chrome/browser/sync/sessions/session_state.h index 2abd559..c6ee65b 100644 --- a/chrome/browser/sync/sessions/session_state.h +++ b/chrome/browser/sync/sessions/session_state.h @@ -23,6 +23,7 @@ #include "chrome/browser/sync/engine/syncer_types.h" #include "chrome/browser/sync/engine/syncproto.h" #include "chrome/browser/sync/sessions/ordered_commit_set.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/syncable/model_type_payload_map.h" #include "chrome/browser/sync/syncable/syncable.h" @@ -89,6 +90,7 @@ struct SyncerStatus { }; // Counters for various errors that can occur repeatedly during a sync session. +// TODO(lipalani) : Rename this structure to Error. struct ErrorCounters { ErrorCounters(); @@ -105,6 +107,9 @@ struct ErrorCounters { // transient errors. When any of these succeed, this counter is reset. // TODO(chron): Reduce number of weird counters we use. int consecutive_errors; + + // Any protocol errors that we received during this sync session. + SyncProtocolError sync_protocol_error; }; // Caller takes ownership of the returned dictionary. @@ -320,7 +325,7 @@ struct AllModelTypeState { // Used to build the shared commit message. DirtyOnWrite<std::vector<int64> > unsynced_handles; DirtyOnWrite<SyncerStatus> syncer_status; - DirtyOnWrite<ErrorCounters> error_counters; + DirtyOnWrite<ErrorCounters> error; SyncCycleControlParameters control_params; DirtyOnWrite<int64> num_server_changes_remaining; OrderedCommitSet commit_set; diff --git a/chrome/browser/sync/sessions/status_controller.cc b/chrome/browser/sync/sessions/status_controller.cc index 5f4fbf2..24a588d 100644 --- a/chrome/browser/sync/sessions/status_controller.cc +++ b/chrome/browser/sync/sessions/status_controller.cc @@ -7,6 +7,7 @@ #include <vector> #include "base/basictypes.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/syncable/model_type.h" namespace browser_sync { @@ -46,7 +47,7 @@ PerModelSafeGroupState* StatusController::GetOrCreateModelSafeGroupState( void StatusController::increment_num_conflicting_commits_by(int value) { if (value == 0) return; - shared_.error_counters.mutate()->num_conflicting_commits += value; + shared_.error.mutate()->num_conflicting_commits += value; } void StatusController::increment_num_updates_downloaded_by(int value) { @@ -65,14 +66,14 @@ void StatusController::increment_num_tombstone_updates_downloaded_by( } void StatusController::reset_num_conflicting_commits() { - if (shared_.error_counters.value().num_conflicting_commits != 0) - shared_.error_counters.mutate()->num_conflicting_commits = 0; + if (shared_.error.value().num_conflicting_commits != 0) + shared_.error.mutate()->num_conflicting_commits = 0; } void StatusController::set_num_consecutive_transient_error_commits(int value) { - if (shared_.error_counters.value().consecutive_transient_error_commits != + if (shared_.error.value().consecutive_transient_error_commits != value) { - shared_.error_counters.mutate()->consecutive_transient_error_commits = + shared_.error.mutate()->consecutive_transient_error_commits = value; } } @@ -80,13 +81,13 @@ void StatusController::set_num_consecutive_transient_error_commits(int value) { void StatusController::increment_num_consecutive_transient_error_commits_by( int value) { set_num_consecutive_transient_error_commits( - shared_.error_counters.value().consecutive_transient_error_commits + + shared_.error.value().consecutive_transient_error_commits + value); } void StatusController::set_num_consecutive_errors(int value) { - if (shared_.error_counters.value().consecutive_errors != value) - shared_.error_counters.mutate()->consecutive_errors = value; + if (shared_.error.value().consecutive_errors != value) + shared_.error.mutate()->consecutive_errors = value; } void StatusController::set_num_server_changes_remaining( @@ -127,12 +128,12 @@ void StatusController::set_unsynced_handles( void StatusController::increment_num_consecutive_errors() { set_num_consecutive_errors( - shared_.error_counters.value().consecutive_errors + 1); + shared_.error.value().consecutive_errors + 1); } void StatusController::increment_num_consecutive_errors_by(int value) { set_num_consecutive_errors( - shared_.error_counters.value().consecutive_errors + value); + shared_.error.value().consecutive_errors + value); } void StatusController::increment_num_successful_bookmark_commits() { @@ -152,6 +153,11 @@ void StatusController::increment_num_server_overwrites() { shared_.syncer_status.mutate()->num_server_overwrites++; } +void StatusController::set_sync_protocol_error( + const SyncProtocolError& error) { + shared_.error.mutate()->sync_protocol_error = error; +} + void StatusController::set_commit_set(const OrderedCommitSet& commit_set) { DCHECK(!group_restriction_in_effect_); shared_.commit_set = commit_set; diff --git a/chrome/browser/sync/sessions/status_controller.h b/chrome/browser/sync/sessions/status_controller.h index 329871f..a12bee8 100644 --- a/chrome/browser/sync/sessions/status_controller.h +++ b/chrome/browser/sync/sessions/status_controller.h @@ -103,8 +103,8 @@ class StatusController { } // Errors and SyncerStatus. - const ErrorCounters& error_counters() const { - return shared_.error_counters.value(); + const ErrorCounters& error() const { + return shared_.error.value(); } const SyncerStatus& syncer_status() const { return shared_.syncer_status.value(); @@ -229,6 +229,7 @@ class StatusController { void set_unsynced_handles(const std::vector<int64>& unsynced_handles); void increment_num_local_overwrites(); void increment_num_server_overwrites(); + void set_sync_protocol_error(const SyncProtocolError& error); void set_commit_set(const OrderedCommitSet& commit_set); void update_conflict_sets_built(bool built); diff --git a/chrome/browser/sync/sessions/status_controller_unittest.cc b/chrome/browser/sync/sessions/status_controller_unittest.cc index 668b66b..bd7296b 100644 --- a/chrome/browser/sync/sessions/status_controller_unittest.cc +++ b/chrome/browser/sync/sessions/status_controller_unittest.cc @@ -108,21 +108,21 @@ TEST_F(StatusControllerTest, StaysClean) { TEST_F(StatusControllerTest, ReadYourWrites) { StatusController status(routes_); status.increment_num_conflicting_commits_by(1); - EXPECT_EQ(1, status.error_counters().num_conflicting_commits); + EXPECT_EQ(1, status.error().num_conflicting_commits); status.set_num_consecutive_transient_error_commits(6); - EXPECT_EQ(6, status.error_counters().consecutive_transient_error_commits); + EXPECT_EQ(6, status.error().consecutive_transient_error_commits); status.increment_num_consecutive_transient_error_commits_by(1); - EXPECT_EQ(7, status.error_counters().consecutive_transient_error_commits); + EXPECT_EQ(7, status.error().consecutive_transient_error_commits); status.increment_num_consecutive_transient_error_commits_by(0); - EXPECT_EQ(7, status.error_counters().consecutive_transient_error_commits); + EXPECT_EQ(7, status.error().consecutive_transient_error_commits); status.set_num_consecutive_errors(8); - EXPECT_EQ(8, status.error_counters().consecutive_errors); + EXPECT_EQ(8, status.error().consecutive_errors); status.increment_num_consecutive_errors(); - EXPECT_EQ(9, status.error_counters().consecutive_errors); + EXPECT_EQ(9, status.error().consecutive_errors); status.increment_num_consecutive_errors_by(2); - EXPECT_EQ(11, status.error_counters().consecutive_errors); + EXPECT_EQ(11, status.error().consecutive_errors); status.set_num_server_changes_remaining(13); EXPECT_EQ(13, status.num_server_changes_remaining()); @@ -211,7 +211,7 @@ TEST_F(StatusControllerTest, Unrestricted) { status.mutable_commit_response(); status.updates_response(); status.mutable_updates_response(); - status.error_counters(); + status.error(); status.syncer_status(); status.num_server_changes_remaining(); status.commit_ids(); diff --git a/chrome/browser/sync/sessions/sync_session.cc b/chrome/browser/sync/sessions/sync_session.cc index 037917b..930664d 100644 --- a/chrome/browser/sync/sessions/sync_session.cc +++ b/chrome/browser/sync/sessions/sync_session.cc @@ -108,7 +108,7 @@ SyncSessionSnapshot SyncSession::TakeSnapshot() const { return SyncSessionSnapshot( status_controller_->syncer_status(), - status_controller_->error_counters(), + status_controller_->error(), status_controller_->num_server_changes_remaining(), is_share_useable, initial_sync_ended, diff --git a/chrome/browser/sync/sessions/sync_session.h b/chrome/browser/sync/sessions/sync_session.h index 9520f9d..04b1a1a 100644 --- a/chrome/browser/sync/sessions/sync_session.h +++ b/chrome/browser/sync/sessions/sync_session.h @@ -79,8 +79,17 @@ class SyncSession { // the Syncer detects that the backend store has fundamentally changed or // is a different instance altogether (e.g. swapping from a test instance // to production, or a global stop syncing operation has wiped the store). + // TODO(lipalani) : Replace this function with the one below. This function + // stops the current sync cycle and purges the client. In the new model + // the former would be done by the |SyncProtocolError| and + // the latter(which is an action) would be done in ProfileSyncService + // along with the rest of the actions. virtual void OnShouldStopSyncingPermanently() = 0; + // Called for the syncer to respond to the error sent by the server. + virtual void OnSyncProtocolError( + const sessions::SyncSessionSnapshot& snapshot) = 0; + protected: virtual ~Delegate() {} }; diff --git a/chrome/browser/sync/sessions/sync_session_unittest.cc b/chrome/browser/sync/sessions/sync_session_unittest.cc index fe5f6ed..4c58b45 100644 --- a/chrome/browser/sync/sessions/sync_session_unittest.cc +++ b/chrome/browser/sync/sessions/sync_session_unittest.cc @@ -71,6 +71,10 @@ class SyncSessionTest : public testing::Test, virtual void OnShouldStopSyncingPermanently() OVERRIDE { FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently"); } + virtual void OnSyncProtocolError( + const sessions::SyncSessionSnapshot& snapshot) { + FailControllerInvocationIfDisabled("SyncProtocolError"); + } // ModelSafeWorkerRegistrar implementation. virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) OVERRIDE {} diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 4a6ca85..13b7862 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -676,6 +676,8 @@ 'browser/sync/protocol/proto_value_conversions.cc', 'browser/sync/protocol/proto_value_conversions.h', 'browser/sync/protocol/service_constants.h', + 'browser/sync/protocol/sync_protocol_error.cc', + 'browser/sync/protocol/sync_protocol_error.h', 'browser/sync/sessions/ordered_commit_set.cc', 'browser/sync/sessions/ordered_commit_set.h', 'browser/sync/sessions/session_state.cc', diff --git a/chrome/test/sync/engine/syncer_command_test.h b/chrome/test/sync/engine/syncer_command_test.h index a5a8235..53dc6fd 100644 --- a/chrome/test/sync/engine/syncer_command_test.h +++ b/chrome/test/sync/engine/syncer_command_test.h @@ -54,7 +54,11 @@ class SyncerCommandTestWithParam : public testing::TestWithParam<T>, FAIL() << "Should not get sessions commit delay."; } virtual void OnShouldStopSyncingPermanently() OVERRIDE { - FAIL() << "Shouldn't be forced to stop syncing."; + FAIL() << "Shouldn't be called."; + } + virtual void OnSyncProtocolError( + const sessions::SyncSessionSnapshot& session) OVERRIDE { + FAIL() << "Shouldn't be called."; } // ModelSafeWorkerRegistrar implementation. |