| Index: components/sync/engine_impl/sync_scheduler_impl.cc
|
| diff --git a/components/sync/engine_impl/sync_scheduler_impl.cc b/components/sync/engine_impl/sync_scheduler_impl.cc
|
| index 96e6d202fb36fbd4957c4216db4c8d2a28cf39ae..4c5ebce331ecb2822cb4c6f3718f6af60dbc9d1b 100644
|
| --- a/components/sync/engine_impl/sync_scheduler_impl.cc
|
| +++ b/components/sync/engine_impl/sync_scheduler_impl.cc
|
| @@ -149,6 +149,7 @@ SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name,
|
|
|
| SyncSchedulerImpl::~SyncSchedulerImpl() {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| Stop();
|
| }
|
|
|
| @@ -162,6 +163,8 @@ void SyncSchedulerImpl::OnCredentialsUpdated() {
|
| }
|
|
|
| void SyncSchedulerImpl::OnConnectionStatusChange() {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| if (HttpResponse::CONNECTION_UNAVAILABLE ==
|
| cycle_context_->connection_manager()->server_status()) {
|
| // Optimistically assume that the connection is fixed and try
|
| @@ -187,6 +190,7 @@ void SyncSchedulerImpl::OnServerConnectionErrorFixed() {
|
|
|
| void SyncSchedulerImpl::Start(Mode mode, base::Time last_poll_time) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| std::string thread_name = base::PlatformThread::GetName();
|
| if (thread_name.empty())
|
| thread_name = "<Main thread>";
|
| @@ -239,6 +243,7 @@ ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnblockedTypes() {
|
|
|
| void SyncSchedulerImpl::SendInitialSnapshot() {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| SyncCycleEvent event(SyncCycleEvent::STATUS_CHANGED);
|
| event.snapshot = SyncCycle(cycle_context_, this).TakeSnapshot();
|
| for (auto& observer : *cycle_context_->listeners())
|
| @@ -274,12 +279,14 @@ void SyncSchedulerImpl::ScheduleClearServerData(const ClearParams& params) {
|
| DCHECK(!pending_configure_params_);
|
| DCHECK(!params.report_success_task.is_null());
|
| CHECK(started_) << "Scheduler must be running to clear.";
|
| +
|
| pending_clear_params_ = base::MakeUnique<ClearParams>(params);
|
| TrySyncCycleJob();
|
| }
|
|
|
| bool SyncSchedulerImpl::CanRunJobNow(JobPriority priority) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| if (IsCurrentlyThrottled()) {
|
| SDVLOG(1) << "Unable to run a job because we're throttled.";
|
| return false;
|
| @@ -391,9 +398,7 @@ void SyncSchedulerImpl::ScheduleNudgeImpl(
|
| if (!CanRunNudgeJobNow(NORMAL_PRIORITY))
|
| return;
|
|
|
| - TimeTicks incoming_run_time = TimeTicks::Now() + delay;
|
| - if (pending_wakeup_timer_.IsRunning() &&
|
| - (pending_wakeup_timer_.desired_run_time() < incoming_run_time)) {
|
| + if (!IsEarlierThanCurrentPendingJob(delay)) {
|
| // Old job arrives sooner than this one. Don't reschedule it.
|
| return;
|
| }
|
| @@ -419,6 +424,7 @@ const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) {
|
|
|
| void SyncSchedulerImpl::SetDefaultNudgeDelay(TimeDelta delay_ms) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| nudge_tracker_.SetDefaultNudgeDelay(delay_ms);
|
| }
|
|
|
| @@ -531,7 +537,6 @@ void SyncSchedulerImpl::HandleFailure(
|
| SDVLOG(2) << "Sync cycle failed. Will back off for "
|
| << wait_interval_->length.InMilliseconds() << "ms.";
|
| }
|
| - RestartWaiting();
|
| }
|
|
|
| void SyncSchedulerImpl::DoPollSyncCycleJob() {
|
| @@ -552,6 +557,7 @@ void SyncSchedulerImpl::DoPollSyncCycleJob() {
|
|
|
| void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| TimeTicks now = TimeTicks::Now();
|
| // Update timing information for how often datatypes are triggering nudges.
|
| for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
|
| @@ -576,6 +582,7 @@ TimeDelta SyncSchedulerImpl::GetPollInterval() {
|
|
|
| void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| if (!started_)
|
| return;
|
|
|
| @@ -619,7 +626,16 @@ void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) {
|
|
|
| void SyncSchedulerImpl::RestartWaiting() {
|
| if (wait_interval_.get()) {
|
| - // Global throttling or backoff
|
| + // Global throttling or backoff.
|
| + if (!IsEarlierThanCurrentPendingJob(wait_interval_->length)) {
|
| + // We check here because if we do not check here, and we already scheduled
|
| + // a global unblock job, we will schedule another unblock job which has
|
| + // same waiting time, then the job will be run later than expected. Even
|
| + // we did not schedule an unblock job when code reach here, it is ok since
|
| + // |TrySyncCycleJobImpl| will call this function after the scheduled job
|
| + // got run.
|
| + return;
|
| + }
|
| NotifyRetryTime(base::Time::Now() + wait_interval_->length);
|
| SDVLOG(2) << "Starting WaitInterval timer of length "
|
| << wait_interval_->length.InMilliseconds() << "ms.";
|
| @@ -637,6 +653,9 @@ void SyncSchedulerImpl::RestartWaiting() {
|
| // Per-datatype throttled or backed off.
|
| TimeDelta time_until_next_unblock =
|
| nudge_tracker_.GetTimeUntilNextUnblock();
|
| + if (!IsEarlierThanCurrentPendingJob(time_until_next_unblock)) {
|
| + return;
|
| + }
|
| pending_wakeup_timer_.Start(FROM_HERE, time_until_next_unblock,
|
| base::Bind(&SyncSchedulerImpl::OnTypesUnblocked,
|
| weak_ptr_factory_.GetWeakPtr()));
|
| @@ -676,12 +695,13 @@ void SyncSchedulerImpl::TrySyncCycleJob() {
|
| }
|
|
|
| void SyncSchedulerImpl::TrySyncCycleJobImpl() {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| JobPriority priority = next_sync_cycle_job_priority_;
|
| next_sync_cycle_job_priority_ = NORMAL_PRIORITY;
|
|
|
| nudge_tracker_.SetSyncCycleStartTime(TimeTicks::Now());
|
|
|
| - DCHECK(CalledOnValidThread());
|
| if (mode_ == CONFIGURATION_MODE) {
|
| if (pending_configure_params_) {
|
| SDVLOG(2) << "Found pending configure job";
|
| @@ -706,17 +726,7 @@ void SyncSchedulerImpl::TrySyncCycleJobImpl() {
|
| cycle_context_->connection_manager()->HasInvalidAuthToken());
|
| }
|
|
|
| - if (IsBackingOff() && !pending_wakeup_timer_.IsRunning()) {
|
| - // If we succeeded, our wait interval would have been cleared. If it hasn't
|
| - // been cleared, then we should increase our backoff interval and schedule
|
| - // another retry.
|
| - TimeDelta length = delay_provider_->GetDelay(wait_interval_->length);
|
| - wait_interval_ = base::MakeUnique<WaitInterval>(
|
| - WaitInterval::EXPONENTIAL_BACKOFF, length);
|
| - SDVLOG(2) << "Sync cycle failed. Will back off for "
|
| - << wait_interval_->length.InMilliseconds() << "ms.";
|
| - RestartWaiting();
|
| - }
|
| + RestartWaiting();
|
| }
|
|
|
| void SyncSchedulerImpl::PollTimerCallback() {
|
| @@ -749,14 +759,16 @@ void SyncSchedulerImpl::Unthrottle() {
|
|
|
| void SyncSchedulerImpl::OnTypesUnblocked() {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| nudge_tracker_.UpdateTypeThrottlingAndBackoffState();
|
| NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes());
|
|
|
| - RestartWaiting();
|
| -
|
| // Maybe this is a good time to run a nudge job. Let's try it.
|
| + // If not a good time, reschedule a new run.
|
| if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(NORMAL_PRIORITY))
|
| TrySyncCycleJob();
|
| + else
|
| + RestartWaiting();
|
| }
|
|
|
| void SyncSchedulerImpl::PerformDelayedNudge() {
|
| @@ -803,12 +815,14 @@ void SyncSchedulerImpl::NotifyBlockedTypesChanged(ModelTypeSet types) {
|
|
|
| bool SyncSchedulerImpl::IsBackingOff() const {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| return wait_interval_.get() &&
|
| wait_interval_->mode == WaitInterval::EXPONENTIAL_BACKOFF;
|
| }
|
|
|
| void SyncSchedulerImpl::OnThrottled(const TimeDelta& throttle_duration) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| wait_interval_ = base::MakeUnique<WaitInterval>(WaitInterval::THROTTLED,
|
| throttle_duration);
|
| NotifyRetryTime(base::Time::Now() + wait_interval_->length);
|
| @@ -820,17 +834,20 @@ void SyncSchedulerImpl::OnThrottled(const TimeDelta& throttle_duration) {
|
|
|
| void SyncSchedulerImpl::OnTypesThrottled(ModelTypeSet types,
|
| const TimeDelta& throttle_duration) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| TimeTicks now = TimeTicks::Now();
|
|
|
| SDVLOG(1) << "Throttling " << ModelTypeSetToString(types) << " for "
|
| << throttle_duration.InMinutes() << " minutes.";
|
|
|
| nudge_tracker_.SetTypesThrottledUntil(types, throttle_duration, now);
|
| - RestartWaiting();
|
| NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes());
|
| }
|
|
|
| void SyncSchedulerImpl::OnTypesBackedOff(ModelTypeSet types) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| TimeTicks now = TimeTicks::Now();
|
|
|
| for (ModelTypeSet::Iterator type = types.First(); type.Good(); type.Inc()) {
|
| @@ -846,12 +863,12 @@ void SyncSchedulerImpl::OnTypesBackedOff(ModelTypeSet types) {
|
| SDVLOG(1) << "Backing off " << ModelTypeToString(type.Get()) << " for "
|
| << length.InSeconds() << " second.";
|
| }
|
| - RestartWaiting();
|
| NotifyBlockedTypesChanged(nudge_tracker_.GetBlockedTypes());
|
| }
|
|
|
| bool SyncSchedulerImpl::IsCurrentlyThrottled() {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| return wait_interval_.get() &&
|
| wait_interval_->mode == WaitInterval::THROTTLED;
|
| }
|
| @@ -859,6 +876,7 @@ bool SyncSchedulerImpl::IsCurrentlyThrottled() {
|
| void SyncSchedulerImpl::OnReceivedShortPollIntervalUpdate(
|
| const TimeDelta& new_interval) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| if (new_interval == syncer_short_poll_interval_seconds_)
|
| return;
|
| SDVLOG(1) << "Updating short poll interval to " << new_interval.InMinutes()
|
| @@ -870,6 +888,7 @@ void SyncSchedulerImpl::OnReceivedShortPollIntervalUpdate(
|
| void SyncSchedulerImpl::OnReceivedLongPollIntervalUpdate(
|
| const TimeDelta& new_interval) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| if (new_interval == syncer_long_poll_interval_seconds_)
|
| return;
|
| SDVLOG(1) << "Updating long poll interval to " << new_interval.InMinutes()
|
| @@ -881,10 +900,13 @@ void SyncSchedulerImpl::OnReceivedLongPollIntervalUpdate(
|
| void SyncSchedulerImpl::OnReceivedCustomNudgeDelays(
|
| const std::map<ModelType, TimeDelta>& nudge_delays) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| nudge_tracker_.OnReceivedCustomNudgeDelays(nudge_delays);
|
| }
|
|
|
| void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| if (size > 0)
|
| nudge_tracker_.SetHintBufferSize(size);
|
| else
|
| @@ -894,6 +916,7 @@ void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) {
|
| void SyncSchedulerImpl::OnSyncProtocolError(
|
| const SyncProtocolError& sync_protocol_error) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| if (ShouldRequestEarlyExit(sync_protocol_error)) {
|
| SDVLOG(2) << "Sync Scheduler requesting early exit.";
|
| Stop();
|
| @@ -906,18 +929,23 @@ void SyncSchedulerImpl::OnSyncProtocolError(
|
| }
|
|
|
| void SyncSchedulerImpl::OnReceivedGuRetryDelay(const TimeDelta& delay) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| nudge_tracker_.SetNextRetryTime(TimeTicks::Now() + delay);
|
| retry_timer_.Start(FROM_HERE, delay, this,
|
| &SyncSchedulerImpl::RetryTimerCallback);
|
| }
|
|
|
| void SyncSchedulerImpl::OnReceivedMigrationRequest(ModelTypeSet types) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| for (auto& observer : *cycle_context_->listeners())
|
| observer.OnMigrationRequested(types);
|
| }
|
|
|
| void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| cycle_context_->set_notifications_enabled(notifications_enabled);
|
| if (notifications_enabled)
|
| nudge_tracker_.OnInvalidationsEnabled();
|
| @@ -925,6 +953,16 @@ void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) {
|
| nudge_tracker_.OnInvalidationsDisabled();
|
| }
|
|
|
| +bool SyncSchedulerImpl::IsEarlierThanCurrentPendingJob(const TimeDelta& delay) {
|
| + TimeTicks incoming_run_time = TimeTicks::Now() + delay;
|
| + if (pending_wakeup_timer_.IsRunning() &&
|
| + (pending_wakeup_timer_.desired_run_time() < incoming_run_time)) {
|
| + // Old job arrives sooner than this one.
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| #undef SDVLOG_LOC
|
|
|
| #undef SDVLOG
|
|
|