summaryrefslogtreecommitdiffstats
path: root/sync/engine
diff options
context:
space:
mode:
authorrlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-21 23:27:53 +0000
committerrlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-21 23:27:53 +0000
commit16dbe4e7d88913eeb4574e9b6a8222d7e76c8981 (patch)
tree0e3a433004010a1bd341575451a80d7ffeb38146 /sync/engine
parenta036232dfd4ae7b50ee97e69dbfa9ebb8f913f68 (diff)
downloadchromium_src-16dbe4e7d88913eeb4574e9b6a8222d7e76c8981.zip
chromium_src-16dbe4e7d88913eeb4574e9b6a8222d7e76c8981.tar.gz
chromium_src-16dbe4e7d88913eeb4574e9b6a8222d7e76c8981.tar.bz2
sync: Retry soon when server returns conflict
When the server gives us a conflict response, we ought to fetch updates in order to figure out what the server is complaining about, resolve any conflicts locally, then re-commit. The current syncer, although not intentionally built to handle this scenario, does the right thing. It considers the server's return code to be indicative of a transient error, so it backs off then retries later. The retry sync cycle will fetch updates, resolve conflicts, and recommit, which is exactly what we want. Unfortunately, the backoff can take five minutes. This commit reduces the time spent unnecessarily backing off. It's not the cleanest solution, but its implementation is easy and safe. BUG=157955 Review URL: https://chromiumcodereview.appspot.com/11411041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169158 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/engine')
-rw-r--r--sync/engine/backoff_delay_provider.cc12
-rw-r--r--sync/engine/backoff_delay_provider_unittest.cc8
-rw-r--r--sync/engine/process_commit_response_command.cc18
3 files changed, 23 insertions, 15 deletions
diff --git a/sync/engine/backoff_delay_provider.cc b/sync/engine/backoff_delay_provider.cc
index d030e26..f8e2750 100644
--- a/sync/engine/backoff_delay_provider.cc
+++ b/sync/engine/backoff_delay_provider.cc
@@ -97,6 +97,18 @@ TimeDelta BackoffDelayProvider::GetInitialDelay(
return short_initial_backoff_;
}
+ // When the server tells us we have a conflict, then we should download the
+ // latest updates so we can see the conflict ourselves, resolve it locally,
+ // then try again to commit. Running another sync cycle will do all these
+ // things. There's no need to back off, we can do this immediately.
+ //
+ // TODO(sync): We shouldn't need to handle this in BackoffDelayProvider.
+ // There should be a way to deal with protocol errors before we get to this
+ // point.
+ if (state.commit_result == SERVER_RETURN_CONFLICT) {
+ return short_initial_backoff_;
+ }
+
return default_initial_backoff_;
}
diff --git a/sync/engine/backoff_delay_provider_unittest.cc b/sync/engine/backoff_delay_provider_unittest.cc
index 8184b0f..4e7bfc2 100644
--- a/sync/engine/backoff_delay_provider_unittest.cc
+++ b/sync/engine/backoff_delay_provider_unittest.cc
@@ -72,6 +72,10 @@ TEST_F(BackoffDelayProviderTest, GetInitialDelay) {
state.commit_result = NETWORK_CONNECTION_UNAVAILABLE;
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
+
+ state.commit_result = SERVER_RETURN_CONFLICT;
+ EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
+ delay->GetInitialDelay(state).InSeconds());
}
TEST_F(BackoffDelayProviderTest, GetInitialDelayWithOverride) {
@@ -106,6 +110,10 @@ TEST_F(BackoffDelayProviderTest, GetInitialDelayWithOverride) {
state.commit_result = SERVER_RETURN_MIGRATION_DONE;
EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
delay->GetInitialDelay(state).InSeconds());
+
+ state.commit_result = SERVER_RETURN_CONFLICT;
+ EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
+ delay->GetInitialDelay(state).InSeconds());
}
} // namespace syncer
diff --git a/sync/engine/process_commit_response_command.cc b/sync/engine/process_commit_response_command.cc
index 200a710..811be36 100644
--- a/sync/engine/process_commit_response_command.cc
+++ b/sync/engine/process_commit_response_command.cc
@@ -171,21 +171,9 @@ SyncerError ProcessCommitResponseCommand::ProcessCommitResponse(
// to resolve the conflict. That's not what this client does.
//
// We don't currently have any code to support that exceptional control
- // flow. We don't intend to add any because this response code will be
- // deprecated soon. Instead, we handle this in the same way that we handle
- // transient errors. We abort the current sync cycle, wait a little while,
- // then try again. The retry sync cycle will attempt to download updates
- // which should be sufficient to trigger client-side conflict resolution.
- //
- // Not treating this as an error would be dangerous. There's a risk that
- // the commit loop would loop indefinitely. The loop won't exit until the
- // number of unsynced items hits zero or an error is detected. If we're
- // constantly receiving conflict responses and we don't treat them as
- // errors, there would be no reason to leave that loop.
- //
- // TODO: Remove this option when the CONFLICT return value is fully
- // deprecated.
- return SERVER_RETURN_TRANSIENT_ERROR;
+ // flow. Instead, we abort the current sync cycle and start a new one. The
+ // end result is the same.
+ return SERVER_RETURN_CONFLICT;
} else {
LOG(FATAL) << "Inconsistent counts when processing commit response";
return SYNCER_OK;