blob: c5629ba59376ccc83ef2eeb6d11fb0dc3f415d0b [file] [log] [blame]
[email protected]6d2dc982012-07-19 22:19:181// 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.
4
5#include "sync/engine/sync_scheduler_impl.h"
6
7#include <algorithm>
8#include <cstring>
9
[email protected]d9f025b2012-09-07 12:57:1410#include "base/auto_reset.h"
[email protected]6d2dc982012-07-19 22:19:1811#include "base/bind.h"
[email protected]eeac662c2012-10-30 20:31:1812#include "base/bind_helpers.h"
[email protected]6d2dc982012-07-19 22:19:1813#include "base/compiler_specific.h"
14#include "base/location.h"
15#include "base/logging.h"
[email protected]a76295972013-07-18 00:42:3216#include "base/message_loop/message_loop.h"
[email protected]f706df52012-08-15 06:18:3617#include "sync/engine/backoff_delay_provider.h"
[email protected]6d2dc982012-07-19 22:19:1818#include "sync/engine/syncer.h"
[email protected]ba857402013-09-03 21:20:5419#include "sync/notifier/object_id_invalidation_map.h"
[email protected]6d2dc982012-07-19 22:19:1820#include "sync/protocol/proto_enum_conversions.h"
21#include "sync/protocol/sync.pb.h"
22#include "sync/util/data_type_histogram.h"
23#include "sync/util/logging.h"
24
25using base::TimeDelta;
26using base::TimeTicks;
27
28namespace syncer {
29
30using sessions::SyncSession;
31using sessions::SyncSessionSnapshot;
[email protected]6d2dc982012-07-19 22:19:1832using sync_pb::GetUpdatesCallerInfo;
33
34namespace {
[email protected]4494c5d2012-08-13 01:07:4235
[email protected]d45f0d92012-07-20 17:25:4136bool ShouldRequestEarlyExit(const SyncProtocolError& error) {
[email protected]6d2dc982012-07-19 22:19:1837 switch (error.error_type) {
[email protected]d45f0d92012-07-20 17:25:4138 case SYNC_SUCCESS:
39 case MIGRATION_DONE:
40 case THROTTLED:
41 case TRANSIENT_ERROR:
[email protected]6d2dc982012-07-19 22:19:1842 return false;
[email protected]d45f0d92012-07-20 17:25:4143 case NOT_MY_BIRTHDAY:
44 case CLEAR_PENDING:
[email protected]5a496e52013-05-29 20:44:5745 case DISABLED_BY_ADMIN:
[email protected]484fff52014-06-11 06:34:0346 case USER_ROLLBACK:
[email protected]6d2dc982012-07-19 22:19:1847 // If we send terminate sync early then |sync_cycle_ended| notification
48 // would not be sent. If there were no actions then |ACTIONABLE_ERROR|
49 // notification wouldnt be sent either. Then the UI layer would be left
50 // waiting forever. So assert we would send something.
[email protected]d45f0d92012-07-20 17:25:4151 DCHECK_NE(error.action, UNKNOWN_ACTION);
[email protected]6d2dc982012-07-19 22:19:1852 return true;
[email protected]d45f0d92012-07-20 17:25:4153 case INVALID_CREDENTIAL:
[email protected]6d2dc982012-07-19 22:19:1854 // The notification for this is handled by PostAndProcessHeaders|.
55 // Server does no have to send any action for this.
56 return true;
57 // Make the default a NOTREACHED. So if a new error is introduced we
58 // think about its expected functionality.
59 default:
60 NOTREACHED();
61 return false;
62 }
63}
64
65bool IsActionableError(
[email protected]d45f0d92012-07-20 17:25:4166 const SyncProtocolError& error) {
67 return (error.action != UNKNOWN_ACTION);
[email protected]6d2dc982012-07-19 22:19:1868}
69} // namespace
70
71ConfigurationParams::ConfigurationParams()
[email protected]310512c2012-07-31 19:44:2572 : source(GetUpdatesCallerInfo::UNKNOWN) {}
[email protected]6d2dc982012-07-19 22:19:1873ConfigurationParams::ConfigurationParams(
74 const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& source,
[email protected]bb7d12a2012-09-01 03:50:2975 ModelTypeSet types_to_download,
[email protected]d45f0d92012-07-20 17:25:4176 const ModelSafeRoutingInfo& routing_info,
[email protected]33160442013-11-17 17:44:4777 const base::Closure& ready_task,
78 const base::Closure& retry_task)
[email protected]6d2dc982012-07-19 22:19:1879 : source(source),
80 types_to_download(types_to_download),
81 routing_info(routing_info),
[email protected]33160442013-11-17 17:44:4782 ready_task(ready_task),
83 retry_task(retry_task) {
[email protected]6d2dc982012-07-19 22:19:1884 DCHECK(!ready_task.is_null());
[email protected]33160442013-11-17 17:44:4785 DCHECK(!retry_task.is_null());
[email protected]6d2dc982012-07-19 22:19:1886}
87ConfigurationParams::~ConfigurationParams() {}
88
[email protected]6d2dc982012-07-19 22:19:1889SyncSchedulerImpl::WaitInterval::WaitInterval()
[email protected]622618f2013-04-06 00:22:2890 : mode(UNKNOWN) {}
[email protected]eeac662c2012-10-30 20:31:1891
92SyncSchedulerImpl::WaitInterval::WaitInterval(Mode mode, TimeDelta length)
[email protected]622618f2013-04-06 00:22:2893 : mode(mode), length(length) {}
[email protected]6d2dc982012-07-19 22:19:1894
95SyncSchedulerImpl::WaitInterval::~WaitInterval() {}
96
97#define ENUM_CASE(x) case x: return #x; break;
98
99const char* SyncSchedulerImpl::WaitInterval::GetModeString(Mode mode) {
100 switch (mode) {
101 ENUM_CASE(UNKNOWN);
102 ENUM_CASE(EXPONENTIAL_BACKOFF);
103 ENUM_CASE(THROTTLED);
104 }
105 NOTREACHED();
106 return "";
107}
108
[email protected]6d2dc982012-07-19 22:19:18109GetUpdatesCallerInfo::GetUpdatesSource GetUpdatesFromNudgeSource(
110 NudgeSource source) {
111 switch (source) {
112 case NUDGE_SOURCE_NOTIFICATION:
113 return GetUpdatesCallerInfo::NOTIFICATION;
114 case NUDGE_SOURCE_LOCAL:
115 return GetUpdatesCallerInfo::LOCAL;
[email protected]6d2dc982012-07-19 22:19:18116 case NUDGE_SOURCE_LOCAL_REFRESH:
117 return GetUpdatesCallerInfo::DATATYPE_REFRESH;
118 case NUDGE_SOURCE_UNKNOWN:
119 return GetUpdatesCallerInfo::UNKNOWN;
120 default:
121 NOTREACHED();
122 return GetUpdatesCallerInfo::UNKNOWN;
123 }
124}
125
[email protected]6d2dc982012-07-19 22:19:18126// Helper macros to log with the syncer thread name; useful when there
127// are multiple syncer threads involved.
128
129#define SLOG(severity) LOG(severity) << name_ << ": "
130
131#define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
132
133#define SDVLOG_LOC(from_here, verbose_level) \
134 DVLOG_LOC(from_here, verbose_level) << name_ << ": "
135
136namespace {
137
138const int kDefaultSessionsCommitDelaySeconds = 10;
139
140bool IsConfigRelatedUpdateSourceValue(
141 GetUpdatesCallerInfo::GetUpdatesSource source) {
142 switch (source) {
143 case GetUpdatesCallerInfo::RECONFIGURATION:
144 case GetUpdatesCallerInfo::MIGRATION:
145 case GetUpdatesCallerInfo::NEW_CLIENT:
146 case GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE:
147 return true;
148 default:
149 return false;
150 }
151}
152
153} // namespace
154
155SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name,
[email protected]f706df52012-08-15 06:18:36156 BackoffDelayProvider* delay_provider,
[email protected]6d2dc982012-07-19 22:19:18157 sessions::SyncSessionContext* context,
158 Syncer* syncer)
[email protected]37d5b3472013-10-10 16:20:36159 : name_(name),
[email protected]6d2dc982012-07-19 22:19:18160 started_(false),
161 syncer_short_poll_interval_seconds_(
162 TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)),
163 syncer_long_poll_interval_seconds_(
164 TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)),
165 sessions_commit_delay_(
166 TimeDelta::FromSeconds(kDefaultSessionsCommitDelaySeconds)),
167 mode_(NORMAL_MODE),
[email protected]f706df52012-08-15 06:18:36168 delay_provider_(delay_provider),
[email protected]6d2dc982012-07-19 22:19:18169 syncer_(syncer),
[email protected]d9f025b2012-09-07 12:57:14170 session_context_(context),
[email protected]a43e34bd2013-07-13 15:04:42171 no_scheduling_allowed_(false),
[email protected]37d5b3472013-10-10 16:20:36172 do_poll_after_credentials_updated_(false),
[email protected]fd405e42014-01-04 03:45:53173 next_sync_session_job_priority_(NORMAL_PRIORITY),
[email protected]37d5b3472013-10-10 16:20:36174 weak_ptr_factory_(this),
175 weak_ptr_factory_for_weak_handle_(this) {
176 weak_handle_this_ = MakeWeakHandle(
177 weak_ptr_factory_for_weak_handle_.GetWeakPtr());
[email protected]6d2dc982012-07-19 22:19:18178}
179
180SyncSchedulerImpl::~SyncSchedulerImpl() {
[email protected]622618f2013-04-06 00:22:28181 DCHECK(CalledOnValidThread());
[email protected]ea29851b2013-09-19 01:17:02182 Stop();
[email protected]6d2dc982012-07-19 22:19:18183}
184
185void SyncSchedulerImpl::OnCredentialsUpdated() {
[email protected]622618f2013-04-06 00:22:28186 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18187
[email protected]5fffc502013-02-08 02:29:22188 if (HttpResponse::SYNC_AUTH_ERROR ==
189 session_context_->connection_manager()->server_status()) {
[email protected]6d2dc982012-07-19 22:19:18190 OnServerConnectionErrorFixed();
191 }
192}
193
194void SyncSchedulerImpl::OnConnectionStatusChange() {
[email protected]7e31df8f2013-03-05 04:14:53195 if (HttpResponse::CONNECTION_UNAVAILABLE ==
196 session_context_->connection_manager()->server_status()) {
[email protected]6d2dc982012-07-19 22:19:18197 // Optimistically assume that the connection is fixed and try
198 // connecting.
199 OnServerConnectionErrorFixed();
200 }
201}
202
203void SyncSchedulerImpl::OnServerConnectionErrorFixed() {
[email protected]eeac662c2012-10-30 20:31:18204 // There could be a pending nudge or configuration job in several cases:
205 //
206 // 1. We're in exponential backoff.
207 // 2. We're silenced / throttled.
208 // 3. A nudge was saved previously due to not having a valid auth token.
209 // 4. A nudge was scheduled + saved while in configuration mode.
210 //
211 // In all cases except (2), we want to retry contacting the server. We
[email protected]e0428b12013-12-16 18:52:43212 // call TryCanaryJob to achieve this, and note that nothing -- not even a
[email protected]eeac662c2012-10-30 20:31:18213 // canary job -- can bypass a THROTTLED WaitInterval. The only thing that
214 // has the authority to do that is the Unthrottle timer.
[email protected]622618f2013-04-06 00:22:28215 TryCanaryJob();
[email protected]6d2dc982012-07-19 22:19:18216}
217
[email protected]6d2dc982012-07-19 22:19:18218void SyncSchedulerImpl::Start(Mode mode) {
[email protected]622618f2013-04-06 00:22:28219 DCHECK(CalledOnValidThread());
[email protected]21cb28a2013-05-07 03:52:45220 std::string thread_name = base::MessageLoop::current()->thread_name();
[email protected]6d2dc982012-07-19 22:19:18221 if (thread_name.empty())
222 thread_name = "<Main thread>";
223 SDVLOG(2) << "Start called from thread "
224 << thread_name << " with mode " << GetModeString(mode);
225 if (!started_) {
226 started_ = true;
227 SendInitialSnapshot();
228 }
229
230 DCHECK(!session_context_->account_name().empty());
231 DCHECK(syncer_.get());
232 Mode old_mode = mode_;
233 mode_ = mode;
[email protected]0248d922013-04-18 04:52:10234 AdjustPolling(UPDATE_INTERVAL); // Will kick start poll timer if needed.
[email protected]6d2dc982012-07-19 22:19:18235
[email protected]3a489722014-02-03 23:35:59236 if (old_mode != mode_ && mode_ == NORMAL_MODE) {
[email protected]622618f2013-04-06 00:22:28237 // We just got back to normal mode. Let's try to run the work that was
238 // queued up while we were configuring.
[email protected]3a489722014-02-03 23:35:59239
240 // Update our current time before checking IsRetryRequired().
241 nudge_tracker_.SetSyncCycleStartTime(base::TimeTicks::Now());
[email protected]eb540e42014-03-04 04:19:57242 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(NORMAL_PRIORITY)) {
[email protected]3a489722014-02-03 23:35:59243 TrySyncSessionJob();
244 }
[email protected]6d2dc982012-07-19 22:19:18245 }
246}
247
[email protected]de84cfd2013-07-03 03:44:20248ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnthrottledTypes() {
[email protected]0662c3e2014-03-20 20:21:27249 ModelTypeSet enabled_types = session_context_->GetEnabledTypes();
[email protected]c9daa4302014-02-12 08:45:16250 ModelTypeSet enabled_protocol_types =
251 Intersection(ProtocolTypes(), enabled_types);
[email protected]a9575482013-12-04 02:51:36252 ModelTypeSet throttled_types = nudge_tracker_.GetThrottledTypes();
[email protected]c9daa4302014-02-12 08:45:16253 return Difference(enabled_protocol_types, throttled_types);
[email protected]de84cfd2013-07-03 03:44:20254}
255
[email protected]6d2dc982012-07-19 22:19:18256void SyncSchedulerImpl::SendInitialSnapshot() {
[email protected]622618f2013-04-06 00:22:28257 DCHECK(CalledOnValidThread());
[email protected]0a6e9612013-08-03 01:41:42258 scoped_ptr<SyncSession> dummy(SyncSession::Build(session_context_, this));
[email protected]325c3502014-02-11 13:56:43259 SyncCycleEvent event(SyncCycleEvent::STATUS_CHANGED);
[email protected]6d2dc982012-07-19 22:19:18260 event.snapshot = dummy->TakeSnapshot();
[email protected]325c3502014-02-11 13:56:43261 FOR_EACH_OBSERVER(SyncEngineEventListener,
262 *session_context_->listeners(),
263 OnSyncCycleEvent(event));
[email protected]6d2dc982012-07-19 22:19:18264}
265
266namespace {
267
[email protected]cb0243522012-09-20 21:53:34268// Helper to extract the routing info corresponding to types in
[email protected]79dc04cce2013-02-15 17:59:48269// |types_to_download| from |current_routes|.
[email protected]6d2dc982012-07-19 22:19:18270void BuildModelSafeParams(
[email protected]bb7d12a2012-09-01 03:50:29271 ModelTypeSet types_to_download,
[email protected]6d2dc982012-07-19 22:19:18272 const ModelSafeRoutingInfo& current_routes,
[email protected]cb0243522012-09-20 21:53:34273 ModelSafeRoutingInfo* result_routes) {
[email protected]6d2dc982012-07-19 22:19:18274 for (ModelTypeSet::Iterator iter = types_to_download.First(); iter.Good();
275 iter.Inc()) {
[email protected]d45f0d92012-07-20 17:25:41276 ModelType type = iter.Get();
[email protected]6d2dc982012-07-19 22:19:18277 ModelSafeRoutingInfo::const_iterator route = current_routes.find(type);
278 DCHECK(route != current_routes.end());
279 ModelSafeGroup group = route->second;
280 (*result_routes)[type] = group;
[email protected]6d2dc982012-07-19 22:19:18281 }
282}
283
284} // namespace.
285
[email protected]33160442013-11-17 17:44:47286void SyncSchedulerImpl::ScheduleConfiguration(
[email protected]6d2dc982012-07-19 22:19:18287 const ConfigurationParams& params) {
[email protected]622618f2013-04-06 00:22:28288 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18289 DCHECK(IsConfigRelatedUpdateSourceValue(params.source));
290 DCHECK_EQ(CONFIGURATION_MODE, mode_);
291 DCHECK(!params.ready_task.is_null());
[email protected]ecf01bd2013-01-10 00:42:42292 CHECK(started_) << "Scheduler must be running to configure.";
[email protected]6d2dc982012-07-19 22:19:18293 SDVLOG(2) << "Reconfiguring syncer.";
294
295 // Only one configuration is allowed at a time. Verify we're not waiting
296 // for a pending configure job.
[email protected]0248d922013-04-18 04:52:10297 DCHECK(!pending_configure_params_);
[email protected]6d2dc982012-07-19 22:19:18298
[email protected]d45f0d92012-07-20 17:25:41299 ModelSafeRoutingInfo restricted_routes;
[email protected]6d2dc982012-07-19 22:19:18300 BuildModelSafeParams(params.types_to_download,
301 params.routing_info,
[email protected]cb0243522012-09-20 21:53:34302 &restricted_routes);
[email protected]2fdf61992014-01-17 23:21:59303 session_context_->SetRoutingInfo(restricted_routes);
[email protected]6d2dc982012-07-19 22:19:18304
[email protected]6d2dc982012-07-19 22:19:18305 // Only reconfigure if we have types to download.
306 if (!params.types_to_download.Empty()) {
[email protected]0248d922013-04-18 04:52:10307 pending_configure_params_.reset(new ConfigurationParams(params));
[email protected]fd405e42014-01-04 03:45:53308 TrySyncSessionJob();
[email protected]6d2dc982012-07-19 22:19:18309 } else {
310 SDVLOG(2) << "No change in routing info, calling ready task directly.";
311 params.ready_task.Run();
312 }
[email protected]6d2dc982012-07-19 22:19:18313}
314
[email protected]0248d922013-04-18 04:52:10315bool SyncSchedulerImpl::CanRunJobNow(JobPriority priority) {
[email protected]622618f2013-04-06 00:22:28316 DCHECK(CalledOnValidThread());
[email protected]0248d922013-04-18 04:52:10317 if (wait_interval_ && wait_interval_->mode == WaitInterval::THROTTLED) {
318 SDVLOG(1) << "Unable to run a job because we're throttled.";
319 return false;
[email protected]6d2dc982012-07-19 22:19:18320 }
[email protected]0248d922013-04-18 04:52:10321
322 if (wait_interval_
323 && wait_interval_->mode == WaitInterval::EXPONENTIAL_BACKOFF
324 && priority != CANARY_PRIORITY) {
325 SDVLOG(1) << "Unable to run a job because we're backing off.";
326 return false;
327 }
328
329 if (session_context_->connection_manager()->HasInvalidAuthToken()) {
330 SDVLOG(1) << "Unable to run a job because we have no valid auth token.";
331 return false;
332 }
333
334 return true;
[email protected]6d2dc982012-07-19 22:19:18335}
336
[email protected]0248d922013-04-18 04:52:10337bool SyncSchedulerImpl::CanRunNudgeJobNow(JobPriority priority) {
[email protected]622618f2013-04-06 00:22:28338 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18339
[email protected]0248d922013-04-18 04:52:10340 if (!CanRunJobNow(priority)) {
341 SDVLOG(1) << "Unable to run a nudge job right now";
342 return false;
343 }
[email protected]93afb3b2013-03-20 21:01:27344
[email protected]0662c3e2014-03-20 20:21:27345 const ModelTypeSet enabled_types = session_context_->GetEnabledTypes();
[email protected]d9d8f9f2013-06-14 19:45:30346 if (nudge_tracker_.GetThrottledTypes().HasAll(enabled_types)) {
347 SDVLOG(1) << "Not running a nudge because we're fully type throttled.";
[email protected]0248d922013-04-18 04:52:10348 return false;
[email protected]6d2dc982012-07-19 22:19:18349 }
350
[email protected]6d2dc982012-07-19 22:19:18351 if (mode_ == CONFIGURATION_MODE) {
[email protected]0248d922013-04-18 04:52:10352 SDVLOG(1) << "Not running nudge because we're in configuration mode.";
353 return false;
[email protected]6d2dc982012-07-19 22:19:18354 }
355
[email protected]0248d922013-04-18 04:52:10356 return true;
[email protected]6d2dc982012-07-19 22:19:18357}
358
[email protected]3e299072013-05-09 05:51:05359void SyncSchedulerImpl::ScheduleLocalNudge(
[email protected]eeac662c2012-10-30 20:31:18360 const TimeDelta& desired_delay,
[email protected]3e299072013-05-09 05:51:05361 ModelTypeSet types,
[email protected]6d2dc982012-07-19 22:19:18362 const tracked_objects::Location& nudge_location) {
[email protected]622618f2013-04-06 00:22:28363 DCHECK(CalledOnValidThread());
[email protected]3e299072013-05-09 05:51:05364 DCHECK(!types.Empty());
[email protected]6d2dc982012-07-19 22:19:18365
[email protected]3e299072013-05-09 05:51:05366 SDVLOG_LOC(nudge_location, 2)
367 << "Scheduling sync because of local change to "
368 << ModelTypeSetToString(types);
369 UpdateNudgeTimeRecords(types);
370 nudge_tracker_.RecordLocalChange(types);
371 ScheduleNudgeImpl(desired_delay, nudge_location);
[email protected]6d2dc982012-07-19 22:19:18372}
373
[email protected]3e299072013-05-09 05:51:05374void SyncSchedulerImpl::ScheduleLocalRefreshRequest(
[email protected]eeac662c2012-10-30 20:31:18375 const TimeDelta& desired_delay,
[email protected]3e299072013-05-09 05:51:05376 ModelTypeSet types,
[email protected]6d2dc982012-07-19 22:19:18377 const tracked_objects::Location& nudge_location) {
[email protected]622618f2013-04-06 00:22:28378 DCHECK(CalledOnValidThread());
[email protected]3e299072013-05-09 05:51:05379 DCHECK(!types.Empty());
380
[email protected]6d2dc982012-07-19 22:19:18381 SDVLOG_LOC(nudge_location, 2)
[email protected]580cda62013-05-16 23:37:30382 << "Scheduling sync because of local refresh request for "
[email protected]3e299072013-05-09 05:51:05383 << ModelTypeSetToString(types);
384 nudge_tracker_.RecordLocalRefreshRequest(types);
385 ScheduleNudgeImpl(desired_delay, nudge_location);
386}
387
388void SyncSchedulerImpl::ScheduleInvalidationNudge(
389 const TimeDelta& desired_delay,
[email protected]51e6efd2014-07-08 23:38:21390 syncer::ModelType model_type,
391 scoped_ptr<InvalidationInterface> invalidation,
[email protected]3e299072013-05-09 05:51:05392 const tracked_objects::Location& nudge_location) {
393 DCHECK(CalledOnValidThread());
[email protected]3e299072013-05-09 05:51:05394
395 SDVLOG_LOC(nudge_location, 2)
396 << "Scheduling sync because we received invalidation for "
[email protected]51e6efd2014-07-08 23:38:21397 << ModelTypeToString(model_type);
398 nudge_tracker_.RecordRemoteInvalidation(model_type, invalidation.Pass());
[email protected]3e299072013-05-09 05:51:05399 ScheduleNudgeImpl(desired_delay, nudge_location);
[email protected]6d2dc982012-07-19 22:19:18400}
401
[email protected]93afb3b2013-03-20 21:01:27402// TODO(zea): Consider adding separate throttling/backoff for datatype
403// refresh requests.
[email protected]6d2dc982012-07-19 22:19:18404void SyncSchedulerImpl::ScheduleNudgeImpl(
405 const TimeDelta& delay,
[email protected]eeac662c2012-10-30 20:31:18406 const tracked_objects::Location& nudge_location) {
[email protected]622618f2013-04-06 00:22:28407 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18408
[email protected]93afb3b2013-03-20 21:01:27409 if (no_scheduling_allowed_) {
410 NOTREACHED() << "Illegal to schedule job while session in progress.";
411 return;
412 }
413
[email protected]ecf01bd2013-01-10 00:42:42414 if (!started_) {
415 SDVLOG_LOC(nudge_location, 2)
416 << "Dropping nudge, scheduler is not running.";
417 return;
418 }
419
[email protected]6d2dc982012-07-19 22:19:18420 SDVLOG_LOC(nudge_location, 2)
421 << "In ScheduleNudgeImpl with delay "
[email protected]3e299072013-05-09 05:51:05422 << delay.InMilliseconds() << " ms";
[email protected]0248d922013-04-18 04:52:10423
424 if (!CanRunNudgeJobNow(NORMAL_PRIORITY))
425 return;
426
[email protected]0248d922013-04-18 04:52:10427 TimeTicks incoming_run_time = TimeTicks::Now() + delay;
428 if (!scheduled_nudge_time_.is_null() &&
429 (scheduled_nudge_time_ < incoming_run_time)) {
430 // Old job arrives sooner than this one. Don't reschedule it.
[email protected]622618f2013-04-06 00:22:28431 return;
432 }
433
[email protected]0248d922013-04-18 04:52:10434 // Either there is no existing nudge in flight or the incoming nudge should be
435 // made to arrive first (preempt) the existing nudge. We reschedule in either
436 // case.
[email protected]93afb3b2013-03-20 21:01:27437 SDVLOG_LOC(nudge_location, 2)
438 << "Scheduling a nudge with "
[email protected]0248d922013-04-18 04:52:10439 << delay.InMilliseconds() << " ms delay";
440 scheduled_nudge_time_ = incoming_run_time;
441 pending_wakeup_timer_.Start(
442 nudge_location,
443 delay,
[email protected]d9d8f9f2013-06-14 19:45:30444 base::Bind(&SyncSchedulerImpl::PerformDelayedNudge,
445 weak_ptr_factory_.GetWeakPtr()));
[email protected]6d2dc982012-07-19 22:19:18446}
447
448const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) {
449 switch (mode) {
450 ENUM_CASE(CONFIGURATION_MODE);
451 ENUM_CASE(NORMAL_MODE);
452 }
453 return "";
454}
455
[email protected]0248d922013-04-18 04:52:10456void SyncSchedulerImpl::DoNudgeSyncSessionJob(JobPriority priority) {
[email protected]622618f2013-04-06 00:22:28457 DCHECK(CalledOnValidThread());
[email protected]d9d8f9f2013-06-14 19:45:30458 DCHECK(CanRunNudgeJobNow(priority));
[email protected]0248d922013-04-18 04:52:10459
[email protected]a9575482013-12-04 02:51:36460 DVLOG(2) << "Will run normal mode sync cycle with types "
[email protected]0662c3e2014-03-20 20:21:27461 << ModelTypeSetToString(session_context_->GetEnabledTypes());
[email protected]0a6e9612013-08-03 01:41:42462 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
[email protected]de84cfd2013-07-03 03:44:20463 bool premature_exit = !syncer_->NormalSyncShare(
464 GetEnabledAndUnthrottledTypes(),
465 nudge_tracker_,
466 session.get());
[email protected]0248d922013-04-18 04:52:10467 AdjustPolling(FORCE_RESET);
[email protected]a43e34bd2013-07-13 15:04:42468 // Don't run poll job till the next time poll timer fires.
469 do_poll_after_credentials_updated_ = false;
[email protected]0248d922013-04-18 04:52:10470
471 bool success = !premature_exit
472 && !sessions::HasSyncerError(
[email protected]3e299072013-05-09 05:51:05473 session->status_controller().model_neutral_state());
[email protected]0248d922013-04-18 04:52:10474
475 if (success) {
476 // That cycle took care of any outstanding work we had.
477 SDVLOG(2) << "Nudge succeeded.";
[email protected]3a489722014-02-03 23:35:59478 nudge_tracker_.RecordSuccessfulSyncCycle();
[email protected]0248d922013-04-18 04:52:10479 scheduled_nudge_time_ = base::TimeTicks();
480
481 // If we're here, then we successfully reached the server. End all backoff.
482 wait_interval_.reset();
483 NotifyRetryTime(base::Time());
[email protected]0248d922013-04-18 04:52:10484 } else {
[email protected]3e299072013-05-09 05:51:05485 HandleFailure(session->status_controller().model_neutral_state());
[email protected]eeac662c2012-10-30 20:31:18486 }
[email protected]622618f2013-04-06 00:22:28487}
488
[email protected]33160442013-11-17 17:44:47489void SyncSchedulerImpl::DoConfigurationSyncSessionJob(JobPriority priority) {
[email protected]0248d922013-04-18 04:52:10490 DCHECK(CalledOnValidThread());
491 DCHECK_EQ(mode_, CONFIGURATION_MODE);
[email protected]33160442013-11-17 17:44:47492 DCHECK(pending_configure_params_ != NULL);
[email protected]0248d922013-04-18 04:52:10493
494 if (!CanRunJobNow(priority)) {
495 SDVLOG(2) << "Unable to run configure job right now.";
[email protected]33160442013-11-17 17:44:47496 if (!pending_configure_params_->retry_task.is_null()) {
497 pending_configure_params_->retry_task.Run();
498 pending_configure_params_->retry_task.Reset();
499 }
500 return;
[email protected]0248d922013-04-18 04:52:10501 }
502
[email protected]a9575482013-12-04 02:51:36503 SDVLOG(2) << "Will run configure SyncShare with types "
[email protected]0662c3e2014-03-20 20:21:27504 << ModelTypeSetToString(session_context_->GetEnabledTypes());
[email protected]0a6e9612013-08-03 01:41:42505 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
[email protected]de84cfd2013-07-03 03:44:20506 bool premature_exit = !syncer_->ConfigureSyncShare(
[email protected]f49ac0f62014-03-25 02:00:25507 pending_configure_params_->types_to_download,
[email protected]0a6e9612013-08-03 01:41:42508 pending_configure_params_->source,
[email protected]de84cfd2013-07-03 03:44:20509 session.get());
[email protected]0248d922013-04-18 04:52:10510 AdjustPolling(FORCE_RESET);
[email protected]a43e34bd2013-07-13 15:04:42511 // Don't run poll job till the next time poll timer fires.
512 do_poll_after_credentials_updated_ = false;
[email protected]0248d922013-04-18 04:52:10513
514 bool success = !premature_exit
515 && !sessions::HasSyncerError(
[email protected]3e299072013-05-09 05:51:05516 session->status_controller().model_neutral_state());
[email protected]0248d922013-04-18 04:52:10517
518 if (success) {
519 SDVLOG(2) << "Configure succeeded.";
520 pending_configure_params_->ready_task.Run();
521 pending_configure_params_.reset();
522
523 // If we're here, then we successfully reached the server. End all backoff.
524 wait_interval_.reset();
525 NotifyRetryTime(base::Time());
[email protected]0248d922013-04-18 04:52:10526 } else {
[email protected]3e299072013-05-09 05:51:05527 HandleFailure(session->status_controller().model_neutral_state());
[email protected]cf6a0242013-11-20 04:13:59528 // Sync cycle might receive response from server that causes scheduler to
529 // stop and draws pending_configure_params_ invalid.
530 if (started_ && !pending_configure_params_->retry_task.is_null()) {
[email protected]33160442013-11-17 17:44:47531 pending_configure_params_->retry_task.Run();
532 pending_configure_params_->retry_task.Reset();
533 }
[email protected]0248d922013-04-18 04:52:10534 }
[email protected]622618f2013-04-06 00:22:28535}
536
[email protected]0248d922013-04-18 04:52:10537void SyncSchedulerImpl::HandleFailure(
538 const sessions::ModelNeutralState& model_neutral_state) {
[email protected]d9d8f9f2013-06-14 19:45:30539 if (IsCurrentlyThrottled()) {
[email protected]0248d922013-04-18 04:52:10540 SDVLOG(2) << "Was throttled during previous sync cycle.";
541 RestartWaiting();
[email protected]580cda62013-05-16 23:37:30542 } else if (!IsBackingOff()) {
543 // Setup our backoff if this is our first such failure.
544 TimeDelta length = delay_provider_->GetDelay(
545 delay_provider_->GetInitialDelay(model_neutral_state));
546 wait_interval_.reset(
547 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length));
[email protected]0248d922013-04-18 04:52:10548 SDVLOG(2) << "Sync cycle failed. Will back off for "
549 << wait_interval_->length.InMilliseconds() << "ms.";
550 RestartWaiting();
[email protected]93afb3b2013-03-20 21:01:27551 }
[email protected]93afb3b2013-03-20 21:01:27552}
553
[email protected]622618f2013-04-06 00:22:28554void SyncSchedulerImpl::DoPollSyncSessionJob() {
[email protected]93afb3b2013-03-20 21:01:27555 base::AutoReset<bool> protector(&no_scheduling_allowed_, true);
556
[email protected]a9575482013-12-04 02:51:36557 SDVLOG(2) << "Polling with types "
[email protected]3dfc7b792014-01-14 16:17:43558 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes());
[email protected]0a6e9612013-08-03 01:41:42559 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
[email protected]de84cfd2013-07-03 03:44:20560 syncer_->PollSyncShare(
561 GetEnabledAndUnthrottledTypes(),
562 session.get());
[email protected]93afb3b2013-03-20 21:01:27563
[email protected]5c135b62013-11-18 20:54:14564 AdjustPolling(FORCE_RESET);
[email protected]93afb3b2013-03-20 21:01:27565
[email protected]d9d8f9f2013-06-14 19:45:30566 if (IsCurrentlyThrottled()) {
[email protected]0248d922013-04-18 04:52:10567 SDVLOG(2) << "Poll request got us throttled.";
568 // The OnSilencedUntil() call set up the WaitInterval for us. All we need
569 // to do is start the timer.
[email protected]622618f2013-04-06 00:22:28570 RestartWaiting();
[email protected]93afb3b2013-03-20 21:01:27571 }
[email protected]6d2dc982012-07-19 22:19:18572}
573
[email protected]3e299072013-05-09 05:51:05574void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) {
[email protected]622618f2013-04-06 00:22:28575 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18576 base::TimeTicks now = TimeTicks::Now();
[email protected]d9f025b2012-09-07 12:57:14577 // Update timing information for how often datatypes are triggering nudges.
[email protected]3e299072013-05-09 05:51:05578 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
579 base::TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()];
580 last_local_nudges_by_model_type_[iter.Get()] = now;
[email protected]d9f025b2012-09-07 12:57:14581 if (previous.is_null())
582 continue;
583
[email protected]6d2dc982012-07-19 22:19:18584#define PER_DATA_TYPE_MACRO(type_str) \
[email protected]d9f025b2012-09-07 12:57:14585 SYNC_FREQ_HISTOGRAM("Sync.Freq" type_str, now - previous);
[email protected]3e299072013-05-09 05:51:05586 SYNC_DATA_TYPE_HISTOGRAM(iter.Get());
[email protected]6d2dc982012-07-19 22:19:18587#undef PER_DATA_TYPE_MACRO
[email protected]6d2dc982012-07-19 22:19:18588 }
[email protected]d9f025b2012-09-07 12:57:14589}
[email protected]6d2dc982012-07-19 22:19:18590
[email protected]5c135b62013-11-18 20:54:14591TimeDelta SyncSchedulerImpl::GetPollInterval() {
592 return (!session_context_->notifications_enabled() ||
593 !session_context_->ShouldFetchUpdatesBeforeCommit()) ?
594 syncer_short_poll_interval_seconds_ :
595 syncer_long_poll_interval_seconds_;
596}
597
[email protected]0248d922013-04-18 04:52:10598void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) {
[email protected]622618f2013-04-06 00:22:28599 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18600
[email protected]5c135b62013-11-18 20:54:14601 TimeDelta poll = GetPollInterval();
[email protected]6d2dc982012-07-19 22:19:18602 bool rate_changed = !poll_timer_.IsRunning() ||
603 poll != poll_timer_.GetCurrentDelay();
604
[email protected]5c135b62013-11-18 20:54:14605 if (type == FORCE_RESET) {
606 last_poll_reset_ = base::TimeTicks::Now();
607 if (!rate_changed)
608 poll_timer_.Reset();
609 }
[email protected]6d2dc982012-07-19 22:19:18610
611 if (!rate_changed)
612 return;
613
614 // Adjust poll rate.
615 poll_timer_.Stop();
616 poll_timer_.Start(FROM_HERE, poll, this,
617 &SyncSchedulerImpl::PollTimerCallback);
618}
619
[email protected]622618f2013-04-06 00:22:28620void SyncSchedulerImpl::RestartWaiting() {
[email protected]6d2dc982012-07-19 22:19:18621 CHECK(wait_interval_.get());
[email protected]eeac662c2012-10-30 20:31:18622 DCHECK(wait_interval_->length >= TimeDelta::FromSeconds(0));
[email protected]0248d922013-04-18 04:52:10623 NotifyRetryTime(base::Time::Now() + wait_interval_->length);
624 SDVLOG(2) << "Starting WaitInterval timer of length "
625 << wait_interval_->length.InMilliseconds() << "ms.";
[email protected]eeac662c2012-10-30 20:31:18626 if (wait_interval_->mode == WaitInterval::THROTTLED) {
[email protected]622618f2013-04-06 00:22:28627 pending_wakeup_timer_.Start(
628 FROM_HERE,
629 wait_interval_->length,
630 base::Bind(&SyncSchedulerImpl::Unthrottle,
631 weak_ptr_factory_.GetWeakPtr()));
[email protected]eeac662c2012-10-30 20:31:18632 } else {
[email protected]622618f2013-04-06 00:22:28633 pending_wakeup_timer_.Start(
634 FROM_HERE,
635 wait_interval_->length,
[email protected]580cda62013-05-16 23:37:30636 base::Bind(&SyncSchedulerImpl::ExponentialBackoffRetry,
[email protected]622618f2013-04-06 00:22:28637 weak_ptr_factory_.GetWeakPtr()));
[email protected]eeac662c2012-10-30 20:31:18638 }
[email protected]6d2dc982012-07-19 22:19:18639}
640
[email protected]ea29851b2013-09-19 01:17:02641void SyncSchedulerImpl::Stop() {
[email protected]622618f2013-04-06 00:22:28642 DCHECK(CalledOnValidThread());
[email protected]ea29851b2013-09-19 01:17:02643 SDVLOG(2) << "Stop called";
[email protected]6d2dc982012-07-19 22:19:18644
645 // Kill any in-flight method calls.
646 weak_ptr_factory_.InvalidateWeakPtrs();
647 wait_interval_.reset();
[email protected]dcdda4312013-02-26 20:33:05648 NotifyRetryTime(base::Time());
[email protected]6d2dc982012-07-19 22:19:18649 poll_timer_.Stop();
[email protected]622618f2013-04-06 00:22:28650 pending_wakeup_timer_.Stop();
[email protected]0248d922013-04-18 04:52:10651 pending_configure_params_.reset();
652 if (started_)
[email protected]6d2dc982012-07-19 22:19:18653 started_ = false;
[email protected]6d2dc982012-07-19 22:19:18654}
655
[email protected]622618f2013-04-06 00:22:28656// This is the only place where we invoke DoSyncSessionJob with canary
657// privileges. Everyone else should use NORMAL_PRIORITY.
658void SyncSchedulerImpl::TryCanaryJob() {
[email protected]fd405e42014-01-04 03:45:53659 next_sync_session_job_priority_ = CANARY_PRIORITY;
660 TrySyncSessionJob();
[email protected]eeac662c2012-10-30 20:31:18661}
662
[email protected]fd405e42014-01-04 03:45:53663void SyncSchedulerImpl::TrySyncSessionJob() {
[email protected]e0428b12013-12-16 18:52:43664 // Post call to TrySyncSessionJobImpl on current thread. Later request for
665 // access token will be here.
666 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
667 &SyncSchedulerImpl::TrySyncSessionJobImpl,
[email protected]fd405e42014-01-04 03:45:53668 weak_ptr_factory_.GetWeakPtr()));
[email protected]e0428b12013-12-16 18:52:43669}
670
[email protected]fd405e42014-01-04 03:45:53671void SyncSchedulerImpl::TrySyncSessionJobImpl() {
672 JobPriority priority = next_sync_session_job_priority_;
673 next_sync_session_job_priority_ = NORMAL_PRIORITY;
674
[email protected]3a489722014-02-03 23:35:59675 nudge_tracker_.SetSyncCycleStartTime(base::TimeTicks::Now());
676
[email protected]5c135b62013-11-18 20:54:14677 DCHECK(CalledOnValidThread());
678 if (mode_ == CONFIGURATION_MODE) {
679 if (pending_configure_params_) {
680 SDVLOG(2) << "Found pending configure job";
681 DoConfigurationSyncSessionJob(priority);
682 }
[email protected]3dfc7b792014-01-14 16:17:43683 } else if (CanRunNudgeJobNow(priority)) {
684 if (nudge_tracker_.IsSyncRequired()) {
[email protected]5c135b62013-11-18 20:54:14685 SDVLOG(2) << "Found pending nudge job";
686 DoNudgeSyncSessionJob(priority);
687 } else if (do_poll_after_credentials_updated_ ||
688 ((base::TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) {
689 DoPollSyncSessionJob();
[email protected]e0428b12013-12-16 18:52:43690 // Poll timer fires infrequently. Usually by this time access token is
691 // already expired and poll job will fail with auth error. Set flag to
692 // retry poll once ProfileSyncService gets new access token, TryCanaryJob
693 // will be called after access token is retrieved.
694 if (HttpResponse::SYNC_AUTH_ERROR ==
695 session_context_->connection_manager()->server_status()) {
696 do_poll_after_credentials_updated_ = true;
697 }
[email protected]5c135b62013-11-18 20:54:14698 }
699 }
[email protected]e0428b12013-12-16 18:52:43700
701 if (priority == CANARY_PRIORITY) {
702 // If this is canary job then whatever result was don't run poll job till
703 // the next time poll timer fires.
704 do_poll_after_credentials_updated_ = false;
705 }
706
707 if (IsBackingOff() && !pending_wakeup_timer_.IsRunning()) {
708 // If we succeeded, our wait interval would have been cleared. If it hasn't
709 // been cleared, then we should increase our backoff interval and schedule
710 // another retry.
711 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length);
712 wait_interval_.reset(
713 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length));
714 SDVLOG(2) << "Sync cycle failed. Will back off for "
715 << wait_interval_->length.InMilliseconds() << "ms.";
716 RestartWaiting();
717 }
[email protected]5c135b62013-11-18 20:54:14718}
719
[email protected]6d2dc982012-07-19 22:19:18720void SyncSchedulerImpl::PollTimerCallback() {
[email protected]622618f2013-04-06 00:22:28721 DCHECK(CalledOnValidThread());
[email protected]93afb3b2013-03-20 21:01:27722 if (no_scheduling_allowed_) {
723 // The no_scheduling_allowed_ flag is set by a function-scoped AutoReset in
724 // functions that are called only on the sync thread. This function is also
725 // called only on the sync thread, and only when it is posted by an expiring
726 // timer. If we find that no_scheduling_allowed_ is set here, then
727 // something is very wrong. Maybe someone mistakenly called us directly, or
728 // mishandled the book-keeping for no_scheduling_allowed_.
729 NOTREACHED() << "Illegal to schedule job while session in progress.";
730 return;
731 }
732
[email protected]fd405e42014-01-04 03:45:53733 TrySyncSessionJob();
[email protected]6d2dc982012-07-19 22:19:18734}
735
[email protected]3dfc7b792014-01-14 16:17:43736void SyncSchedulerImpl::RetryTimerCallback() {
737 TrySyncSessionJob();
738}
739
[email protected]622618f2013-04-06 00:22:28740void SyncSchedulerImpl::Unthrottle() {
741 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18742 DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode);
[email protected]eeac662c2012-10-30 20:31:18743
[email protected]f643ae0a2013-01-26 03:37:24744 // We're no longer throttled, so clear the wait interval.
[email protected]6d2dc982012-07-19 22:19:18745 wait_interval_.reset();
[email protected]dcdda4312013-02-26 20:33:05746 NotifyRetryTime(base::Time());
[email protected]eb370fc2014-03-21 22:14:35747 NotifyThrottledTypesChanged(nudge_tracker_.GetThrottledTypes());
[email protected]f643ae0a2013-01-26 03:37:24748
749 // We treat this as a 'canary' in the sense that it was originally scheduled
750 // to run some time ago, failed, and we now want to retry, versus a job that
751 // was just created (e.g via ScheduleNudgeImpl). The main implication is
752 // that we're careful to update routing info (etc) with such potentially
753 // stale canary jobs.
[email protected]622618f2013-04-06 00:22:28754 TryCanaryJob();
[email protected]6d2dc982012-07-19 22:19:18755}
756
[email protected]d9d8f9f2013-06-14 19:45:30757void SyncSchedulerImpl::TypeUnthrottle(base::TimeTicks unthrottle_time) {
758 DCHECK(CalledOnValidThread());
759 nudge_tracker_.UpdateTypeThrottlingState(unthrottle_time);
760 NotifyThrottledTypesChanged(nudge_tracker_.GetThrottledTypes());
761
762 if (nudge_tracker_.IsAnyTypeThrottled()) {
[email protected]543489a612014-02-06 09:12:07763 const base::TimeTicks now = base::TimeTicks::Now();
[email protected]d9d8f9f2013-06-14 19:45:30764 base::TimeDelta time_until_next_unthrottle =
[email protected]543489a612014-02-06 09:12:07765 nudge_tracker_.GetTimeUntilNextUnthrottle(now);
[email protected]d9d8f9f2013-06-14 19:45:30766 type_unthrottle_timer_.Start(
767 FROM_HERE,
768 time_until_next_unthrottle,
769 base::Bind(&SyncSchedulerImpl::TypeUnthrottle,
770 weak_ptr_factory_.GetWeakPtr(),
[email protected]543489a612014-02-06 09:12:07771 now + time_until_next_unthrottle));
[email protected]d9d8f9f2013-06-14 19:45:30772 }
773
774 // Maybe this is a good time to run a nudge job. Let's try it.
775 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(NORMAL_PRIORITY))
[email protected]fd405e42014-01-04 03:45:53776 TrySyncSessionJob();
[email protected]d9d8f9f2013-06-14 19:45:30777}
778
779void SyncSchedulerImpl::PerformDelayedNudge() {
780 // Circumstances may have changed since we scheduled this delayed nudge.
781 // We must check to see if it's OK to run the job before we do so.
782 if (CanRunNudgeJobNow(NORMAL_PRIORITY))
[email protected]fd405e42014-01-04 03:45:53783 TrySyncSessionJob();
[email protected]d9d8f9f2013-06-14 19:45:30784
785 // We're not responsible for setting up any retries here. The functions that
786 // first put us into a state that prevents successful sync cycles (eg. global
787 // throttling, type throttling, network errors, transient errors) will also
788 // setup the appropriate retry logic (eg. retry after timeout, exponential
789 // backoff, retry when the network changes).
790}
791
[email protected]580cda62013-05-16 23:37:30792void SyncSchedulerImpl::ExponentialBackoffRetry() {
793 TryCanaryJob();
[email protected]580cda62013-05-16 23:37:30794}
795
[email protected]dcdda4312013-02-26 20:33:05796void SyncSchedulerImpl::NotifyRetryTime(base::Time retry_time) {
[email protected]325c3502014-02-11 13:56:43797 FOR_EACH_OBSERVER(SyncEngineEventListener,
798 *session_context_->listeners(),
799 OnRetryTimeChanged(retry_time));
[email protected]dcdda4312013-02-26 20:33:05800}
801
[email protected]d9d8f9f2013-06-14 19:45:30802void SyncSchedulerImpl::NotifyThrottledTypesChanged(ModelTypeSet types) {
[email protected]325c3502014-02-11 13:56:43803 FOR_EACH_OBSERVER(SyncEngineEventListener,
804 *session_context_->listeners(),
805 OnThrottledTypesChanged(types));
[email protected]d9d8f9f2013-06-14 19:45:30806}
807
[email protected]6d2dc982012-07-19 22:19:18808bool SyncSchedulerImpl::IsBackingOff() const {
[email protected]622618f2013-04-06 00:22:28809 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18810 return wait_interval_.get() && wait_interval_->mode ==
811 WaitInterval::EXPONENTIAL_BACKOFF;
812}
813
[email protected]d9d8f9f2013-06-14 19:45:30814void SyncSchedulerImpl::OnThrottled(const base::TimeDelta& throttle_duration) {
[email protected]622618f2013-04-06 00:22:28815 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18816 wait_interval_.reset(new WaitInterval(WaitInterval::THROTTLED,
[email protected]d9d8f9f2013-06-14 19:45:30817 throttle_duration));
[email protected]dcdda4312013-02-26 20:33:05818 NotifyRetryTime(base::Time::Now() + wait_interval_->length);
[email protected]eb370fc2014-03-21 22:14:35819 NotifyThrottledTypesChanged(ModelTypeSet::All());
[email protected]6d2dc982012-07-19 22:19:18820}
821
[email protected]d9d8f9f2013-06-14 19:45:30822void SyncSchedulerImpl::OnTypesThrottled(
823 ModelTypeSet types,
824 const base::TimeDelta& throttle_duration) {
825 base::TimeTicks now = base::TimeTicks::Now();
826
827 nudge_tracker_.SetTypesThrottledUntil(types, throttle_duration, now);
828 base::TimeDelta time_until_next_unthrottle =
829 nudge_tracker_.GetTimeUntilNextUnthrottle(now);
830 type_unthrottle_timer_.Start(
831 FROM_HERE,
832 time_until_next_unthrottle,
833 base::Bind(&SyncSchedulerImpl::TypeUnthrottle,
834 weak_ptr_factory_.GetWeakPtr(),
835 now + time_until_next_unthrottle));
836 NotifyThrottledTypesChanged(nudge_tracker_.GetThrottledTypes());
837}
838
839bool SyncSchedulerImpl::IsCurrentlyThrottled() {
[email protected]622618f2013-04-06 00:22:28840 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18841 return wait_interval_.get() && wait_interval_->mode ==
842 WaitInterval::THROTTLED;
843}
844
845void SyncSchedulerImpl::OnReceivedShortPollIntervalUpdate(
846 const base::TimeDelta& new_interval) {
[email protected]622618f2013-04-06 00:22:28847 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18848 syncer_short_poll_interval_seconds_ = new_interval;
849}
850
851void SyncSchedulerImpl::OnReceivedLongPollIntervalUpdate(
852 const base::TimeDelta& new_interval) {
[email protected]622618f2013-04-06 00:22:28853 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18854 syncer_long_poll_interval_seconds_ = new_interval;
855}
856
857void SyncSchedulerImpl::OnReceivedSessionsCommitDelay(
858 const base::TimeDelta& new_delay) {
[email protected]622618f2013-04-06 00:22:28859 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18860 sessions_commit_delay_ = new_delay;
861}
862
[email protected]3e299072013-05-09 05:51:05863void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) {
864 if (size > 0)
865 nudge_tracker_.SetHintBufferSize(size);
866 else
867 NOTREACHED() << "Hint buffer size should be > 0.";
868}
869
[email protected]6d2dc982012-07-19 22:19:18870void SyncSchedulerImpl::OnSyncProtocolError(
[email protected]325c3502014-02-11 13:56:43871 const SyncProtocolError& sync_protocol_error) {
[email protected]622618f2013-04-06 00:22:28872 DCHECK(CalledOnValidThread());
[email protected]325c3502014-02-11 13:56:43873 if (ShouldRequestEarlyExit(sync_protocol_error)) {
[email protected]6d2dc982012-07-19 22:19:18874 SDVLOG(2) << "Sync Scheduler requesting early exit.";
[email protected]ea29851b2013-09-19 01:17:02875 Stop();
[email protected]6d2dc982012-07-19 22:19:18876 }
[email protected]325c3502014-02-11 13:56:43877 if (IsActionableError(sync_protocol_error)) {
878 SDVLOG(2) << "OnActionableError";
879 FOR_EACH_OBSERVER(SyncEngineEventListener,
880 *session_context_->listeners(),
881 OnActionableError(sync_protocol_error));
882 }
[email protected]6d2dc982012-07-19 22:19:18883}
884
[email protected]3dfc7b792014-01-14 16:17:43885void SyncSchedulerImpl::OnReceivedGuRetryDelay(const base::TimeDelta& delay) {
[email protected]3a489722014-02-03 23:35:59886 nudge_tracker_.SetNextRetryTime(TimeTicks::Now() + delay);
[email protected]3dfc7b792014-01-14 16:17:43887 retry_timer_.Start(FROM_HERE, delay, this,
888 &SyncSchedulerImpl::RetryTimerCallback);
889}
890
[email protected]b99f5482014-02-12 23:47:37891void SyncSchedulerImpl::OnReceivedMigrationRequest(ModelTypeSet types) {
892 FOR_EACH_OBSERVER(SyncEngineEventListener,
893 *session_context_->listeners(),
894 OnMigrationRequested(types));
895}
896
[email protected]6d2dc982012-07-19 22:19:18897void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) {
[email protected]622618f2013-04-06 00:22:28898 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18899 session_context_->set_notifications_enabled(notifications_enabled);
[email protected]3e299072013-05-09 05:51:05900 if (notifications_enabled)
901 nudge_tracker_.OnInvalidationsEnabled();
902 else
903 nudge_tracker_.OnInvalidationsDisabled();
[email protected]6d2dc982012-07-19 22:19:18904}
905
906base::TimeDelta SyncSchedulerImpl::GetSessionsCommitDelay() const {
[email protected]622618f2013-04-06 00:22:28907 DCHECK(CalledOnValidThread());
[email protected]6d2dc982012-07-19 22:19:18908 return sessions_commit_delay_;
909}
910
911#undef SDVLOG_LOC
912
913#undef SDVLOG
914
915#undef SLOG
916
917#undef ENUM_CASE
918
919} // namespace syncer