OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sync/engine/sync_scheduler_impl.h" | 5 #include "sync/engine/sync_scheduler_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstring> | 8 #include <cstring> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/location.h" | 12 #include "base/location.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
15 #include "base/rand_util.h" | 15 #include "sync/engine/backoff_delay_provider.h" |
16 #include "sync/engine/syncer.h" | 16 #include "sync/engine/syncer.h" |
17 #include "sync/engine/throttled_data_type_tracker.h" | 17 #include "sync/engine/throttled_data_type_tracker.h" |
18 #include "sync/protocol/proto_enum_conversions.h" | 18 #include "sync/protocol/proto_enum_conversions.h" |
19 #include "sync/protocol/sync.pb.h" | 19 #include "sync/protocol/sync.pb.h" |
20 #include "sync/util/data_type_histogram.h" | 20 #include "sync/util/data_type_histogram.h" |
21 #include "sync/util/logging.h" | 21 #include "sync/util/logging.h" |
22 | 22 |
23 using base::TimeDelta; | 23 using base::TimeDelta; |
24 using base::TimeTicks; | 24 using base::TimeTicks; |
25 | 25 |
26 namespace syncer { | 26 namespace syncer { |
27 | 27 |
28 using sessions::SyncSession; | 28 using sessions::SyncSession; |
29 using sessions::SyncSessionSnapshot; | 29 using sessions::SyncSessionSnapshot; |
30 using sessions::SyncSourceInfo; | 30 using sessions::SyncSourceInfo; |
31 using sync_pb::GetUpdatesCallerInfo; | 31 using sync_pb::GetUpdatesCallerInfo; |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 // For integration tests only. Override initial backoff value. | |
36 // TODO(tim): Remove this egregiousness, use command line flag and plumb | |
37 // through. Done this way to reduce diffs in hotfix. | |
38 static bool g_force_short_retry = false; | |
39 | |
40 bool ShouldRequestEarlyExit(const SyncProtocolError& error) { | 35 bool ShouldRequestEarlyExit(const SyncProtocolError& error) { |
41 switch (error.error_type) { | 36 switch (error.error_type) { |
42 case SYNC_SUCCESS: | 37 case SYNC_SUCCESS: |
43 case MIGRATION_DONE: | 38 case MIGRATION_DONE: |
44 case THROTTLED: | 39 case THROTTLED: |
45 case TRANSIENT_ERROR: | 40 case TRANSIENT_ERROR: |
46 return false; | 41 return false; |
47 case NOT_MY_BIRTHDAY: | 42 case NOT_MY_BIRTHDAY: |
48 case CLEAR_PENDING: | 43 case CLEAR_PENDING: |
49 // If we send terminate sync early then |sync_cycle_ended| notification | 44 // If we send terminate sync early then |sync_cycle_ended| notification |
(...skipping 28 matching lines...) Expand all Loading... |
78 const ModelSafeRoutingInfo& routing_info, | 73 const ModelSafeRoutingInfo& routing_info, |
79 const base::Closure& ready_task) | 74 const base::Closure& ready_task) |
80 : source(source), | 75 : source(source), |
81 types_to_download(types_to_download), | 76 types_to_download(types_to_download), |
82 routing_info(routing_info), | 77 routing_info(routing_info), |
83 ready_task(ready_task) { | 78 ready_task(ready_task) { |
84 DCHECK(!ready_task.is_null()); | 79 DCHECK(!ready_task.is_null()); |
85 } | 80 } |
86 ConfigurationParams::~ConfigurationParams() {} | 81 ConfigurationParams::~ConfigurationParams() {} |
87 | 82 |
88 SyncSchedulerImpl::DelayProvider::DelayProvider() {} | |
89 SyncSchedulerImpl::DelayProvider::~DelayProvider() {} | |
90 | |
91 SyncSchedulerImpl::WaitInterval::WaitInterval() | 83 SyncSchedulerImpl::WaitInterval::WaitInterval() |
92 : mode(UNKNOWN), | 84 : mode(UNKNOWN), |
93 had_nudge(false) { | 85 had_nudge(false) { |
94 } | 86 } |
95 | 87 |
96 SyncSchedulerImpl::WaitInterval::~WaitInterval() {} | 88 SyncSchedulerImpl::WaitInterval::~WaitInterval() {} |
97 | 89 |
98 #define ENUM_CASE(x) case x: return #x; break; | 90 #define ENUM_CASE(x) case x: return #x; break; |
99 | 91 |
100 const char* SyncSchedulerImpl::WaitInterval::GetModeString(Mode mode) { | 92 const char* SyncSchedulerImpl::WaitInterval::GetModeString(Mode mode) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 switch (purpose) { | 125 switch (purpose) { |
134 ENUM_CASE(UNKNOWN); | 126 ENUM_CASE(UNKNOWN); |
135 ENUM_CASE(POLL); | 127 ENUM_CASE(POLL); |
136 ENUM_CASE(NUDGE); | 128 ENUM_CASE(NUDGE); |
137 ENUM_CASE(CONFIGURATION); | 129 ENUM_CASE(CONFIGURATION); |
138 } | 130 } |
139 NOTREACHED(); | 131 NOTREACHED(); |
140 return ""; | 132 return ""; |
141 } | 133 } |
142 | 134 |
143 TimeDelta SyncSchedulerImpl::DelayProvider::GetDelay( | |
144 const base::TimeDelta& last_delay) { | |
145 return SyncSchedulerImpl::GetRecommendedDelay(last_delay); | |
146 } | |
147 | |
148 GetUpdatesCallerInfo::GetUpdatesSource GetUpdatesFromNudgeSource( | 135 GetUpdatesCallerInfo::GetUpdatesSource GetUpdatesFromNudgeSource( |
149 NudgeSource source) { | 136 NudgeSource source) { |
150 switch (source) { | 137 switch (source) { |
151 case NUDGE_SOURCE_NOTIFICATION: | 138 case NUDGE_SOURCE_NOTIFICATION: |
152 return GetUpdatesCallerInfo::NOTIFICATION; | 139 return GetUpdatesCallerInfo::NOTIFICATION; |
153 case NUDGE_SOURCE_LOCAL: | 140 case NUDGE_SOURCE_LOCAL: |
154 return GetUpdatesCallerInfo::LOCAL; | 141 return GetUpdatesCallerInfo::LOCAL; |
155 case NUDGE_SOURCE_CONTINUATION: | 142 case NUDGE_SOURCE_CONTINUATION: |
156 return GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION; | 143 return GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION; |
157 case NUDGE_SOURCE_LOCAL_REFRESH: | 144 case NUDGE_SOURCE_LOCAL_REFRESH: |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 case GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE: | 177 case GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE: |
191 return true; | 178 return true; |
192 default: | 179 default: |
193 return false; | 180 return false; |
194 } | 181 } |
195 } | 182 } |
196 | 183 |
197 } // namespace | 184 } // namespace |
198 | 185 |
199 SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name, | 186 SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name, |
| 187 BackoffDelayProvider* delay_provider, |
200 sessions::SyncSessionContext* context, | 188 sessions::SyncSessionContext* context, |
201 Syncer* syncer) | 189 Syncer* syncer) |
202 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 190 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
203 weak_ptr_factory_for_weak_handle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 191 weak_ptr_factory_for_weak_handle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
204 weak_handle_this_(MakeWeakHandle( | 192 weak_handle_this_(MakeWeakHandle( |
205 weak_ptr_factory_for_weak_handle_.GetWeakPtr())), | 193 weak_ptr_factory_for_weak_handle_.GetWeakPtr())), |
206 name_(name), | 194 name_(name), |
207 sync_loop_(MessageLoop::current()), | 195 sync_loop_(MessageLoop::current()), |
208 started_(false), | 196 started_(false), |
209 syncer_short_poll_interval_seconds_( | 197 syncer_short_poll_interval_seconds_( |
210 TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)), | 198 TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)), |
211 syncer_long_poll_interval_seconds_( | 199 syncer_long_poll_interval_seconds_( |
212 TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)), | 200 TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)), |
213 sessions_commit_delay_( | 201 sessions_commit_delay_( |
214 TimeDelta::FromSeconds(kDefaultSessionsCommitDelaySeconds)), | 202 TimeDelta::FromSeconds(kDefaultSessionsCommitDelaySeconds)), |
215 mode_(NORMAL_MODE), | 203 mode_(NORMAL_MODE), |
216 // Start with assuming everything is fine with the connection. | 204 // Start with assuming everything is fine with the connection. |
217 // At the end of the sync cycle we would have the correct status. | 205 // At the end of the sync cycle we would have the correct status. |
218 connection_code_(HttpResponse::SERVER_CONNECTION_OK), | 206 connection_code_(HttpResponse::SERVER_CONNECTION_OK), |
219 delay_provider_(new DelayProvider()), | 207 delay_provider_(delay_provider), |
220 syncer_(syncer), | 208 syncer_(syncer), |
221 session_context_(context) { | 209 session_context_(context) { |
222 DCHECK(sync_loop_); | 210 DCHECK(sync_loop_); |
223 } | 211 } |
224 | 212 |
225 SyncSchedulerImpl::~SyncSchedulerImpl() { | 213 SyncSchedulerImpl::~SyncSchedulerImpl() { |
226 DCHECK_EQ(MessageLoop::current(), sync_loop_); | 214 DCHECK_EQ(MessageLoop::current(), sync_loop_); |
227 StopImpl(base::Closure()); | 215 StopImpl(base::Closure()); |
228 } | 216 } |
229 | 217 |
(...skipping 666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
896 &SyncSchedulerImpl::PollTimerCallback); | 884 &SyncSchedulerImpl::PollTimerCallback); |
897 } | 885 } |
898 | 886 |
899 void SyncSchedulerImpl::RestartWaiting() { | 887 void SyncSchedulerImpl::RestartWaiting() { |
900 CHECK(wait_interval_.get()); | 888 CHECK(wait_interval_.get()); |
901 wait_interval_->timer.Stop(); | 889 wait_interval_->timer.Stop(); |
902 wait_interval_->timer.Start(FROM_HERE, wait_interval_->length, | 890 wait_interval_->timer.Start(FROM_HERE, wait_interval_->length, |
903 this, &SyncSchedulerImpl::DoCanaryJob); | 891 this, &SyncSchedulerImpl::DoCanaryJob); |
904 } | 892 } |
905 | 893 |
906 namespace { | |
907 // TODO(tim): Move this function to syncer_error.h. | |
908 // Return true if the command in question was attempted and did not complete | |
909 // successfully. | |
910 bool IsError(SyncerError error) { | |
911 return error != UNSET && error != SYNCER_OK; | |
912 } | |
913 } // namespace | |
914 | |
915 // static | |
916 void SyncSchedulerImpl::ForceShortInitialBackoffRetry() { | |
917 g_force_short_retry = true; | |
918 } | |
919 | |
920 TimeDelta SyncSchedulerImpl::GetInitialBackoffDelay( | |
921 const sessions::ModelNeutralState& state) const { | |
922 // TODO(tim): Remove this, provide integration-test-only mechanism | |
923 // for override. | |
924 if (g_force_short_retry) { | |
925 return TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds); | |
926 } | |
927 | |
928 if (IsError(state.last_get_key_result)) | |
929 return TimeDelta::FromSeconds(kInitialBackoffRetrySeconds); | |
930 // Note: If we received a MIGRATION_DONE on download updates, then commit | |
931 // should not have taken place. Moreover, if we receive a MIGRATION_DONE | |
932 // on commit, it means that download updates succeeded. Therefore, we only | |
933 // need to check if either code is equal to SERVER_RETURN_MIGRATION_DONE, | |
934 // and not if there were any more serious errors requiring the long retry. | |
935 if (state.last_download_updates_result == SERVER_RETURN_MIGRATION_DONE || | |
936 state.commit_result == SERVER_RETURN_MIGRATION_DONE) { | |
937 return TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds); | |
938 } | |
939 | |
940 return TimeDelta::FromSeconds(kInitialBackoffRetrySeconds); | |
941 } | |
942 | |
943 void SyncSchedulerImpl::HandleContinuationError( | 894 void SyncSchedulerImpl::HandleContinuationError( |
944 const SyncSessionJob& old_job) { | 895 const SyncSessionJob& old_job) { |
945 DCHECK_EQ(MessageLoop::current(), sync_loop_); | 896 DCHECK_EQ(MessageLoop::current(), sync_loop_); |
946 if (DCHECK_IS_ON()) { | 897 if (DCHECK_IS_ON()) { |
947 if (IsBackingOff()) { | 898 if (IsBackingOff()) { |
948 DCHECK(wait_interval_->timer.IsRunning() || old_job.is_canary_job); | 899 DCHECK(wait_interval_->timer.IsRunning() || old_job.is_canary_job); |
949 } | 900 } |
950 } | 901 } |
951 | 902 |
952 TimeDelta length = delay_provider_->GetDelay( | 903 TimeDelta length = delay_provider_->GetDelay( |
953 IsBackingOff() ? wait_interval_->length : | 904 IsBackingOff() ? wait_interval_->length : |
954 GetInitialBackoffDelay( | 905 delay_provider_->GetInitialDelay( |
955 old_job.session->status_controller().model_neutral_state())); | 906 old_job.session->status_controller().model_neutral_state())); |
956 | 907 |
957 SDVLOG(2) << "In handle continuation error with " | 908 SDVLOG(2) << "In handle continuation error with " |
958 << SyncSessionJob::GetPurposeString(old_job.purpose) | 909 << SyncSessionJob::GetPurposeString(old_job.purpose) |
959 << " job. The time delta(ms) is " | 910 << " job. The time delta(ms) is " |
960 << length.InMilliseconds(); | 911 << length.InMilliseconds(); |
961 | 912 |
962 // This will reset the had_nudge variable as well. | 913 // This will reset the had_nudge variable as well. |
963 wait_interval_.reset(new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, | 914 wait_interval_.reset(new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, |
964 length)); | 915 length)); |
(...skipping 12 matching lines...) Expand all Loading... |
977 // We are not in configuration mode. So wait_interval's pending job | 928 // We are not in configuration mode. So wait_interval's pending job |
978 // should be null. | 929 // should be null. |
979 DCHECK(wait_interval_->pending_configure_job.get() == NULL); | 930 DCHECK(wait_interval_->pending_configure_job.get() == NULL); |
980 | 931 |
981 // TODO(lipalani) - handle clear user data. | 932 // TODO(lipalani) - handle clear user data. |
982 InitOrCoalescePendingJob(old_job); | 933 InitOrCoalescePendingJob(old_job); |
983 } | 934 } |
984 RestartWaiting(); | 935 RestartWaiting(); |
985 } | 936 } |
986 | 937 |
987 // static | |
988 TimeDelta SyncSchedulerImpl::GetRecommendedDelay(const TimeDelta& last_delay) { | |
989 if (last_delay.InSeconds() >= kMaxBackoffSeconds) | |
990 return TimeDelta::FromSeconds(kMaxBackoffSeconds); | |
991 | |
992 // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2 | |
993 int64 backoff_s = | |
994 std::max(static_cast<int64>(1), | |
995 last_delay.InSeconds() * kBackoffRandomizationFactor); | |
996 | |
997 // Flip a coin to randomize backoff interval by +/- 50%. | |
998 int rand_sign = base::RandInt(0, 1) * 2 - 1; | |
999 | |
1000 // Truncation is adequate for rounding here. | |
1001 backoff_s = backoff_s + | |
1002 (rand_sign * (last_delay.InSeconds() / kBackoffRandomizationFactor)); | |
1003 | |
1004 // Cap the backoff interval. | |
1005 backoff_s = std::max(static_cast<int64>(1), | |
1006 std::min(backoff_s, kMaxBackoffSeconds)); | |
1007 | |
1008 return TimeDelta::FromSeconds(backoff_s); | |
1009 } | |
1010 | |
1011 void SyncSchedulerImpl::RequestStop(const base::Closure& callback) { | 938 void SyncSchedulerImpl::RequestStop(const base::Closure& callback) { |
1012 syncer_->RequestEarlyExit(); // Safe to call from any thread. | 939 syncer_->RequestEarlyExit(); // Safe to call from any thread. |
1013 DCHECK(weak_handle_this_.IsInitialized()); | 940 DCHECK(weak_handle_this_.IsInitialized()); |
1014 SDVLOG(3) << "Posting StopImpl"; | 941 SDVLOG(3) << "Posting StopImpl"; |
1015 weak_handle_this_.Call(FROM_HERE, | 942 weak_handle_this_.Call(FROM_HERE, |
1016 &SyncSchedulerImpl::StopImpl, | 943 &SyncSchedulerImpl::StopImpl, |
1017 callback); | 944 callback); |
1018 } | 945 } |
1019 | 946 |
1020 void SyncSchedulerImpl::StopImpl(const base::Closure& callback) { | 947 void SyncSchedulerImpl::StopImpl(const base::Closure& callback) { |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1192 | 1119 |
1193 #undef SDVLOG_LOC | 1120 #undef SDVLOG_LOC |
1194 | 1121 |
1195 #undef SDVLOG | 1122 #undef SDVLOG |
1196 | 1123 |
1197 #undef SLOG | 1124 #undef SLOG |
1198 | 1125 |
1199 #undef ENUM_CASE | 1126 #undef ENUM_CASE |
1200 | 1127 |
1201 } // namespace syncer | 1128 } // namespace syncer |
OLD | NEW |