Extension syncing: Introduce a NeedsSync pref
[chromium-blink-merge.git] / sync / engine / backoff_delay_provider.cc
blobbff3fd61c6e1d23456d657711a548a679cf9c72c
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sync/engine/backoff_delay_provider.h"
7 #include "base/rand_util.h"
8 #include "sync/internal_api/public/engine/polling_constants.h"
9 #include "sync/internal_api/public/sessions/model_neutral_state.h"
10 #include "sync/internal_api/public/util/syncer_error.h"
12 using base::TimeDelta;
14 namespace syncer {
16 // static
17 BackoffDelayProvider* BackoffDelayProvider::FromDefaults() {
18 return new BackoffDelayProvider(
19 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
20 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds));
23 // static
24 BackoffDelayProvider* BackoffDelayProvider::WithShortInitialRetryOverride() {
25 return new BackoffDelayProvider(
26 TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds),
27 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds));
30 BackoffDelayProvider::BackoffDelayProvider(
31 const base::TimeDelta& default_initial_backoff,
32 const base::TimeDelta& short_initial_backoff)
33 : default_initial_backoff_(default_initial_backoff),
34 short_initial_backoff_(short_initial_backoff) {
37 BackoffDelayProvider::~BackoffDelayProvider() {}
39 TimeDelta BackoffDelayProvider::GetDelay(const base::TimeDelta& last_delay) {
40 if (last_delay.InSeconds() >= kMaxBackoffSeconds)
41 return TimeDelta::FromSeconds(kMaxBackoffSeconds);
43 // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2
44 int64 backoff_s =
45 std::max(static_cast<int64>(1),
46 last_delay.InSeconds() * kBackoffRandomizationFactor);
48 // Flip a coin to randomize backoff interval by +/- 50%.
49 int rand_sign = base::RandInt(0, 1) * 2 - 1;
51 // Truncation is adequate for rounding here.
52 backoff_s = backoff_s +
53 (rand_sign * (last_delay.InSeconds() / kBackoffRandomizationFactor));
55 // Cap the backoff interval.
56 backoff_s = std::max(static_cast<int64>(1),
57 std::min(backoff_s, kMaxBackoffSeconds));
59 return TimeDelta::FromSeconds(backoff_s);
62 TimeDelta BackoffDelayProvider::GetInitialDelay(
63 const sessions::ModelNeutralState& state) const {
64 // NETWORK_CONNECTION_UNAVAILABLE implies we did not even manage to hit the
65 // wire; the failure occurred locally. Note that if commit_result is *not*
66 // UNSET, this implies download_updates_result succeeded. Also note that
67 // last_get_key_result is coupled to last_download_updates_result in that
68 // they are part of the same GetUpdates request, so we only check if
69 // the download request is CONNECTION_UNAVAILABLE.
71 // TODO(tim): Should we treat NETWORK_IO_ERROR similarly? It's different
72 // from CONNECTION_UNAVAILABLE in that a request may well have succeeded
73 // in contacting the server (e.g we got a 200 back), but we failed
74 // trying to parse the response (actual content length != HTTP response
75 // header content length value). For now since we're considering
76 // merging this code to branches and I haven't audited all the
77 // NETWORK_IO_ERROR cases carefully, I'm going to target the fix
78 // very tightly (see bug chromium-os:35073). DIRECTORY_LOOKUP_FAILED is
79 // another example of something that shouldn't backoff, though the
80 // scheduler should probably be handling these cases differently. See
81 // the TODO(rlarocque) in ScheduleNextSync.
82 if (state.commit_result == NETWORK_CONNECTION_UNAVAILABLE ||
83 state.last_download_updates_result == NETWORK_CONNECTION_UNAVAILABLE) {
84 return short_initial_backoff_;
87 if (SyncerErrorIsError(state.last_get_key_result))
88 return default_initial_backoff_;
90 // Note: If we received a MIGRATION_DONE on download updates, then commit
91 // should not have taken place. Moreover, if we receive a MIGRATION_DONE
92 // on commit, it means that download updates succeeded. Therefore, we only
93 // need to check if either code is equal to SERVER_RETURN_MIGRATION_DONE,
94 // and not if there were any more serious errors requiring the long retry.
95 if (state.last_download_updates_result == SERVER_RETURN_MIGRATION_DONE ||
96 state.commit_result == SERVER_RETURN_MIGRATION_DONE) {
97 return short_initial_backoff_;
100 // If a datatype decides the GetUpdates must be retried (e.g. because the
101 // context has been updated since the request), use the short delay.
102 if (state.last_download_updates_result == DATATYPE_TRIGGERED_RETRY)
103 return short_initial_backoff_;
105 // When the server tells us we have a conflict, then we should download the
106 // latest updates so we can see the conflict ourselves, resolve it locally,
107 // then try again to commit. Running another sync cycle will do all these
108 // things. There's no need to back off, we can do this immediately.
110 // TODO(sync): We shouldn't need to handle this in BackoffDelayProvider.
111 // There should be a way to deal with protocol errors before we get to this
112 // point.
113 if (state.commit_result == SERVER_RETURN_CONFLICT)
114 return short_initial_backoff_;
116 return default_initial_backoff_;
119 } // namespace syncer