Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1228)

Unified Diff: sync/engine/sync_scheduler_impl.cc

Issue 12538015: sync: Handle POLL jobs in separate a code path (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Amend comments Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sync/engine/sync_scheduler_impl.h ('k') | sync/engine/sync_scheduler_whitebox_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sync/engine/sync_scheduler_impl.cc
diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc
index 0f55c5fa8dd99cb944adfcef61eea1ccbb272d78..5bfcbcc18dddb72bc2e46ec9acc878d63cc549d2 100644
--- a/sync/engine/sync_scheduler_impl.cc
+++ b/sync/engine/sync_scheduler_impl.cc
@@ -343,15 +343,13 @@ SyncSchedulerImpl::DecideWhileInWaitInterval(const SyncSessionJob& job,
JobPriority priority) {
DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(wait_interval_.get());
+ DCHECK_NE(job.purpose(), SyncSessionJob::POLL);
SDVLOG(2) << "DecideWhileInWaitInterval with WaitInterval mode "
<< WaitInterval::GetModeString(wait_interval_->mode)
<< (wait_interval_->had_nudge ? " (had nudge)" : "")
<< ((priority == CANARY_PRIORITY) ? " (canary)" : "");
- if (job.purpose() == SyncSessionJob::POLL)
- return DROP;
-
// 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.
@@ -383,6 +381,10 @@ SyncSchedulerImpl::JobProcessDecision SyncSchedulerImpl::DecideOnJob(
JobPriority priority) {
DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ // POLL jobs do not call this function.
+ DCHECK(job.purpose() == SyncSessionJob::NUDGE ||
+ job.purpose() == SyncSessionJob::CONFIGURATION);
+
// See if our type is throttled.
ModelTypeSet throttled_types =
session_context_->throttled_data_type_tracker()->GetThrottledTypes();
@@ -412,10 +414,8 @@ SyncSchedulerImpl::JobProcessDecision SyncSchedulerImpl::DecideOnJob(
if (mode_ == CONFIGURATION_MODE) {
if (job.purpose() == SyncSessionJob::NUDGE)
return SAVE; // Running requires a mode switch.
- else if (job.purpose() == SyncSessionJob::CONFIGURATION)
+ else // Implies job.purpose() == SyncSessionJob::CONFIGURATION.
return CONTINUE;
- else
- return DROP;
}
// We are in normal mode.
@@ -427,26 +427,16 @@ SyncSchedulerImpl::JobProcessDecision SyncSchedulerImpl::DecideOnJob(
// 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 POLL with a |scheduled_start| time that is less than
- // the time that the last successful all-datatype NUDGE completed.
- //
- // 2) |job| is a NUDGE (for any combination of types) with a
+ // 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.
//
- // 3) |job| is a NUDGE with a |scheduled_start| time that is less than
+ // 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.
//
- // Case 1 can occur if the POLL timer fires *after* a call to
- // ScheduleSyncSessionJob for a NUDGE, but *before* the thread actually
- // picks the resulting posted task off of the MessageLoop. The NUDGE will
- // run first and complete at a time greater than the POLL scheduled_start.
- // However, this case (and POLLs in general) is so rare that we ignore it (
- // and avoid the required bookeeping to simplify code).
- //
- // We avoid cases 2 and 3 by externally synchronizing NUDGE requests --
+ // 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
@@ -564,6 +554,9 @@ void SyncSchedulerImpl::ScheduleNudgeWithStatesAsync(
nudge_location);
}
+
+// TODO(zea): Consider adding separate throttling/backoff for datatype
+// refresh requests.
void SyncSchedulerImpl::ScheduleNudgeImpl(
const TimeDelta& delay,
GetUpdatesCallerInfo::GetUpdatesSource source,
@@ -572,6 +565,11 @@ void SyncSchedulerImpl::ScheduleNudgeImpl(
DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(!invalidation_map.empty()) << "Nudge scheduled for no types!";
+ if (no_scheduling_allowed_) {
+ NOTREACHED() << "Illegal to schedule job while session in progress.";
+ return;
+ }
+
if (!started_) {
SDVLOG_LOC(nudge_location, 2)
<< "Dropping nudge, scheduler is not running.";
@@ -631,9 +629,20 @@ void SyncSchedulerImpl::ScheduleNudgeImpl(
DCHECK(!wait_interval_ || !wait_interval_->had_nudge);
}
- // TODO(zea): Consider adding separate throttling/backoff for datatype
- // refresh requests.
- ScheduleSyncSessionJob(nudge_location, job.Pass());
+ TimeDelta run_delay = job->scheduled_start() - TimeTicks::Now();
+ if (run_delay < TimeDelta::FromMilliseconds(0))
+ run_delay = TimeDelta::FromMilliseconds(0);
+ SDVLOG_LOC(nudge_location, 2)
+ << "Scheduling a nudge with "
+ << run_delay.InMilliseconds() << " ms delay";
+
+ pending_nudge_ = job.get();
+ PostDelayedTask(nudge_location, "DoSyncSessionJob",
+ base::Bind(base::IgnoreResult(&SyncSchedulerImpl::DoSyncSessionJob),
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(&job),
+ NORMAL_PRIORITY),
+ run_delay);
}
const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) {
@@ -679,40 +688,6 @@ void SyncSchedulerImpl::PostDelayedTask(
sync_loop_->PostDelayedTask(from_here, task, delay);
}
-void SyncSchedulerImpl::ScheduleSyncSessionJob(
- const tracked_objects::Location& loc,
- scoped_ptr<SyncSessionJob> job) {
- DCHECK_EQ(MessageLoop::current(), sync_loop_);
- if (no_scheduling_allowed_) {
- NOTREACHED() << "Illegal to schedule job while session in progress.";
- return;
- }
-
- TimeDelta delay = job->scheduled_start() - TimeTicks::Now();
- if (delay < TimeDelta::FromMilliseconds(0))
- delay = TimeDelta::FromMilliseconds(0);
- SDVLOG_LOC(loc, 2)
- << "In ScheduleSyncSessionJob with "
- << SyncSessionJob::GetPurposeString(job->purpose())
- << " job and " << delay.InMilliseconds() << " ms delay";
-
- DCHECK(job->purpose() == SyncSessionJob::NUDGE ||
- job->purpose() == SyncSessionJob::POLL);
- if (job->purpose() == SyncSessionJob::NUDGE) {
- SDVLOG_LOC(loc, 2) << "Resetting pending_nudge to ";
- DCHECK(!pending_nudge_ || pending_nudge_->session() ==
- job->session());
- pending_nudge_ = job.get();
- }
-
- PostDelayedTask(loc, "DoSyncSessionJob",
- base::Bind(base::IgnoreResult(&SyncSchedulerImpl::DoSyncSessionJob),
- weak_ptr_factory_.GetWeakPtr(),
- base::Passed(&job),
- NORMAL_PRIORITY),
- delay);
-}
-
bool SyncSchedulerImpl::DoSyncSessionJob(scoped_ptr<SyncSessionJob> job,
JobPriority priority) {
DCHECK_EQ(MessageLoop::current(), sync_loop_);
@@ -756,7 +731,78 @@ bool SyncSchedulerImpl::DoSyncSessionJob(scoped_ptr<SyncSessionJob> job,
job->end_step());
SDVLOG(2) << "Done SyncShare, returned: " << premature_exit;
- return FinishSyncSessionJob(job.Pass(), premature_exit);
+ bool success = FinishSyncSessionJob(job.get(), premature_exit);
+
+ 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).
+ scoped_ptr<SyncSessionJob> clone = job->Clone();
+ if (clone->purpose() == SyncSessionJob::NUDGE)
+ pending_nudge_ = clone.get();
+ else if (clone->purpose() == SyncSessionJob::CONFIGURATION)
+ wait_interval_->pending_configure_job = clone.get();
+ else
+ NOTREACHED();
+
+ RestartWaiting(clone.Pass());
+ return success;
+ }
+
+ if (!success)
+ ScheduleNextSync(job.Pass());
+
+ return success;
+}
+
+bool SyncSchedulerImpl::ShouldPoll() {
+ if (wait_interval_.get()) {
+ SDVLOG(2) << "Not running poll in wait interval.";
+ return false;
+ }
+
+ if (mode_ == CONFIGURATION_MODE) {
+ SDVLOG(2) << "Not running poll in configuration mode.";
+ return false;
+ }
+
+ // TODO(rlarocque): Refactor decision-making logic common to all types
+ // of jobs into a shared function.
+
+ if (session_context_->connection_manager()->HasInvalidAuthToken()) {
+ SDVLOG(2) << "Not running poll because auth token is invalid.";
+ return false;
+ }
+
+ return true;
+}
+
+void SyncSchedulerImpl::DoPollSyncSessionJob(scoped_ptr<SyncSessionJob> job) {
+ DCHECK_EQ(job->purpose(), SyncSessionJob::POLL);
+
+ base::AutoReset<bool> protector(&no_scheduling_allowed_, true);
+
+ if (!ShouldPoll())
+ return;
+
+ SDVLOG(2) << "Calling SyncShare with "
+ << SyncSessionJob::GetPurposeString(job->purpose()) << " job";
+ bool premature_exit = !syncer_->SyncShare(job->mutable_session(),
+ job->start_step(),
+ job->end_step());
+ SDVLOG(2) << "Done SyncShare, returned: " << premature_exit;
+
+ FinishSyncSessionJob(job.get(), premature_exit);
+
+ if (IsSyncingCurrentlySilenced()) {
+ // This will start the countdown to unthrottle. Other kinds of jobs would
+ // schedule themselves as the post-unthrottle canary. A poll job is not
+ // that urgent, so it does not get to be the canary. We still need to start
+ // the timer regardless. Otherwise there could be no one to clear the
+ // WaitInterval when the throttling expires.
+ RestartWaiting(scoped_ptr<SyncSessionJob>());
+ }
}
void SyncSchedulerImpl::UpdateNudgeTimeRecords(const SyncSourceInfo& info) {
@@ -784,7 +830,7 @@ void SyncSchedulerImpl::UpdateNudgeTimeRecords(const SyncSourceInfo& info) {
}
}
-bool SyncSchedulerImpl::FinishSyncSessionJob(scoped_ptr<SyncSessionJob> job,
+bool SyncSchedulerImpl::FinishSyncSessionJob(SyncSessionJob* job,
bool exited_prematurely) {
DCHECK_EQ(MessageLoop::current(), sync_loop_);
@@ -796,15 +842,8 @@ bool SyncSchedulerImpl::FinishSyncSessionJob(scoped_ptr<SyncSessionJob> job,
}
SDVLOG(2) << "Updating the next polling time after SyncMain";
- ScheduleNextSync(job.Pass(), succeeded);
- return succeeded;
-}
-void SyncSchedulerImpl::ScheduleNextSync(
- scoped_ptr<SyncSessionJob> finished_job, bool succeeded) {
- DCHECK_EQ(MessageLoop::current(), sync_loop_);
-
- AdjustPolling(finished_job.get());
+ AdjustPolling(job);
if (succeeded) {
// No job currently supported by the scheduler could succeed without
@@ -813,29 +852,16 @@ void SyncSchedulerImpl::ScheduleNextSync(
wait_interval_.reset();
NotifyRetryTime(base::Time());
SDVLOG(2) << "Job succeeded so not scheduling more jobs";
- return;
}
- 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).
- scoped_ptr<SyncSessionJob> clone = finished_job->Clone();
- if (clone->purpose() == SyncSessionJob::NUDGE)
- pending_nudge_ = clone.get();
- else if (clone->purpose() == SyncSessionJob::CONFIGURATION)
- wait_interval_->pending_configure_job = clone.get();
- else
- clone.reset(); // Unthrottling is enough, no need to force a canary.
-
- RestartWaiting(clone.Pass());
- return;
- }
+ return succeeded;
+}
- if (finished_job->purpose() == SyncSessionJob::POLL) {
- return; // We don't retry POLL jobs.
- }
+void SyncSchedulerImpl::ScheduleNextSync(
+ scoped_ptr<SyncSessionJob> finished_job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ 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
@@ -980,7 +1006,7 @@ void SyncSchedulerImpl::DoCanaryJob(scoped_ptr<SyncSessionJob> to_be_canary) {
pending_nudge_->session() != to_be_canary->session()) {
// |job| is abandoned.
SDVLOG(2) << "Dropping a nudge in "
- << "DoSyncSessionJob because another nudge was scheduled";
+ << "DoCanaryJob because another nudge was scheduled";
return;
}
DCHECK_EQ(pending_nudge_->session(), to_be_canary->session());
@@ -1035,7 +1061,18 @@ void SyncSchedulerImpl::PollTimerCallback() {
TimeTicks::Now(),
s.Pass(),
ConfigurationParams()));
- ScheduleSyncSessionJob(FROM_HERE, job.Pass());
+ if (no_scheduling_allowed_) {
+ // The no_scheduling_allowed_ flag is set by a function-scoped AutoReset in
+ // functions that are called only on the sync thread. This function is also
+ // called only on the sync thread, and only when it is posted by an expiring
+ // timer. If we find that no_scheduling_allowed_ is set here, then
+ // something is very wrong. Maybe someone mistakenly called us directly, or
+ // mishandled the book-keeping for no_scheduling_allowed_.
+ NOTREACHED() << "Illegal to schedule job while session in progress.";
+ return;
+ }
+
+ DoPollSyncSessionJob(job.Pass());
}
void SyncSchedulerImpl::Unthrottle(scoped_ptr<SyncSessionJob> to_be_canary) {
« no previous file with comments | « sync/engine/sync_scheduler_impl.h ('k') | sync/engine/sync_scheduler_whitebox_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698