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 "components/sync/engine_impl/sync_scheduler_impl.h" | 5 #include "components/sync/engine_impl/sync_scheduler_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstring> | 8 #include <cstring> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 mode_(CONFIGURATION_MODE), | 142 mode_(CONFIGURATION_MODE), |
143 delay_provider_(delay_provider), | 143 delay_provider_(delay_provider), |
144 syncer_(syncer), | 144 syncer_(syncer), |
145 cycle_context_(context), | 145 cycle_context_(context), |
146 next_sync_cycle_job_priority_(NORMAL_PRIORITY), | 146 next_sync_cycle_job_priority_(NORMAL_PRIORITY), |
147 ignore_auth_credentials_(ignore_auth_credentials), | 147 ignore_auth_credentials_(ignore_auth_credentials), |
148 weak_ptr_factory_(this) {} | 148 weak_ptr_factory_(this) {} |
149 | 149 |
150 SyncSchedulerImpl::~SyncSchedulerImpl() { | 150 SyncSchedulerImpl::~SyncSchedulerImpl() { |
151 DCHECK(CalledOnValidThread()); | 151 DCHECK(CalledOnValidThread()); |
| 152 |
152 Stop(); | 153 Stop(); |
153 } | 154 } |
154 | 155 |
155 void SyncSchedulerImpl::OnCredentialsUpdated() { | 156 void SyncSchedulerImpl::OnCredentialsUpdated() { |
156 DCHECK(CalledOnValidThread()); | 157 DCHECK(CalledOnValidThread()); |
157 | 158 |
158 if (HttpResponse::SYNC_AUTH_ERROR == | 159 if (HttpResponse::SYNC_AUTH_ERROR == |
159 cycle_context_->connection_manager()->server_status()) { | 160 cycle_context_->connection_manager()->server_status()) { |
160 OnServerConnectionErrorFixed(); | 161 OnServerConnectionErrorFixed(); |
161 } | 162 } |
162 } | 163 } |
163 | 164 |
164 void SyncSchedulerImpl::OnConnectionStatusChange() { | 165 void SyncSchedulerImpl::OnConnectionStatusChange() { |
| 166 DCHECK(CalledOnValidThread()); |
| 167 |
165 if (HttpResponse::CONNECTION_UNAVAILABLE == | 168 if (HttpResponse::CONNECTION_UNAVAILABLE == |
166 cycle_context_->connection_manager()->server_status()) { | 169 cycle_context_->connection_manager()->server_status()) { |
167 // Optimistically assume that the connection is fixed and try | 170 // Optimistically assume that the connection is fixed and try |
168 // connecting. | 171 // connecting. |
169 OnServerConnectionErrorFixed(); | 172 OnServerConnectionErrorFixed(); |
170 } | 173 } |
171 } | 174 } |
172 | 175 |
173 void SyncSchedulerImpl::OnServerConnectionErrorFixed() { | 176 void SyncSchedulerImpl::OnServerConnectionErrorFixed() { |
174 // There could be a pending nudge or configuration job in several cases: | 177 // There could be a pending nudge or configuration job in several cases: |
175 // | 178 // |
176 // 1. We're in exponential backoff. | 179 // 1. We're in exponential backoff. |
177 // 2. We're silenced / throttled. | 180 // 2. We're silenced / throttled. |
178 // 3. A nudge was saved previously due to not having a valid auth token. | 181 // 3. A nudge was saved previously due to not having a valid auth token. |
179 // 4. A nudge was scheduled + saved while in configuration mode. | 182 // 4. A nudge was scheduled + saved while in configuration mode. |
180 // | 183 // |
181 // In all cases except (2), we want to retry contacting the server. We | 184 // In all cases except (2), we want to retry contacting the server. We |
182 // call TryCanaryJob to achieve this, and note that nothing -- not even a | 185 // call TryCanaryJob to achieve this, and note that nothing -- not even a |
183 // canary job -- can bypass a THROTTLED WaitInterval. The only thing that | 186 // canary job -- can bypass a THROTTLED WaitInterval. The only thing that |
184 // has the authority to do that is the Unthrottle timer. | 187 // has the authority to do that is the Unthrottle timer. |
185 TryCanaryJob(); | 188 TryCanaryJob(); |
186 } | 189 } |
187 | 190 |
188 void SyncSchedulerImpl::Start(Mode mode, base::Time last_poll_time) { | 191 void SyncSchedulerImpl::Start(Mode mode, base::Time last_poll_time) { |
189 DCHECK(CalledOnValidThread()); | 192 DCHECK(CalledOnValidThread()); |
| 193 |
190 std::string thread_name = base::PlatformThread::GetName(); | 194 std::string thread_name = base::PlatformThread::GetName(); |
191 if (thread_name.empty()) | 195 if (thread_name.empty()) |
192 thread_name = "<Main thread>"; | 196 thread_name = "<Main thread>"; |
193 SDVLOG(2) << "Start called from thread " << thread_name << " with mode " | 197 SDVLOG(2) << "Start called from thread " << thread_name << " with mode " |
194 << GetModeString(mode); | 198 << GetModeString(mode); |
195 if (!started_) { | 199 if (!started_) { |
196 started_ = true; | 200 started_ = true; |
197 SendInitialSnapshot(); | 201 SendInitialSnapshot(); |
198 } | 202 } |
199 | 203 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnblockedTypes() { | 236 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnblockedTypes() { |
233 ModelTypeSet enabled_types = cycle_context_->GetEnabledTypes(); | 237 ModelTypeSet enabled_types = cycle_context_->GetEnabledTypes(); |
234 ModelTypeSet enabled_protocol_types = | 238 ModelTypeSet enabled_protocol_types = |
235 Intersection(ProtocolTypes(), enabled_types); | 239 Intersection(ProtocolTypes(), enabled_types); |
236 ModelTypeSet blocked_types = nudge_tracker_.GetBlockedTypes(); | 240 ModelTypeSet blocked_types = nudge_tracker_.GetBlockedTypes(); |
237 return Difference(enabled_protocol_types, blocked_types); | 241 return Difference(enabled_protocol_types, blocked_types); |
238 } | 242 } |
239 | 243 |
240 void SyncSchedulerImpl::SendInitialSnapshot() { | 244 void SyncSchedulerImpl::SendInitialSnapshot() { |
241 DCHECK(CalledOnValidThread()); | 245 DCHECK(CalledOnValidThread()); |
| 246 |
242 SyncCycleEvent event(SyncCycleEvent::STATUS_CHANGED); | 247 SyncCycleEvent event(SyncCycleEvent::STATUS_CHANGED); |
243 event.snapshot = SyncCycle(cycle_context_, this).TakeSnapshot(); | 248 event.snapshot = SyncCycle(cycle_context_, this).TakeSnapshot(); |
244 for (auto& observer : *cycle_context_->listeners()) | 249 for (auto& observer : *cycle_context_->listeners()) |
245 observer.OnSyncCycleEvent(event); | 250 observer.OnSyncCycleEvent(event); |
246 } | 251 } |
247 | 252 |
248 void SyncSchedulerImpl::ScheduleConfiguration( | 253 void SyncSchedulerImpl::ScheduleConfiguration( |
249 const ConfigurationParams& params) { | 254 const ConfigurationParams& params) { |
250 DCHECK(CalledOnValidThread()); | 255 DCHECK(CalledOnValidThread()); |
251 DCHECK(IsConfigRelatedUpdateSourceValue(params.source)); | 256 DCHECK(IsConfigRelatedUpdateSourceValue(params.source)); |
(...skipping 15 matching lines...) Expand all Loading... |
267 params.ready_task.Run(); | 272 params.ready_task.Run(); |
268 } | 273 } |
269 } | 274 } |
270 | 275 |
271 void SyncSchedulerImpl::ScheduleClearServerData(const ClearParams& params) { | 276 void SyncSchedulerImpl::ScheduleClearServerData(const ClearParams& params) { |
272 DCHECK(CalledOnValidThread()); | 277 DCHECK(CalledOnValidThread()); |
273 DCHECK_EQ(CLEAR_SERVER_DATA_MODE, mode_); | 278 DCHECK_EQ(CLEAR_SERVER_DATA_MODE, mode_); |
274 DCHECK(!pending_configure_params_); | 279 DCHECK(!pending_configure_params_); |
275 DCHECK(!params.report_success_task.is_null()); | 280 DCHECK(!params.report_success_task.is_null()); |
276 CHECK(started_) << "Scheduler must be running to clear."; | 281 CHECK(started_) << "Scheduler must be running to clear."; |
| 282 |
277 pending_clear_params_ = base::MakeUnique<ClearParams>(params); | 283 pending_clear_params_ = base::MakeUnique<ClearParams>(params); |
278 TrySyncCycleJob(); | 284 TrySyncCycleJob(); |
279 } | 285 } |
280 | 286 |
281 bool SyncSchedulerImpl::CanRunJobNow(JobPriority priority) { | 287 bool SyncSchedulerImpl::CanRunJobNow(JobPriority priority) { |
282 DCHECK(CalledOnValidThread()); | 288 DCHECK(CalledOnValidThread()); |
| 289 |
283 if (IsCurrentlyThrottled()) { | 290 if (IsCurrentlyThrottled()) { |
284 SDVLOG(1) << "Unable to run a job because we're throttled."; | 291 SDVLOG(1) << "Unable to run a job because we're throttled."; |
285 return false; | 292 return false; |
286 } | 293 } |
287 | 294 |
288 if (IsBackingOff() && priority != CANARY_PRIORITY) { | 295 if (IsBackingOff() && priority != CANARY_PRIORITY) { |
289 SDVLOG(1) << "Unable to run a job because we're backing off."; | 296 SDVLOG(1) << "Unable to run a job because we're backing off."; |
290 return false; | 297 return false; |
291 } | 298 } |
292 | 299 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 << "Dropping nudge, scheduler is not running."; | 391 << "Dropping nudge, scheduler is not running."; |
385 return; | 392 return; |
386 } | 393 } |
387 | 394 |
388 SDVLOG_LOC(nudge_location, 2) << "In ScheduleNudgeImpl with delay " | 395 SDVLOG_LOC(nudge_location, 2) << "In ScheduleNudgeImpl with delay " |
389 << delay.InMilliseconds() << " ms"; | 396 << delay.InMilliseconds() << " ms"; |
390 | 397 |
391 if (!CanRunNudgeJobNow(NORMAL_PRIORITY)) | 398 if (!CanRunNudgeJobNow(NORMAL_PRIORITY)) |
392 return; | 399 return; |
393 | 400 |
394 TimeTicks incoming_run_time = TimeTicks::Now() + delay; | 401 if (!IsEarlierThanCurrentPendingJob(delay)) { |
395 if (pending_wakeup_timer_.IsRunning() && | |
396 (pending_wakeup_timer_.desired_run_time() < incoming_run_time)) { | |
397 // Old job arrives sooner than this one. Don't reschedule it. | 402 // Old job arrives sooner than this one. Don't reschedule it. |
398 return; | 403 return; |
399 } | 404 } |
400 | 405 |
401 // Either there is no existing nudge in flight or the incoming nudge should be | 406 // Either there is no existing nudge in flight or the incoming nudge should be |
402 // made to arrive first (preempt) the existing nudge. We reschedule in either | 407 // made to arrive first (preempt) the existing nudge. We reschedule in either |
403 // case. | 408 // case. |
404 SDVLOG_LOC(nudge_location, 2) << "Scheduling a nudge with " | 409 SDVLOG_LOC(nudge_location, 2) << "Scheduling a nudge with " |
405 << delay.InMilliseconds() << " ms delay"; | 410 << delay.InMilliseconds() << " ms delay"; |
406 pending_wakeup_timer_.Start( | 411 pending_wakeup_timer_.Start( |
407 nudge_location, delay, base::Bind(&SyncSchedulerImpl::PerformDelayedNudge, | 412 nudge_location, delay, base::Bind(&SyncSchedulerImpl::PerformDelayedNudge, |
408 weak_ptr_factory_.GetWeakPtr())); | 413 weak_ptr_factory_.GetWeakPtr())); |
409 } | 414 } |
410 | 415 |
411 const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) { | 416 const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) { |
412 switch (mode) { | 417 switch (mode) { |
413 ENUM_CASE(CONFIGURATION_MODE); | 418 ENUM_CASE(CONFIGURATION_MODE); |
414 ENUM_CASE(CLEAR_SERVER_DATA_MODE); | 419 ENUM_CASE(CLEAR_SERVER_DATA_MODE); |
415 ENUM_CASE(NORMAL_MODE); | 420 ENUM_CASE(NORMAL_MODE); |
416 } | 421 } |
417 return ""; | 422 return ""; |
418 } | 423 } |
419 | 424 |
420 void SyncSchedulerImpl::SetDefaultNudgeDelay(TimeDelta delay_ms) { | 425 void SyncSchedulerImpl::SetDefaultNudgeDelay(TimeDelta delay_ms) { |
421 DCHECK(CalledOnValidThread()); | 426 DCHECK(CalledOnValidThread()); |
| 427 |
422 nudge_tracker_.SetDefaultNudgeDelay(delay_ms); | 428 nudge_tracker_.SetDefaultNudgeDelay(delay_ms); |
423 } | 429 } |
424 | 430 |
425 void SyncSchedulerImpl::DoNudgeSyncCycleJob(JobPriority priority) { | 431 void SyncSchedulerImpl::DoNudgeSyncCycleJob(JobPriority priority) { |
426 DCHECK(CalledOnValidThread()); | 432 DCHECK(CalledOnValidThread()); |
427 DCHECK(CanRunNudgeJobNow(priority)); | 433 DCHECK(CanRunNudgeJobNow(priority)); |
428 | 434 |
429 DVLOG(2) << "Will run normal mode sync cycle with types " | 435 DVLOG(2) << "Will run normal mode sync cycle with types " |
430 << ModelTypeSetToString(GetEnabledAndUnblockedTypes()); | 436 << ModelTypeSetToString(GetEnabledAndUnblockedTypes()); |
431 SyncCycle cycle(cycle_context_, this); | 437 SyncCycle cycle(cycle_context_, this); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 SDVLOG(2) << "Sync cycle failed. Will back off for " | 530 SDVLOG(2) << "Sync cycle failed. Will back off for " |
525 << wait_interval_->length.InMilliseconds() << "ms."; | 531 << wait_interval_->length.InMilliseconds() << "ms."; |
526 } else { | 532 } else { |
527 // Increase our backoff interval and schedule another retry. | 533 // Increase our backoff interval and schedule another retry. |
528 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length); | 534 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length); |
529 wait_interval_ = base::MakeUnique<WaitInterval>( | 535 wait_interval_ = base::MakeUnique<WaitInterval>( |
530 WaitInterval::EXPONENTIAL_BACKOFF, length); | 536 WaitInterval::EXPONENTIAL_BACKOFF, length); |
531 SDVLOG(2) << "Sync cycle failed. Will back off for " | 537 SDVLOG(2) << "Sync cycle failed. Will back off for " |
532 << wait_interval_->length.InMilliseconds() << "ms."; | 538 << wait_interval_->length.InMilliseconds() << "ms."; |
533 } | 539 } |
534 RestartWaiting(); | |
535 } | 540 } |
536 | 541 |
537 void SyncSchedulerImpl::DoPollSyncCycleJob() { | 542 void SyncSchedulerImpl::DoPollSyncCycleJob() { |
538 SDVLOG(2) << "Polling with types " | 543 SDVLOG(2) << "Polling with types " |
539 << ModelTypeSetToString(GetEnabledAndUnblockedTypes()); | 544 << ModelTypeSetToString(GetEnabledAndUnblockedTypes()); |
540 SyncCycle cycle(cycle_context_, this); | 545 SyncCycle cycle(cycle_context_, this); |
541 bool success = syncer_->PollSyncShare(GetEnabledAndUnblockedTypes(), &cycle); | 546 bool success = syncer_->PollSyncShare(GetEnabledAndUnblockedTypes(), &cycle); |
542 | 547 |
543 // Only restart the timer if the poll succeeded. Otherwise rely on normal | 548 // Only restart the timer if the poll succeeded. Otherwise rely on normal |
544 // failure handling to retry with backoff. | 549 // failure handling to retry with backoff. |
545 if (success) { | 550 if (success) { |
546 AdjustPolling(FORCE_RESET); | 551 AdjustPolling(FORCE_RESET); |
547 HandleSuccess(); | 552 HandleSuccess(); |
548 } else { | 553 } else { |
549 HandleFailure(cycle.status_controller().model_neutral_state()); | 554 HandleFailure(cycle.status_controller().model_neutral_state()); |
550 } | 555 } |
551 } | 556 } |
552 | 557 |
553 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { | 558 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { |
554 DCHECK(CalledOnValidThread()); | 559 DCHECK(CalledOnValidThread()); |
| 560 |
555 TimeTicks now = TimeTicks::Now(); | 561 TimeTicks now = TimeTicks::Now(); |
556 // Update timing information for how often datatypes are triggering nudges. | 562 // Update timing information for how often datatypes are triggering nudges. |
557 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) { | 563 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) { |
558 TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()]; | 564 TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()]; |
559 last_local_nudges_by_model_type_[iter.Get()] = now; | 565 last_local_nudges_by_model_type_[iter.Get()] = now; |
560 if (previous.is_null()) | 566 if (previous.is_null()) |
561 continue; | 567 continue; |
562 | 568 |
563 #define PER_DATA_TYPE_MACRO(type_str) \ | 569 #define PER_DATA_TYPE_MACRO(type_str) \ |
564 SYNC_FREQ_HISTOGRAM("Sync.Freq" type_str, now - previous); | 570 SYNC_FREQ_HISTOGRAM("Sync.Freq" type_str, now - previous); |
565 SYNC_DATA_TYPE_HISTOGRAM(iter.Get()); | 571 SYNC_DATA_TYPE_HISTOGRAM(iter.Get()); |
566 #undef PER_DATA_TYPE_MACRO | 572 #undef PER_DATA_TYPE_MACRO |
567 } | 573 } |
568 } | 574 } |
569 | 575 |
570 TimeDelta SyncSchedulerImpl::GetPollInterval() { | 576 TimeDelta SyncSchedulerImpl::GetPollInterval() { |
571 return (!cycle_context_->notifications_enabled() || | 577 return (!cycle_context_->notifications_enabled() || |
572 !cycle_context_->ShouldFetchUpdatesBeforeCommit()) | 578 !cycle_context_->ShouldFetchUpdatesBeforeCommit()) |
573 ? syncer_short_poll_interval_seconds_ | 579 ? syncer_short_poll_interval_seconds_ |
574 : syncer_long_poll_interval_seconds_; | 580 : syncer_long_poll_interval_seconds_; |
575 } | 581 } |
576 | 582 |
577 void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) { | 583 void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) { |
578 DCHECK(CalledOnValidThread()); | 584 DCHECK(CalledOnValidThread()); |
| 585 |
579 if (!started_) | 586 if (!started_) |
580 return; | 587 return; |
581 | 588 |
582 TimeDelta poll_interval = GetPollInterval(); | 589 TimeDelta poll_interval = GetPollInterval(); |
583 TimeDelta poll_delay = poll_interval; | 590 TimeDelta poll_delay = poll_interval; |
584 const TimeTicks now = TimeTicks::Now(); | 591 const TimeTicks now = TimeTicks::Now(); |
585 | 592 |
586 if (type == UPDATE_INTERVAL) { | 593 if (type == UPDATE_INTERVAL) { |
587 if (!last_poll_reset_.is_null()) { | 594 if (!last_poll_reset_.is_null()) { |
588 // Override the delay based on the last successful poll time (if it was | 595 // Override the delay based on the last successful poll time (if it was |
(...skipping 23 matching lines...) Expand all Loading... |
612 SDVLOG(1) << "Updating polling delay to " << poll_delay.InMinutes() | 619 SDVLOG(1) << "Updating polling delay to " << poll_delay.InMinutes() |
613 << " minutes."; | 620 << " minutes."; |
614 | 621 |
615 // Adjust poll rate. Start will reset the timer if it was already running. | 622 // Adjust poll rate. Start will reset the timer if it was already running. |
616 poll_timer_.Start(FROM_HERE, poll_delay, this, | 623 poll_timer_.Start(FROM_HERE, poll_delay, this, |
617 &SyncSchedulerImpl::PollTimerCallback); | 624 &SyncSchedulerImpl::PollTimerCallback); |
618 } | 625 } |
619 | 626 |
620 void SyncSchedulerImpl::RestartWaiting() { | 627 void SyncSchedulerImpl::RestartWaiting() { |
621 if (wait_interval_.get()) { | 628 if (wait_interval_.get()) { |
622 // Global throttling or backoff | 629 // Global throttling or backoff. |
| 630 if (!IsEarlierThanCurrentPendingJob(wait_interval_->length)) { |
| 631 // We check here because if we do not check here, and we already scheduled |
| 632 // a global unblock job, we will schedule another unblock job which has |
| 633 // same waiting time, then the job will be run later than expected. Even |
| 634 // we did not schedule an unblock job when code reach here, it is ok since |
| 635 // |TrySyncCycleJobImpl| will call this function after the scheduled job |
| 636 // got run. |
| 637 return; |
| 638 } |
623 NotifyRetryTime(base::Time::Now() + wait_interval_->length); | 639 NotifyRetryTime(base::Time::Now() + wait_interval_->length); |
624 SDVLOG(2) << "Starting WaitInterval timer of length " | 640 SDVLOG(2) << "Starting WaitInterval timer of length " |
625 << wait_interval_->length.InMilliseconds() << "ms."; | 641 << wait_interval_->length.InMilliseconds() << "ms."; |
626 if (wait_interval_->mode == WaitInterval::THROTTLED) { | 642 if (wait_interval_->mode == WaitInterval::THROTTLED) { |
627 pending_wakeup_timer_.Start(FROM_HERE, wait_interval_->length, | 643 pending_wakeup_timer_.Start(FROM_HERE, wait_interval_->length, |
628 base::Bind(&SyncSchedulerImpl::Unthrottle, | 644 base::Bind(&SyncSchedulerImpl::Unthrottle, |
629 weak_ptr_factory_.GetWeakPtr())); | 645 weak_ptr_factory_.GetWeakPtr())); |
630 } else { | 646 } else { |
631 pending_wakeup_timer_.Start( | 647 pending_wakeup_timer_.Start( |
632 FROM_HERE, wait_interval_->length, | 648 FROM_HERE, wait_interval_->length, |
633 base::Bind(&SyncSchedulerImpl::ExponentialBackoffRetry, | 649 base::Bind(&SyncSchedulerImpl::ExponentialBackoffRetry, |
634 weak_ptr_factory_.GetWeakPtr())); | 650 weak_ptr_factory_.GetWeakPtr())); |
635 } | 651 } |
636 } else if (nudge_tracker_.IsAnyTypeBlocked()) { | 652 } else if (nudge_tracker_.IsAnyTypeBlocked()) { |
637 // Per-datatype throttled or backed off. | 653 // Per-datatype throttled or backed off. |
638 TimeDelta time_until_next_unblock = | 654 TimeDelta time_until_next_unblock = |
639 nudge_tracker_.GetTimeUntilNextUnblock(); | 655 nudge_tracker_.GetTimeUntilNextUnblock(); |
| 656 if (!IsEarlierThanCurrentPendingJob(time_until_next_unblock)) { |
| 657 return; |
| 658 } |
640 pending_wakeup_timer_.Start(FROM_HERE, time_until_next_unblock, | 659 pending_wakeup_timer_.Start(FROM_HERE, time_until_next_unblock, |
641 base::Bind(&SyncSchedulerImpl::OnTypesUnblocked, | 660 base::Bind(&SyncSchedulerImpl::OnTypesUnblocked, |
642 weak_ptr_factory_.GetWeakPtr())); | 661 weak_ptr_factory_.GetWeakPtr())); |
643 } | 662 } |
644 } | 663 } |
645 | 664 |
646 void SyncSchedulerImpl::Stop() { | 665 void SyncSchedulerImpl::Stop() { |
647 DCHECK(CalledOnValidThread()); | 666 DCHECK(CalledOnValidThread()); |
648 SDVLOG(2) << "Stop called"; | 667 SDVLOG(2) << "Stop called"; |
649 | 668 |
(...skipping 19 matching lines...) Expand all Loading... |
669 | 688 |
670 void SyncSchedulerImpl::TrySyncCycleJob() { | 689 void SyncSchedulerImpl::TrySyncCycleJob() { |
671 // Post call to TrySyncCycleJobImpl on current thread. Later request for | 690 // Post call to TrySyncCycleJobImpl on current thread. Later request for |
672 // access token will be here. | 691 // access token will be here. |
673 base::ThreadTaskRunnerHandle::Get()->PostTask( | 692 base::ThreadTaskRunnerHandle::Get()->PostTask( |
674 FROM_HERE, base::Bind(&SyncSchedulerImpl::TrySyncCycleJobImpl, | 693 FROM_HERE, base::Bind(&SyncSchedulerImpl::TrySyncCycleJobImpl, |
675 weak_ptr_factory_.GetWeakPtr())); | 694 weak_ptr_factory_.GetWeakPtr())); |
676 } | 695 } |
677 | 696 |
678 void SyncSchedulerImpl::TrySyncCycleJobImpl() { | 697 void SyncSchedulerImpl::TrySyncCycleJobImpl() { |
| 698 DCHECK(CalledOnValidThread()); |
| 699 |
679 JobPriority priority = next_sync_cycle_job_priority_; | 700 JobPriority priority = next_sync_cycle_job_priority_; |
680 next_sync_cycle_job_priority_ = NORMAL_PRIORITY; | 701 next_sync_cycle_job_priority_ = NORMAL_PRIORITY; |
681 | 702 |
682 nudge_tracker_.SetSyncCycleStartTime(TimeTicks::Now()); | 703 nudge_tracker_.SetSyncCycleStartTime(TimeTicks::Now()); |
683 | 704 |
684 DCHECK(CalledOnValidThread()); | |
685 if (mode_ == CONFIGURATION_MODE) { | 705 if (mode_ == CONFIGURATION_MODE) { |
686 if (pending_configure_params_) { | 706 if (pending_configure_params_) { |
687 SDVLOG(2) << "Found pending configure job"; | 707 SDVLOG(2) << "Found pending configure job"; |
688 DoConfigurationSyncCycleJob(priority); | 708 DoConfigurationSyncCycleJob(priority); |
689 } | 709 } |
690 } else if (mode_ == CLEAR_SERVER_DATA_MODE) { | 710 } else if (mode_ == CLEAR_SERVER_DATA_MODE) { |
691 if (pending_clear_params_) { | 711 if (pending_clear_params_) { |
692 DoClearServerDataSyncCycleJob(priority); | 712 DoClearServerDataSyncCycleJob(priority); |
693 } | 713 } |
694 } else if (CanRunNudgeJobNow(priority)) { | 714 } else if (CanRunNudgeJobNow(priority)) { |
695 if (nudge_tracker_.IsSyncRequired()) { | 715 if (nudge_tracker_.IsSyncRequired()) { |
696 SDVLOG(2) << "Found pending nudge job"; | 716 SDVLOG(2) << "Found pending nudge job"; |
697 DoNudgeSyncCycleJob(priority); | 717 DoNudgeSyncCycleJob(priority); |
698 } else if (((TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) { | 718 } else if (((TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) { |
699 SDVLOG(2) << "Found pending poll"; | 719 SDVLOG(2) << "Found pending poll"; |
700 DoPollSyncCycleJob(); | 720 DoPollSyncCycleJob(); |
701 } | 721 } |
702 } else { | 722 } else { |
703 // We must be in an error state. Transitioning out of each of these | 723 // We must be in an error state. Transitioning out of each of these |
704 // error states should trigger a canary job. | 724 // error states should trigger a canary job. |
705 DCHECK(IsCurrentlyThrottled() || IsBackingOff() || | 725 DCHECK(IsCurrentlyThrottled() || IsBackingOff() || |
706 cycle_context_->connection_manager()->HasInvalidAuthToken()); | 726 cycle_context_->connection_manager()->HasInvalidAuthToken()); |
707 } | 727 } |
708 | 728 |
709 if (IsBackingOff() && !pending_wakeup_timer_.IsRunning()) { | 729 RestartWaiting(); |
710 // If we succeeded, our wait interval would have been cleared. If it hasn't | |
711 // been cleared, then we should increase our backoff interval and schedule | |
712 // another retry. | |
713 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length); | |
714 wait_interval_ = base::MakeUnique<WaitInterval>( | |
715 WaitInterval::EXPONENTIAL_BACKOFF, length); | |
716 SDVLOG(2) << "Sync cycle failed. Will back off for " | |
717 << wait_interval_->length.InMilliseconds() << "ms."; | |
718 RestartWaiting(); | |
719 } | |
720 } | 730 } |
721 | 731 |
722 void SyncSchedulerImpl::PollTimerCallback() { | 732 void SyncSchedulerImpl::PollTimerCallback() { |
723 DCHECK(CalledOnValidThread()); | 733 DCHECK(CalledOnValidThread()); |
724 CHECK(!syncer_->IsSyncing()); | 734 CHECK(!syncer_->IsSyncing()); |
725 | 735 |
726 TrySyncCycleJob(); | 736 TrySyncCycleJob(); |
727 } | 737 } |
728 | 738 |
729 void SyncSchedulerImpl::RetryTimerCallback() { | 739 void SyncSchedulerImpl::RetryTimerCallback() { |
(...skipping 12 matching lines...) Expand all Loading... |
742 // We treat this as a 'canary' in the sense that it was originally scheduled | 752 // We treat this as a 'canary' in the sense that it was originally scheduled |
743 // to run some time ago, failed, and we now want to retry, versus a job that | 753 // to run some time ago, failed, and we now want to retry, versus a job that |
744 // was just created (e.g via ScheduleNudgeImpl). The main implication is | 754 // was just created (e.g via ScheduleNudgeImpl). The main implication is |
745 // that we're careful to update routing info (etc) with such potentially | 755 // that we're careful to update routing info (etc) with such potentially |
746 // stale canary jobs. | 756 // stale canary jobs. |
747 TryCanaryJob(); | 757 TryCanaryJob(); |
748 } | 758 } |
749 | 759 |
750 void SyncSchedulerImpl::OnTypesUnblocked() { | 760 void SyncSchedulerImpl::OnTypesUnblocked() { |
751 DCHECK(CalledOnValidThread()); | 761 DCHECK(CalledOnValidThread()); |
| 762 |
752 nudge_tracker_.UpdateTypeThrottlingAndBackoffState(); | 763 nudge_tracker_.UpdateTypeThrottlingAndBackoffState(); |
753 NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes()); | 764 NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes()); |
754 | 765 |
755 RestartWaiting(); | |
756 | |
757 // Maybe this is a good time to run a nudge job. Let's try it. | 766 // Maybe this is a good time to run a nudge job. Let's try it. |
| 767 // If not a good time, reschedule a new run. |
758 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(NORMAL_PRIORITY)) | 768 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(NORMAL_PRIORITY)) |
759 TrySyncCycleJob(); | 769 TrySyncCycleJob(); |
| 770 else |
| 771 RestartWaiting(); |
760 } | 772 } |
761 | 773 |
762 void SyncSchedulerImpl::PerformDelayedNudge() { | 774 void SyncSchedulerImpl::PerformDelayedNudge() { |
763 // Circumstances may have changed since we scheduled this delayed nudge. | 775 // Circumstances may have changed since we scheduled this delayed nudge. |
764 // We must check to see if it's OK to run the job before we do so. | 776 // We must check to see if it's OK to run the job before we do so. |
765 if (CanRunNudgeJobNow(NORMAL_PRIORITY)) | 777 if (CanRunNudgeJobNow(NORMAL_PRIORITY)) |
766 TrySyncCycleJob(); | 778 TrySyncCycleJob(); |
767 | 779 |
768 // We're not responsible for setting up any retries here. The functions that | 780 // We're not responsible for setting up any retries here. The functions that |
769 // first put us into a state that prevents successful sync cycles (eg. global | 781 // first put us into a state that prevents successful sync cycles (eg. global |
(...skipping 26 matching lines...) Expand all Loading... |
796 } | 808 } |
797 | 809 |
798 for (auto& observer : *cycle_context_->listeners()) { | 810 for (auto& observer : *cycle_context_->listeners()) { |
799 observer.OnThrottledTypesChanged(throttled_types); | 811 observer.OnThrottledTypesChanged(throttled_types); |
800 observer.OnBackedOffTypesChanged(backed_off_types); | 812 observer.OnBackedOffTypesChanged(backed_off_types); |
801 } | 813 } |
802 } | 814 } |
803 | 815 |
804 bool SyncSchedulerImpl::IsBackingOff() const { | 816 bool SyncSchedulerImpl::IsBackingOff() const { |
805 DCHECK(CalledOnValidThread()); | 817 DCHECK(CalledOnValidThread()); |
| 818 |
806 return wait_interval_.get() && | 819 return wait_interval_.get() && |
807 wait_interval_->mode == WaitInterval::EXPONENTIAL_BACKOFF; | 820 wait_interval_->mode == WaitInterval::EXPONENTIAL_BACKOFF; |
808 } | 821 } |
809 | 822 |
810 void SyncSchedulerImpl::OnThrottled(const TimeDelta& throttle_duration) { | 823 void SyncSchedulerImpl::OnThrottled(const TimeDelta& throttle_duration) { |
811 DCHECK(CalledOnValidThread()); | 824 DCHECK(CalledOnValidThread()); |
| 825 |
812 wait_interval_ = base::MakeUnique<WaitInterval>(WaitInterval::THROTTLED, | 826 wait_interval_ = base::MakeUnique<WaitInterval>(WaitInterval::THROTTLED, |
813 throttle_duration); | 827 throttle_duration); |
814 NotifyRetryTime(base::Time::Now() + wait_interval_->length); | 828 NotifyRetryTime(base::Time::Now() + wait_interval_->length); |
815 | 829 |
816 for (auto& observer : *cycle_context_->listeners()) { | 830 for (auto& observer : *cycle_context_->listeners()) { |
817 observer.OnThrottledTypesChanged(ModelTypeSet::All()); | 831 observer.OnThrottledTypesChanged(ModelTypeSet::All()); |
818 } | 832 } |
819 } | 833 } |
820 | 834 |
821 void SyncSchedulerImpl::OnTypesThrottled(ModelTypeSet types, | 835 void SyncSchedulerImpl::OnTypesThrottled(ModelTypeSet types, |
822 const TimeDelta& throttle_duration) { | 836 const TimeDelta& throttle_duration) { |
| 837 DCHECK(CalledOnValidThread()); |
| 838 |
823 TimeTicks now = TimeTicks::Now(); | 839 TimeTicks now = TimeTicks::Now(); |
824 | 840 |
825 SDVLOG(1) << "Throttling " << ModelTypeSetToString(types) << " for " | 841 SDVLOG(1) << "Throttling " << ModelTypeSetToString(types) << " for " |
826 << throttle_duration.InMinutes() << " minutes."; | 842 << throttle_duration.InMinutes() << " minutes."; |
827 | 843 |
828 nudge_tracker_.SetTypesThrottledUntil(types, throttle_duration, now); | 844 nudge_tracker_.SetTypesThrottledUntil(types, throttle_duration, now); |
829 RestartWaiting(); | |
830 NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes()); | 845 NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes()); |
831 } | 846 } |
832 | 847 |
833 void SyncSchedulerImpl::OnTypesBackedOff(ModelTypeSet types) { | 848 void SyncSchedulerImpl::OnTypesBackedOff(ModelTypeSet types) { |
| 849 DCHECK(CalledOnValidThread()); |
| 850 |
834 TimeTicks now = TimeTicks::Now(); | 851 TimeTicks now = TimeTicks::Now(); |
835 | 852 |
836 for (ModelTypeSet::Iterator type = types.First(); type.Good(); type.Inc()) { | 853 for (ModelTypeSet::Iterator type = types.First(); type.Good(); type.Inc()) { |
837 TimeDelta last_backoff_time = | 854 TimeDelta last_backoff_time = |
838 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds); | 855 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds); |
839 if (nudge_tracker_.GetTypeBlockingMode(type.Get()) == | 856 if (nudge_tracker_.GetTypeBlockingMode(type.Get()) == |
840 WaitInterval::EXPONENTIAL_BACKOFF_RETRYING) { | 857 WaitInterval::EXPONENTIAL_BACKOFF_RETRYING) { |
841 last_backoff_time = nudge_tracker_.GetTypeLastBackoffInterval(type.Get()); | 858 last_backoff_time = nudge_tracker_.GetTypeLastBackoffInterval(type.Get()); |
842 } | 859 } |
843 | 860 |
844 TimeDelta length = delay_provider_->GetDelay(last_backoff_time); | 861 TimeDelta length = delay_provider_->GetDelay(last_backoff_time); |
845 nudge_tracker_.SetTypeBackedOff(type.Get(), length, now); | 862 nudge_tracker_.SetTypeBackedOff(type.Get(), length, now); |
846 SDVLOG(1) << "Backing off " << ModelTypeToString(type.Get()) << " for " | 863 SDVLOG(1) << "Backing off " << ModelTypeToString(type.Get()) << " for " |
847 << length.InSeconds() << " second."; | 864 << length.InSeconds() << " second."; |
848 } | 865 } |
849 RestartWaiting(); | |
850 NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes()); | 866 NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes()); |
851 } | 867 } |
852 | 868 |
853 bool SyncSchedulerImpl::IsCurrentlyThrottled() { | 869 bool SyncSchedulerImpl::IsCurrentlyThrottled() { |
854 DCHECK(CalledOnValidThread()); | 870 DCHECK(CalledOnValidThread()); |
| 871 |
855 return wait_interval_.get() && | 872 return wait_interval_.get() && |
856 wait_interval_->mode == WaitInterval::THROTTLED; | 873 wait_interval_->mode == WaitInterval::THROTTLED; |
857 } | 874 } |
858 | 875 |
859 void SyncSchedulerImpl::OnReceivedShortPollIntervalUpdate( | 876 void SyncSchedulerImpl::OnReceivedShortPollIntervalUpdate( |
860 const TimeDelta& new_interval) { | 877 const TimeDelta& new_interval) { |
861 DCHECK(CalledOnValidThread()); | 878 DCHECK(CalledOnValidThread()); |
| 879 |
862 if (new_interval == syncer_short_poll_interval_seconds_) | 880 if (new_interval == syncer_short_poll_interval_seconds_) |
863 return; | 881 return; |
864 SDVLOG(1) << "Updating short poll interval to " << new_interval.InMinutes() | 882 SDVLOG(1) << "Updating short poll interval to " << new_interval.InMinutes() |
865 << " minutes."; | 883 << " minutes."; |
866 syncer_short_poll_interval_seconds_ = new_interval; | 884 syncer_short_poll_interval_seconds_ = new_interval; |
867 AdjustPolling(UPDATE_INTERVAL); | 885 AdjustPolling(UPDATE_INTERVAL); |
868 } | 886 } |
869 | 887 |
870 void SyncSchedulerImpl::OnReceivedLongPollIntervalUpdate( | 888 void SyncSchedulerImpl::OnReceivedLongPollIntervalUpdate( |
871 const TimeDelta& new_interval) { | 889 const TimeDelta& new_interval) { |
872 DCHECK(CalledOnValidThread()); | 890 DCHECK(CalledOnValidThread()); |
| 891 |
873 if (new_interval == syncer_long_poll_interval_seconds_) | 892 if (new_interval == syncer_long_poll_interval_seconds_) |
874 return; | 893 return; |
875 SDVLOG(1) << "Updating long poll interval to " << new_interval.InMinutes() | 894 SDVLOG(1) << "Updating long poll interval to " << new_interval.InMinutes() |
876 << " minutes."; | 895 << " minutes."; |
877 syncer_long_poll_interval_seconds_ = new_interval; | 896 syncer_long_poll_interval_seconds_ = new_interval; |
878 AdjustPolling(UPDATE_INTERVAL); | 897 AdjustPolling(UPDATE_INTERVAL); |
879 } | 898 } |
880 | 899 |
881 void SyncSchedulerImpl::OnReceivedCustomNudgeDelays( | 900 void SyncSchedulerImpl::OnReceivedCustomNudgeDelays( |
882 const std::map<ModelType, TimeDelta>& nudge_delays) { | 901 const std::map<ModelType, TimeDelta>& nudge_delays) { |
883 DCHECK(CalledOnValidThread()); | 902 DCHECK(CalledOnValidThread()); |
| 903 |
884 nudge_tracker_.OnReceivedCustomNudgeDelays(nudge_delays); | 904 nudge_tracker_.OnReceivedCustomNudgeDelays(nudge_delays); |
885 } | 905 } |
886 | 906 |
887 void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) { | 907 void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) { |
| 908 DCHECK(CalledOnValidThread()); |
| 909 |
888 if (size > 0) | 910 if (size > 0) |
889 nudge_tracker_.SetHintBufferSize(size); | 911 nudge_tracker_.SetHintBufferSize(size); |
890 else | 912 else |
891 NOTREACHED() << "Hint buffer size should be > 0."; | 913 NOTREACHED() << "Hint buffer size should be > 0."; |
892 } | 914 } |
893 | 915 |
894 void SyncSchedulerImpl::OnSyncProtocolError( | 916 void SyncSchedulerImpl::OnSyncProtocolError( |
895 const SyncProtocolError& sync_protocol_error) { | 917 const SyncProtocolError& sync_protocol_error) { |
896 DCHECK(CalledOnValidThread()); | 918 DCHECK(CalledOnValidThread()); |
| 919 |
897 if (ShouldRequestEarlyExit(sync_protocol_error)) { | 920 if (ShouldRequestEarlyExit(sync_protocol_error)) { |
898 SDVLOG(2) << "Sync Scheduler requesting early exit."; | 921 SDVLOG(2) << "Sync Scheduler requesting early exit."; |
899 Stop(); | 922 Stop(); |
900 } | 923 } |
901 if (IsActionableError(sync_protocol_error)) { | 924 if (IsActionableError(sync_protocol_error)) { |
902 SDVLOG(2) << "OnActionableError"; | 925 SDVLOG(2) << "OnActionableError"; |
903 for (auto& observer : *cycle_context_->listeners()) | 926 for (auto& observer : *cycle_context_->listeners()) |
904 observer.OnActionableError(sync_protocol_error); | 927 observer.OnActionableError(sync_protocol_error); |
905 } | 928 } |
906 } | 929 } |
907 | 930 |
908 void SyncSchedulerImpl::OnReceivedGuRetryDelay(const TimeDelta& delay) { | 931 void SyncSchedulerImpl::OnReceivedGuRetryDelay(const TimeDelta& delay) { |
| 932 DCHECK(CalledOnValidThread()); |
| 933 |
909 nudge_tracker_.SetNextRetryTime(TimeTicks::Now() + delay); | 934 nudge_tracker_.SetNextRetryTime(TimeTicks::Now() + delay); |
910 retry_timer_.Start(FROM_HERE, delay, this, | 935 retry_timer_.Start(FROM_HERE, delay, this, |
911 &SyncSchedulerImpl::RetryTimerCallback); | 936 &SyncSchedulerImpl::RetryTimerCallback); |
912 } | 937 } |
913 | 938 |
914 void SyncSchedulerImpl::OnReceivedMigrationRequest(ModelTypeSet types) { | 939 void SyncSchedulerImpl::OnReceivedMigrationRequest(ModelTypeSet types) { |
| 940 DCHECK(CalledOnValidThread()); |
| 941 |
915 for (auto& observer : *cycle_context_->listeners()) | 942 for (auto& observer : *cycle_context_->listeners()) |
916 observer.OnMigrationRequested(types); | 943 observer.OnMigrationRequested(types); |
917 } | 944 } |
918 | 945 |
919 void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) { | 946 void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) { |
920 DCHECK(CalledOnValidThread()); | 947 DCHECK(CalledOnValidThread()); |
| 948 |
921 cycle_context_->set_notifications_enabled(notifications_enabled); | 949 cycle_context_->set_notifications_enabled(notifications_enabled); |
922 if (notifications_enabled) | 950 if (notifications_enabled) |
923 nudge_tracker_.OnInvalidationsEnabled(); | 951 nudge_tracker_.OnInvalidationsEnabled(); |
924 else | 952 else |
925 nudge_tracker_.OnInvalidationsDisabled(); | 953 nudge_tracker_.OnInvalidationsDisabled(); |
926 } | 954 } |
927 | 955 |
| 956 bool SyncSchedulerImpl::IsEarlierThanCurrentPendingJob(const TimeDelta& delay) { |
| 957 TimeTicks incoming_run_time = TimeTicks::Now() + delay; |
| 958 if (pending_wakeup_timer_.IsRunning() && |
| 959 (pending_wakeup_timer_.desired_run_time() < incoming_run_time)) { |
| 960 // Old job arrives sooner than this one. |
| 961 return false; |
| 962 } |
| 963 return true; |
| 964 } |
| 965 |
928 #undef SDVLOG_LOC | 966 #undef SDVLOG_LOC |
929 | 967 |
930 #undef SDVLOG | 968 #undef SDVLOG |
931 | 969 |
932 #undef SLOG | 970 #undef SLOG |
933 | 971 |
934 #undef ENUM_CASE | 972 #undef ENUM_CASE |
935 | 973 |
936 } // namespace syncer | 974 } // namespace syncer |
OLD | NEW |