summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-31 21:56:34 +0000
committerlipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-31 21:56:34 +0000
commitbe0af86bae56ca50bbeadffc0da1848d56f30995 (patch)
tree50cbc411a8e0279574a226c0919fa9aa7b3fc936
parent0a23c8f93d334d4d67cd332ced96e998cada64f6 (diff)
downloadchromium_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
-rw-r--r--chrome/browser/sync/engine/sync_scheduler.cc57
-rw-r--r--chrome/browser/sync/engine/sync_scheduler.h5
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util.cc115
-rw-r--r--chrome/browser/sync/engine/syncer_types.h4
-rw-r--r--chrome/browser/sync/engine/syncer_unittest.cc5
-rw-r--r--chrome/browser/sync/protocol/sync.proto23
-rw-r--r--chrome/browser/sync/protocol/sync_protocol_error.cc63
-rw-r--r--chrome/browser/sync/protocol/sync_protocol_error.h76
-rw-r--r--chrome/browser/sync/sessions/session_state.cc2
-rw-r--r--chrome/browser/sync/sessions/session_state.h7
-rw-r--r--chrome/browser/sync/sessions/status_controller.cc26
-rw-r--r--chrome/browser/sync/sessions/status_controller.h5
-rw-r--r--chrome/browser/sync/sessions/status_controller_unittest.cc16
-rw-r--r--chrome/browser/sync/sessions/sync_session.cc2
-rw-r--r--chrome/browser/sync/sessions/sync_session.h9
-rw-r--r--chrome/browser/sync/sessions/sync_session_unittest.cc4
-rw-r--r--chrome/chrome.gyp2
-rw-r--r--chrome/test/sync/engine/syncer_command_test.h6
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.