Chromium Code Reviews| Index: sync/engine/sync_scheduler_impl.cc |
| diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc |
| index b03b3c85bb16613012941a5627f6a7425922c3f7..527f8ef416c4dc12cf63dba4d81cd7bfb654ae9d 100644 |
| --- a/sync/engine/sync_scheduler_impl.cc |
| +++ b/sync/engine/sync_scheduler_impl.cc |
| @@ -225,9 +225,9 @@ void SyncSchedulerImpl::Start(Mode mode) { |
| DCHECK(syncer_.get()); |
| Mode old_mode = mode_; |
| mode_ = mode; |
| - AdjustPolling(NULL); // Will kick start poll timer if needed. |
| + RestartPollTimerIfRateChanged(); // Will kick start poll timer if needed. |
| - if (old_mode != mode_ && mode_ == NORMAL_MODE && pending_nudge_job_) { |
| + if (old_mode != mode_ && mode_ == NORMAL_MODE && !nudge_tracker_.IsEmpty()) { |
| // We just got back to normal mode. Let's try to run the work that was |
| // queued up while we were configuring. |
| DoNudgeSyncSessionJob(NORMAL_PRIORITY); |
| @@ -274,7 +274,7 @@ bool SyncSchedulerImpl::ScheduleConfiguration( |
| // Only one configuration is allowed at a time. Verify we're not waiting |
| // for a pending configure job. |
| - DCHECK(!pending_configure_job_); |
| + DCHECK(!pending_configure_params_); |
| ModelSafeRoutingInfo restricted_routes; |
| BuildModelSafeParams(params.types_to_download, |
| @@ -284,25 +284,17 @@ bool SyncSchedulerImpl::ScheduleConfiguration( |
| // Only reconfigure if we have types to download. |
| if (!params.types_to_download.Empty()) { |
| - DCHECK(!restricted_routes.empty()); |
| - pending_configure_job_.reset(new SyncSessionJob( |
| - SyncSessionJob::CONFIGURATION, |
| - TimeTicks::Now(), |
| - SyncSourceInfo(params.source, |
| - ModelSafeRoutingInfoToInvalidationMap( |
| - restricted_routes, |
| - std::string())), |
| - params)); |
| + pending_configure_params_.reset(new ConfigurationParams(params)); |
| bool succeeded = DoConfigurationSyncSessionJob(NORMAL_PRIORITY); |
| // If we failed, the job would have been saved as the pending configure |
| // job and a wait interval would have been set. |
| if (!succeeded) { |
| - DCHECK(pending_configure_job_); |
| - return false; |
| + DCHECK(pending_configure_params_); |
| } else { |
| - DCHECK(!pending_configure_job_); |
| + DCHECK(!pending_configure_params_); |
| } |
| + return succeeded; |
| } else { |
| SDVLOG(2) << "No change in routing info, calling ready task directly."; |
| params.ready_task.Run(); |
| @@ -311,120 +303,55 @@ bool SyncSchedulerImpl::ScheduleConfiguration( |
| return true; |
| } |
| -SyncSchedulerImpl::JobProcessDecision |
| -SyncSchedulerImpl::DecideWhileInWaitInterval(const SyncSessionJob& job, |
| - JobPriority priority) { |
| +bool SyncSchedulerImpl::CanRunJobNow(JobPriority priority) { |
| DCHECK(CalledOnValidThread()); |
| - DCHECK(wait_interval_.get()); |
| - DCHECK_NE(job.purpose(), SyncSessionJob::POLL); |
| - |
| - SDVLOG(2) << "DecideWhileInWaitInterval with WaitInterval mode " |
| - << WaitInterval::GetModeString(wait_interval_->mode) |
| - << ((priority == CANARY_PRIORITY) ? " (canary)" : ""); |
| - |
| - // If we save a job while in a WaitInterval, there is a well-defined moment |
| - // in time in the future when it makes sense for that SAVE-worthy job to try |
| - // running again -- the end of the WaitInterval. |
| - DCHECK(job.purpose() == SyncSessionJob::NUDGE || |
| - job.purpose() == SyncSessionJob::CONFIGURATION); |
| - |
| - // If throttled, there's a clock ticking to unthrottle. We want to get |
| - // on the same train. |
| - if (wait_interval_->mode == WaitInterval::THROTTLED) |
| - return SAVE; |
| + if (wait_interval_ && wait_interval_->mode == WaitInterval::THROTTLED) { |
| + SDVLOG(1) << "Unable to run a job because we're throttled."; |
| + return false; |
| + } |
| - DCHECK_EQ(wait_interval_->mode, WaitInterval::EXPONENTIAL_BACKOFF); |
| - if (job.purpose() == SyncSessionJob::NUDGE) { |
| - if (mode_ == CONFIGURATION_MODE) |
| - return SAVE; |
| + if (wait_interval_ |
| + && wait_interval_->mode == WaitInterval::EXPONENTIAL_BACKOFF |
| + && priority != CANARY_PRIORITY) { |
| + SDVLOG(1) << "Unable to run a job because we're backing off."; |
| + return false; |
| + } |
| - if (priority == NORMAL_PRIORITY) |
| - return DROP; |
| - else // Either backoff has ended, or we have permission to bypass it. |
| - return CONTINUE; |
| + if (session_context_->connection_manager()->HasInvalidAuthToken()) { |
| + SDVLOG(1) << "Unable to run a job because we have no valid auth token."; |
| + return false; |
| } |
| - return (priority == CANARY_PRIORITY) ? CONTINUE : SAVE; |
| + |
| + return true; |
| } |
| -SyncSchedulerImpl::JobProcessDecision SyncSchedulerImpl::DecideOnJob( |
| - const SyncSessionJob& job, |
| - JobPriority priority) { |
| +bool SyncSchedulerImpl::CanRunNudgeJobNow(JobPriority priority) { |
| DCHECK(CalledOnValidThread()); |
| - // POLL jobs do not call this function. |
| - DCHECK(job.purpose() == SyncSessionJob::NUDGE || |
| - job.purpose() == SyncSessionJob::CONFIGURATION); |
| + if (!CanRunJobNow(priority)) { |
| + SDVLOG(1) << "Unable to run a nudge job right now"; |
| + return false; |
| + } |
| - // See if our type is throttled. |
| + // If all types are throttled, do not continue. Today, we don't treat a |
| + // per-datatype "unthrottle" event as something that should force a canary |
| + // job. For this reason, there's no good time to reschedule this job to run |
| + // -- we'll lazily wait for an independent event to trigger a sync. |
| ModelTypeSet throttled_types = |
| session_context_->throttled_data_type_tracker()->GetThrottledTypes(); |
| - if (job.purpose() == SyncSessionJob::NUDGE && |
| - job.source_info().updates_source == GetUpdatesCallerInfo::LOCAL) { |
| - ModelTypeSet requested_types; |
| - for (ModelTypeInvalidationMap::const_iterator i = |
| - job.source_info().types.begin(); i != job.source_info().types.end(); |
| - ++i) { |
| - requested_types.Put(i->first); |
| - } |
| - |
| - // If all types are throttled, do not CONTINUE. Today, we don't treat |
| - // a per-datatype "unthrottle" event as something that should force a |
| - // canary job. For this reason, there's no good time to reschedule this job |
| - // to run -- we'll lazily wait for an independent event to trigger a sync. |
| - // Note that there may already be such an event if we're in a WaitInterval, |
| - // so we can retry it then. |
| - if (!requested_types.Empty() && throttled_types.HasAll(requested_types)) |
| - return DROP; // TODO(tim): Don't drop. http://crbug.com/177659 |
| + if (!nudge_tracker_.GetLocallyModifiedTypes().Empty() && |
| + throttled_types.HasAll(nudge_tracker_.GetLocallyModifiedTypes())) { |
| + // TODO(sync): Throttled types should be pruned from the sources list. |
| + SDVLOG(1) << "Not running a nudge because we're fully datatype throttled."; |
| + return false; |
| } |
| - if (wait_interval_.get()) |
| - return DecideWhileInWaitInterval(job, priority); |
| - |
| if (mode_ == CONFIGURATION_MODE) { |
| - if (job.purpose() == SyncSessionJob::NUDGE) |
| - return SAVE; // Running requires a mode switch. |
| - else // Implies job.purpose() == SyncSessionJob::CONFIGURATION. |
| - return CONTINUE; |
| + SDVLOG(1) << "Not running nudge because we're in configuration mode."; |
| + return false; |
| } |
| - // We are in normal mode. |
| - DCHECK_EQ(mode_, NORMAL_MODE); |
| - DCHECK_NE(job.purpose(), SyncSessionJob::CONFIGURATION); |
| - |
| - // Note about some subtle scheduling semantics. |
| - // |
| - // It's possible at this point that |job| is known to be unnecessary, and |
| - // dropping it would be perfectly safe and correct. Consider |
| - // |
| - // 1) |job| is a NUDGE (for any combination of types) with a |
| - // |scheduled_start| time that is less than the time that the last |
| - // successful all-datatype NUDGE completed, and it has a NOTIFICATION |
| - // GetUpdatesCallerInfo value yet offers no new notification hint. |
| - // |
| - // 2) |job| is a NUDGE with a |scheduled_start| time that is less than |
| - // the time that the last successful matching-datatype NUDGE completed, |
| - // and payloads (hints) are identical to that last successful NUDGE. |
| - // |
| - // We avoid cases 1 and 2 by externally synchronizing NUDGE requests -- |
| - // scheduling a NUDGE requires command of the sync thread, which is |
| - // impossible* from outside of SyncScheduler if a NUDGE is taking place. |
| - // And if you have command of the sync thread when scheduling a NUDGE and a |
| - // previous NUDGE exists, they will be coalesced and the stale job will be |
| - // cancelled via the session-equality check in DoSyncSessionJob. |
| - // |
| - // * It's not strictly "impossible", but it would be reentrant and hence |
| - // illegal. e.g. scheduling a job and re-entering the SyncScheduler is NOT a |
| - // legal side effect of any of the work being done as part of a sync cycle. |
| - // See |no_scheduling_allowed_| for details. |
| - |
| - // Decision now rests on state of auth tokens. |
| - if (!session_context_->connection_manager()->HasInvalidAuthToken()) |
| - return CONTINUE; |
| - |
| - SDVLOG(2) << "No valid auth token. Using that to decide on job."; |
| - // Running the job would require updated auth, so we can't honour |
| - // job.scheduled_start(). |
| - return job.purpose() == SyncSessionJob::NUDGE ? SAVE : DROP; |
| + return true; |
| } |
| void SyncSchedulerImpl::ScheduleNudgeAsync( |
| @@ -496,53 +423,38 @@ void SyncSchedulerImpl::ScheduleNudgeImpl( |
| SyncSourceInfo info(source, invalidation_map); |
| UpdateNudgeTimeRecords(info); |
| - scoped_ptr<SyncSessionJob> job(new SyncSessionJob( |
| - SyncSessionJob::NUDGE, |
| - TimeTicks::Now() + delay, |
| - info, |
| - ConfigurationParams())); |
| - JobProcessDecision decision = DecideOnJob(*job, NORMAL_PRIORITY); |
| - SDVLOG(2) << "Should run " |
| - << SyncSessionJob::GetPurposeString(job->purpose()) |
| - << " in mode " << GetModeString(mode_) |
| - << ": " << GetDecisionString(decision); |
| - if (decision == DROP) { |
| + // Coalesce the new nudge information with any existing information. |
| + nudge_tracker_.CoalesceSources(info); |
| + |
| + if (!CanRunNudgeJobNow(NORMAL_PRIORITY)) |
| return; |
| - } |
| - // Try to coalesce in both SAVE and CONTINUE cases. |
| - if (pending_nudge_job_) { |
| - pending_nudge_job_->CoalesceSources(job->source_info()); |
| - if (decision == CONTINUE) { |
| - // Only update the scheduled_start if we're going to reschedule. |
| - pending_nudge_job_->set_scheduled_start( |
| - std::min(job->scheduled_start(), |
| - pending_nudge_job_->scheduled_start())); |
| - } |
| - } else { |
| - pending_nudge_job_ = job.Pass(); |
| + if (!started_) { |
| + SDVLOG_LOC(nudge_location, 2) |
| + << "Schedule not started; not running a nudge."; |
| + return; |
| } |
| - if (decision == SAVE) { |
| + TimeTicks incoming_run_time = TimeTicks::Now() + delay; |
| + if (!scheduled_nudge_time_.is_null() && |
| + (scheduled_nudge_time_ < incoming_run_time)) { |
| + // Old job arrives sooner than this one. Don't reschedule it. |
| return; |
| } |
| - TimeDelta run_delay = |
| - pending_nudge_job_->scheduled_start() - TimeTicks::Now(); |
| - if (run_delay < TimeDelta::FromMilliseconds(0)) |
| - run_delay = TimeDelta::FromMilliseconds(0); |
| + // Either there is no existing nudge in flight or the incoming nudge should be |
| + // made to arrive first (preempt) the existing nudge. We reschedule in either |
| + // case. |
| SDVLOG_LOC(nudge_location, 2) |
| << "Scheduling a nudge with " |
| - << run_delay.InMilliseconds() << " ms delay"; |
| - |
| - if (started_) { |
| - pending_wakeup_timer_.Start( |
| - nudge_location, |
| - run_delay, |
| - base::Bind(&SyncSchedulerImpl::DoNudgeSyncSessionJob, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - NORMAL_PRIORITY)); |
| - } |
| + << delay.InMilliseconds() << " ms delay"; |
| + scheduled_nudge_time_ = incoming_run_time; |
| + pending_wakeup_timer_.Start( |
| + nudge_location, |
| + delay, |
| + base::Bind(&SyncSchedulerImpl::DoNudgeSyncSessionJob, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + NORMAL_PRIORITY)); |
| } |
| const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) { |
| @@ -553,103 +465,88 @@ const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) { |
| return ""; |
| } |
| -const char* SyncSchedulerImpl::GetDecisionString( |
| - SyncSchedulerImpl::JobProcessDecision mode) { |
| - switch (mode) { |
| - ENUM_CASE(CONTINUE); |
| - ENUM_CASE(SAVE); |
| - ENUM_CASE(DROP); |
| - } |
| - return ""; |
| -} |
| - |
| -bool SyncSchedulerImpl::DoSyncSessionJobImpl(scoped_ptr<SyncSessionJob> job, |
| - JobPriority priority) { |
| +void SyncSchedulerImpl::DoNudgeSyncSessionJob(JobPriority priority) { |
| DCHECK(CalledOnValidThread()); |
| - base::AutoReset<bool> protector(&no_scheduling_allowed_, true); |
| - JobProcessDecision decision = DecideOnJob(*job, priority); |
| - SDVLOG(2) << "Should run " |
| - << SyncSessionJob::GetPurposeString(job->purpose()) |
| - << " in mode " << GetModeString(mode_) |
| - << " with source " << job->source_info().updates_source |
| - << ": " << GetDecisionString(decision); |
| - if (decision != CONTINUE) { |
| - if (decision == SAVE) { |
| - if (job->purpose() == SyncSessionJob::CONFIGURATION) { |
| - pending_configure_job_ = job.Pass(); |
| - } else { |
| - pending_nudge_job_ = job.Pass(); |
| - } |
| - } else { |
| - DCHECK_EQ(decision, DROP); |
| - } |
| - return false; |
| - } |
| + if (!CanRunNudgeJobNow(priority)) |
| + return; |
| - DVLOG(2) << "Creating sync session with routes " |
| - << ModelSafeRoutingInfoToString(session_context_->routing_info()) |
| - << "and purpose " << job->purpose(); |
| - SyncSession session(session_context_, this, job->source_info()); |
| - bool premature_exit = !syncer_->SyncShare(&session, |
| - job->start_step(), |
| - job->end_step()); |
| - SDVLOG(2) << "Done SyncShare, returned: " << premature_exit; |
| + DVLOG(2) << "Will run normal mode sync cycle with routing info " |
| + << ModelSafeRoutingInfoToString(session_context_->routing_info()); |
| + SyncSession session(session_context_, this, nudge_tracker_.source_info()); |
| + bool premature_exit = !syncer_->SyncShare(&session, SYNCER_BEGIN, SYNCER_END); |
| + RestartPollTimer(); |
| - bool success = FinishSyncSessionJob(job.get(), |
| - premature_exit, |
| - &session); |
| + bool success = !premature_exit |
| + && !sessions::HasSyncerError( |
| + session.status_controller().model_neutral_state()); |
| - if (IsSyncingCurrentlySilenced()) { |
| - SDVLOG(2) << "We are currently throttled; scheduling Unthrottle."; |
| - // If we're here, it's because |job| was silenced until a server specified |
| - // time. (Note, it had to be |job|, because DecideOnJob would not permit |
| - // any job through while in WaitInterval::THROTTLED). |
| - if (job->purpose() == SyncSessionJob::NUDGE) |
| - pending_nudge_job_ = job.Pass(); |
| - else if (job->purpose() == SyncSessionJob::CONFIGURATION) |
| - pending_configure_job_ = job.Pass(); |
| - else |
| - NOTREACHED(); |
| + if (success) { |
| + // That cycle took care of any outstanding work we had. |
| + SDVLOG(2) << "Nudge succeeded."; |
| + nudge_tracker_.Reset(); |
| + scheduled_nudge_time_ = base::TimeTicks(); |
| - RestartWaiting(); |
| - return success; |
| + // If we're here, then we successfully reached the server. End all backoff. |
| + wait_interval_.reset(); |
| + NotifyRetryTime(base::Time()); |
| + return; |
| + } else { |
| + HandleFailure(session.status_controller().model_neutral_state()); |
| } |
| - |
| - if (!success) |
| - ScheduleNextSync(job.Pass(), &session); |
| - |
| - return success; |
| -} |
| - |
| -void SyncSchedulerImpl::DoNudgeSyncSessionJob(JobPriority priority) { |
| - DoSyncSessionJobImpl(pending_nudge_job_.Pass(), priority); |
| } |
| bool SyncSchedulerImpl::DoConfigurationSyncSessionJob(JobPriority priority) { |
| - return DoSyncSessionJobImpl(pending_configure_job_.Pass(), priority); |
| -} |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK_EQ(mode_, CONFIGURATION_MODE); |
| -bool SyncSchedulerImpl::ShouldPoll() { |
| - if (wait_interval_.get()) { |
| - SDVLOG(2) << "Not running poll in wait interval."; |
| + if (!CanRunJobNow(priority)) { |
| + SDVLOG(2) << "Unable to run configure job right now."; |
| return false; |
| } |
| - if (mode_ == CONFIGURATION_MODE) { |
| - SDVLOG(2) << "Not running poll in configuration mode."; |
| - return false; |
| - } |
| + SDVLOG(2) << "Will run configure SyncShare with routes " |
| + << ModelSafeRoutingInfoToString(session_context_->routing_info()); |
| + SyncSourceInfo source_info(pending_configure_params_->source, |
| + ModelSafeRoutingInfoToInvalidationMap( |
| + session_context_->routing_info(), |
| + std::string())); |
| + SyncSession session(session_context_, this, source_info); |
| + bool premature_exit = !syncer_->SyncShare(&session, |
| + DOWNLOAD_UPDATES, |
| + APPLY_UPDATES); |
| + RestartPollTimer(); |
| - // TODO(rlarocque): Refactor decision-making logic common to all types |
| - // of jobs into a shared function. |
| + bool success = !premature_exit |
| + && !sessions::HasSyncerError( |
| + session.status_controller().model_neutral_state()); |
| - if (session_context_->connection_manager()->HasInvalidAuthToken()) { |
| - SDVLOG(2) << "Not running poll because auth token is invalid."; |
| + if (success) { |
| + SDVLOG(2) << "Configure succeeded."; |
| + pending_configure_params_->ready_task.Run(); |
| + pending_configure_params_.reset(); |
| + |
| + // If we're here, then we successfully reached the server. End all backoff. |
| + wait_interval_.reset(); |
| + NotifyRetryTime(base::Time()); |
| + return true; |
| + } else { |
| + HandleFailure(session.status_controller().model_neutral_state()); |
| return false; |
| } |
| +} |
| - return true; |
| +void SyncSchedulerImpl::HandleFailure( |
| + const sessions::ModelNeutralState& model_neutral_state) { |
| + if (IsSyncingCurrentlySilenced()) { |
| + SDVLOG(2) << "Was throttled during previous sync cycle."; |
| + RestartWaiting(); |
| + } else { |
| + UpdateExponentialBackoff(model_neutral_state); |
| + SDVLOG(2) << "Sync cycle failed. Will back off for " |
| + << wait_interval_->length.InMilliseconds() << "ms."; |
| + RestartWaiting(); |
| + } |
| } |
| void SyncSchedulerImpl::DoPollSyncSessionJob() { |
| @@ -657,31 +554,29 @@ void SyncSchedulerImpl::DoPollSyncSessionJob() { |
| ModelTypeInvalidationMap invalidation_map = |
| ModelSafeRoutingInfoToInvalidationMap(r, std::string()); |
| SyncSourceInfo info(GetUpdatesCallerInfo::PERIODIC, invalidation_map); |
| - scoped_ptr<SyncSessionJob> job(new SyncSessionJob(SyncSessionJob::POLL, |
| - TimeTicks::Now(), |
| - info, |
| - ConfigurationParams())); |
| - |
| base::AutoReset<bool> protector(&no_scheduling_allowed_, true); |
| - if (!ShouldPoll()) |
| + if (!CanRunJobNow(NORMAL_PRIORITY)) { |
| + SDVLOG(2) << "Unable to run a poll job right now."; |
| return; |
| + } |
| - DVLOG(2) << "Polling with routes " |
| + if (mode_ != NORMAL_MODE) { |
| + SDVLOG(2) << "Not running poll job in configure mode."; |
| + return; |
| + } |
| + |
| + SDVLOG(2) << "Polling with routes " |
| << ModelSafeRoutingInfoToString(session_context_->routing_info()); |
| - SyncSession session(session_context_, this, job->source_info()); |
| - bool premature_exit = !syncer_->SyncShare(&session, |
| - job->start_step(), |
| - job->end_step()); |
| - SDVLOG(2) << "Done SyncShare, returned: " << premature_exit; |
| + SyncSession session(session_context_, this, info); |
| + syncer_->SyncShare(&session, SYNCER_BEGIN, SYNCER_END); |
| - FinishSyncSessionJob(job.get(), premature_exit, &session); |
| + RestartPollTimerIfRateChanged(); |
| if (IsSyncingCurrentlySilenced()) { |
| - // Normally we would only call RestartWaiting() if we had a |
| - // pending_nudge_job_ or pending_configure_job_ set. In this case, it's |
| - // possible that neither is set. We create the wait interval anyway because |
| - // we need it to make sure we get unthrottled on time. |
| + SDVLOG(2) << "Poll request got us throttled."; |
| + // The OnSilencedUntil() call set up the WaitInterval for us. All we need |
| + // to do is start the timer. |
| RestartWaiting(); |
| } |
| } |
| @@ -711,75 +606,41 @@ void SyncSchedulerImpl::UpdateNudgeTimeRecords(const SyncSourceInfo& info) { |
| } |
| } |
| -bool SyncSchedulerImpl::FinishSyncSessionJob(SyncSessionJob* job, |
| - bool exited_prematurely, |
| - SyncSession* session) { |
| - DCHECK(CalledOnValidThread()); |
| - |
| - // Let job know that we're through syncing (calling SyncShare) at this point. |
| - bool succeeded = false; |
| - { |
| - base::AutoReset<bool> protector(&no_scheduling_allowed_, true); |
| - succeeded = job->Finish(exited_prematurely, session); |
| - } |
| - |
| - SDVLOG(2) << "Updating the next polling time after SyncMain"; |
| - |
| - AdjustPolling(job); |
| - |
| - if (succeeded) { |
| - // No job currently supported by the scheduler could succeed without |
| - // successfully reaching the server. Therefore, if we make it here, it is |
| - // appropriate to reset the backoff interval. |
| - wait_interval_.reset(); |
| - NotifyRetryTime(base::Time()); |
| - SDVLOG(2) << "Job succeeded so not scheduling more jobs"; |
| - } |
| - |
| - return succeeded; |
| +base::TimeDelta SyncSchedulerImpl::GetDesiredPollRate() { |
| + return (!session_context_->notifications_enabled()) ? |
| + syncer_short_poll_interval_seconds_ : |
| + syncer_long_poll_interval_seconds_; |
| } |
| -void SyncSchedulerImpl::ScheduleNextSync( |
| - scoped_ptr<SyncSessionJob> finished_job, |
| - SyncSession* session) { |
| - DCHECK(CalledOnValidThread()); |
| - DCHECK(finished_job->purpose() == SyncSessionJob::CONFIGURATION |
| - || finished_job->purpose() == SyncSessionJob::NUDGE); |
| - |
| - // TODO(rlarocque): There's no reason why we should blindly backoff and retry |
| - // if we don't succeed. Some types of errors are not likely to disappear on |
| - // their own. With the return values now available in the old_job.session, |
| - // we should be able to detect such errors and only retry when we detect |
| - // transient errors. |
| - |
| - SDVLOG(2) << "SyncShare job failed; will start or update backoff"; |
| - HandleContinuationError(finished_job.Pass(), session); |
| +bool SyncSchedulerImpl::DidPollRateChange() { |
| + return !poll_timer_.IsRunning() |
| + || GetDesiredPollRate() != poll_timer_.GetCurrentDelay(); |
| } |
| -void SyncSchedulerImpl::AdjustPolling(const SyncSessionJob* old_job) { |
| +void SyncSchedulerImpl::RestartPollTimer() { |
|
tim (not reviewing)
2013/04/17 17:49:00
If this patch is supposed to be about removing Syn
rlarocque
2013/04/17 20:45:38
Yes, you're right. I'll put it back to the way it
|
| DCHECK(CalledOnValidThread()); |
| - |
| - TimeDelta poll = (!session_context_->notifications_enabled()) ? |
| - syncer_short_poll_interval_seconds_ : |
| - syncer_long_poll_interval_seconds_; |
| - bool rate_changed = !poll_timer_.IsRunning() || |
| - poll != poll_timer_.GetCurrentDelay(); |
| - |
| - if (old_job && old_job->purpose() != SyncSessionJob::POLL && !rate_changed) |
| + if (!DidPollRateChange()) { |
| poll_timer_.Reset(); |
| + } else { |
| + RestartPollTimerIfRateChanged(); |
| + } |
| +} |
| - if (!rate_changed) |
| - return; |
| - |
| - // Adjust poll rate. |
| - poll_timer_.Stop(); |
| - poll_timer_.Start(FROM_HERE, poll, this, |
| - &SyncSchedulerImpl::PollTimerCallback); |
| +void SyncSchedulerImpl::RestartPollTimerIfRateChanged() { |
| + DCHECK(CalledOnValidThread()); |
| + if (DidPollRateChange()) { |
| + poll_timer_.Stop(); |
| + poll_timer_.Start(FROM_HERE, GetDesiredPollRate(), this, |
| + &SyncSchedulerImpl::PollTimerCallback); |
| + } |
| } |
| void SyncSchedulerImpl::RestartWaiting() { |
| CHECK(wait_interval_.get()); |
| DCHECK(wait_interval_->length >= TimeDelta::FromSeconds(0)); |
| + NotifyRetryTime(base::Time::Now() + wait_interval_->length); |
| + SDVLOG(2) << "Starting WaitInterval timer of length " |
| + << wait_interval_->length.InMilliseconds() << "ms."; |
| if (wait_interval_->mode == WaitInterval::THROTTLED) { |
| pending_wakeup_timer_.Start( |
| FROM_HERE, |
| @@ -795,39 +656,15 @@ void SyncSchedulerImpl::RestartWaiting() { |
| } |
| } |
| -void SyncSchedulerImpl::HandleContinuationError( |
| - scoped_ptr<SyncSessionJob> old_job, |
| - SyncSession* session) { |
| +void SyncSchedulerImpl::UpdateExponentialBackoff( |
| + const sessions::ModelNeutralState& model_neutral_state) { |
| DCHECK(CalledOnValidThread()); |
| TimeDelta length = delay_provider_->GetDelay( |
| IsBackingOff() ? wait_interval_->length : |
| - delay_provider_->GetInitialDelay( |
| - session->status_controller().model_neutral_state())); |
| - |
| - SDVLOG(2) << "In handle continuation error with " |
| - << SyncSessionJob::GetPurposeString(old_job->purpose()) |
| - << " job. The time delta(ms) is " |
| - << length.InMilliseconds(); |
| - |
| + delay_provider_->GetInitialDelay(model_neutral_state)); |
| wait_interval_.reset(new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, |
| length)); |
| - NotifyRetryTime(base::Time::Now() + length); |
| - old_job->set_scheduled_start(TimeTicks::Now() + length); |
| - if (old_job->purpose() == SyncSessionJob::CONFIGURATION) { |
| - SDVLOG(2) << "Configuration did not succeed, scheduling retry."; |
| - // Config params should always get set. |
| - DCHECK(!old_job->config_params().ready_task.is_null()); |
| - DCHECK(!pending_configure_job_); |
| - pending_configure_job_ = old_job.Pass(); |
| - } else { |
| - // We're not in configure mode so we should not have a configure job. |
| - DCHECK(!pending_configure_job_); |
| - DCHECK(!pending_nudge_job_); |
| - pending_nudge_job_ = old_job.Pass(); |
| - } |
| - |
| - RestartWaiting(); |
| } |
| void SyncSchedulerImpl::RequestStop(const base::Closure& callback) { |
| @@ -849,11 +686,9 @@ void SyncSchedulerImpl::StopImpl(const base::Closure& callback) { |
| NotifyRetryTime(base::Time()); |
| poll_timer_.Stop(); |
| pending_wakeup_timer_.Stop(); |
| - pending_nudge_job_.reset(); |
| - pending_configure_job_.reset(); |
| - if (started_) { |
| + pending_configure_params_.reset(); |
| + if (started_) |
| started_ = false; |
| - } |
| if (!callback.is_null()) |
| callback.Run(); |
| } |
| @@ -863,10 +698,10 @@ void SyncSchedulerImpl::StopImpl(const base::Closure& callback) { |
| void SyncSchedulerImpl::TryCanaryJob() { |
| DCHECK(CalledOnValidThread()); |
| - if (mode_ == CONFIGURATION_MODE && pending_configure_job_) { |
| + if (mode_ == CONFIGURATION_MODE && pending_configure_params_) { |
| SDVLOG(2) << "Found pending configure job; will run as canary"; |
| DoConfigurationSyncSessionJob(CANARY_PRIORITY); |
| - } else if (mode_ == NORMAL_MODE && pending_nudge_job_) { |
| + } else if (mode_ == NORMAL_MODE && !nudge_tracker_.IsEmpty()) { |
| SDVLOG(2) << "Found pending nudge job; will run as canary"; |
| DoNudgeSyncSessionJob(CANARY_PRIORITY); |
| } else { |