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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "sync/engine/sync_scheduler_impl.h" 5 #include "sync/engine/sync_scheduler_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cstring> 8 #include <cstring>
9 9
10 #include "base/auto_reset.h" 10 #include "base/auto_reset.h"
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 } 336 }
337 337
338 return true; 338 return true;
339 } 339 }
340 340
341 SyncSchedulerImpl::JobProcessDecision 341 SyncSchedulerImpl::JobProcessDecision
342 SyncSchedulerImpl::DecideWhileInWaitInterval(const SyncSessionJob& job, 342 SyncSchedulerImpl::DecideWhileInWaitInterval(const SyncSessionJob& job,
343 JobPriority priority) { 343 JobPriority priority) {
344 DCHECK_EQ(MessageLoop::current(), sync_loop_); 344 DCHECK_EQ(MessageLoop::current(), sync_loop_);
345 DCHECK(wait_interval_.get()); 345 DCHECK(wait_interval_.get());
346 DCHECK_NE(job.purpose(), SyncSessionJob::POLL);
346 347
347 SDVLOG(2) << "DecideWhileInWaitInterval with WaitInterval mode " 348 SDVLOG(2) << "DecideWhileInWaitInterval with WaitInterval mode "
348 << WaitInterval::GetModeString(wait_interval_->mode) 349 << WaitInterval::GetModeString(wait_interval_->mode)
349 << (wait_interval_->had_nudge ? " (had nudge)" : "") 350 << (wait_interval_->had_nudge ? " (had nudge)" : "")
350 << ((priority == CANARY_PRIORITY) ? " (canary)" : ""); 351 << ((priority == CANARY_PRIORITY) ? " (canary)" : "");
351 352
352 if (job.purpose() == SyncSessionJob::POLL)
353 return DROP;
354
355 // If we save a job while in a WaitInterval, there is a well-defined moment 353 // If we save a job while in a WaitInterval, there is a well-defined moment
356 // in time in the future when it makes sense for that SAVE-worthy job to try 354 // in time in the future when it makes sense for that SAVE-worthy job to try
357 // running again -- the end of the WaitInterval. 355 // running again -- the end of the WaitInterval.
358 DCHECK(job.purpose() == SyncSessionJob::NUDGE || 356 DCHECK(job.purpose() == SyncSessionJob::NUDGE ||
359 job.purpose() == SyncSessionJob::CONFIGURATION); 357 job.purpose() == SyncSessionJob::CONFIGURATION);
360 358
361 // If throttled, there's a clock ticking to unthrottle. We want to get 359 // If throttled, there's a clock ticking to unthrottle. We want to get
362 // on the same train. 360 // on the same train.
363 if (wait_interval_->mode == WaitInterval::THROTTLED) 361 if (wait_interval_->mode == WaitInterval::THROTTLED)
364 return SAVE; 362 return SAVE;
(...skipping 11 matching lines...) Expand all
376 return CONTINUE; 374 return CONTINUE;
377 } 375 }
378 return (priority == CANARY_PRIORITY) ? CONTINUE : SAVE; 376 return (priority == CANARY_PRIORITY) ? CONTINUE : SAVE;
379 } 377 }
380 378
381 SyncSchedulerImpl::JobProcessDecision SyncSchedulerImpl::DecideOnJob( 379 SyncSchedulerImpl::JobProcessDecision SyncSchedulerImpl::DecideOnJob(
382 const SyncSessionJob& job, 380 const SyncSessionJob& job,
383 JobPriority priority) { 381 JobPriority priority) {
384 DCHECK_EQ(MessageLoop::current(), sync_loop_); 382 DCHECK_EQ(MessageLoop::current(), sync_loop_);
385 383
384 // POLL jobs do not call this function.
385 DCHECK(job.purpose() == SyncSessionJob::NUDGE ||
386 job.purpose() == SyncSessionJob::CONFIGURATION);
387
386 // See if our type is throttled. 388 // See if our type is throttled.
387 ModelTypeSet throttled_types = 389 ModelTypeSet throttled_types =
388 session_context_->throttled_data_type_tracker()->GetThrottledTypes(); 390 session_context_->throttled_data_type_tracker()->GetThrottledTypes();
389 if (job.purpose() == SyncSessionJob::NUDGE && 391 if (job.purpose() == SyncSessionJob::NUDGE &&
390 job.session()->source().updates_source == GetUpdatesCallerInfo::LOCAL) { 392 job.session()->source().updates_source == GetUpdatesCallerInfo::LOCAL) {
391 ModelTypeSet requested_types; 393 ModelTypeSet requested_types;
392 for (ModelTypeInvalidationMap::const_iterator i = 394 for (ModelTypeInvalidationMap::const_iterator i =
393 job.session()->source().types.begin(); 395 job.session()->source().types.begin();
394 i != job.session()->source().types.end(); 396 i != job.session()->source().types.end();
395 ++i) { 397 ++i) {
396 requested_types.Put(i->first); 398 requested_types.Put(i->first);
397 } 399 }
398 400
399 // If all types are throttled, do not CONTINUE. Today, we don't treat 401 // If all types are throttled, do not CONTINUE. Today, we don't treat
400 // a per-datatype "unthrottle" event as something that should force a 402 // a per-datatype "unthrottle" event as something that should force a
401 // canary job. For this reason, there's no good time to reschedule this job 403 // canary job. For this reason, there's no good time to reschedule this job
402 // to run -- we'll lazily wait for an independent event to trigger a sync. 404 // to run -- we'll lazily wait for an independent event to trigger a sync.
403 // Note that there may already be such an event if we're in a WaitInterval, 405 // Note that there may already be such an event if we're in a WaitInterval,
404 // so we can retry it then. 406 // so we can retry it then.
405 if (!requested_types.Empty() && throttled_types.HasAll(requested_types)) 407 if (!requested_types.Empty() && throttled_types.HasAll(requested_types))
406 return DROP; // TODO(tim): Don't drop. http://crbug.com/177659 408 return DROP; // TODO(tim): Don't drop. http://crbug.com/177659
407 } 409 }
408 410
409 if (wait_interval_.get()) 411 if (wait_interval_.get())
410 return DecideWhileInWaitInterval(job, priority); 412 return DecideWhileInWaitInterval(job, priority);
411 413
412 if (mode_ == CONFIGURATION_MODE) { 414 if (mode_ == CONFIGURATION_MODE) {
413 if (job.purpose() == SyncSessionJob::NUDGE) 415 if (job.purpose() == SyncSessionJob::NUDGE)
414 return SAVE; // Running requires a mode switch. 416 return SAVE; // Running requires a mode switch.
415 else if (job.purpose() == SyncSessionJob::CONFIGURATION) 417 else // Implies job.purpose() == SyncSessionJob::CONFIGURATION.
416 return CONTINUE; 418 return CONTINUE;
417 else
418 return DROP;
419 } 419 }
420 420
421 // We are in normal mode. 421 // We are in normal mode.
422 DCHECK_EQ(mode_, NORMAL_MODE); 422 DCHECK_EQ(mode_, NORMAL_MODE);
423 DCHECK_NE(job.purpose(), SyncSessionJob::CONFIGURATION); 423 DCHECK_NE(job.purpose(), SyncSessionJob::CONFIGURATION);
424 424
425 // Note about some subtle scheduling semantics. 425 // Note about some subtle scheduling semantics.
426 // 426 //
427 // It's possible at this point that |job| is known to be unnecessary, and 427 // It's possible at this point that |job| is known to be unnecessary, and
428 // dropping it would be perfectly safe and correct. Consider 428 // dropping it would be perfectly safe and correct. Consider
429 // 429 //
430 // 1) |job| is a POLL with a |scheduled_start| time that is less than 430 // 1) |job| is a NUDGE (for any combination of types) with a
431 // the time that the last successful all-datatype NUDGE completed.
432 //
433 // 2) |job| is a NUDGE (for any combination of types) with a
434 // |scheduled_start| time that is less than the time that the last 431 // |scheduled_start| time that is less than the time that the last
435 // successful all-datatype NUDGE completed, and it has a NOTIFICATION 432 // successful all-datatype NUDGE completed, and it has a NOTIFICATION
436 // GetUpdatesCallerInfo value yet offers no new notification hint. 433 // GetUpdatesCallerInfo value yet offers no new notification hint.
437 // 434 //
438 // 3) |job| is a NUDGE with a |scheduled_start| time that is less than 435 // 2) |job| is a NUDGE with a |scheduled_start| time that is less than
439 // the time that the last successful matching-datatype NUDGE completed, 436 // the time that the last successful matching-datatype NUDGE completed,
440 // and payloads (hints) are identical to that last successful NUDGE. 437 // and payloads (hints) are identical to that last successful NUDGE.
441 // 438 //
442 // Case 1 can occur if the POLL timer fires *after* a call to 439 // We avoid cases 1 and 2 by externally synchronizing NUDGE requests --
443 // ScheduleSyncSessionJob for a NUDGE, but *before* the thread actually
444 // picks the resulting posted task off of the MessageLoop. The NUDGE will
445 // run first and complete at a time greater than the POLL scheduled_start.
446 // However, this case (and POLLs in general) is so rare that we ignore it (
447 // and avoid the required bookeeping to simplify code).
448 //
449 // We avoid cases 2 and 3 by externally synchronizing NUDGE requests --
450 // scheduling a NUDGE requires command of the sync thread, which is 440 // scheduling a NUDGE requires command of the sync thread, which is
451 // impossible* from outside of SyncScheduler if a NUDGE is taking place. 441 // impossible* from outside of SyncScheduler if a NUDGE is taking place.
452 // And if you have command of the sync thread when scheduling a NUDGE and a 442 // And if you have command of the sync thread when scheduling a NUDGE and a
453 // previous NUDGE exists, they will be coalesced and the stale job will be 443 // previous NUDGE exists, they will be coalesced and the stale job will be
454 // cancelled via the session-equality check in DoSyncSessionJob. 444 // cancelled via the session-equality check in DoSyncSessionJob.
455 // 445 //
456 // * It's not strictly "impossible", but it would be reentrant and hence 446 // * It's not strictly "impossible", but it would be reentrant and hence
457 // illegal. e.g. scheduling a job and re-entering the SyncScheduler is NOT a 447 // illegal. e.g. scheduling a job and re-entering the SyncScheduler is NOT a
458 // legal side effect of any of the work being done as part of a sync cycle. 448 // legal side effect of any of the work being done as part of a sync cycle.
459 // See |no_scheduling_allowed_| for details. 449 // See |no_scheduling_allowed_| for details.
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 << "source " << GetNudgeSourceString(source) << ", " 547 << "source " << GetNudgeSourceString(source) << ", "
558 << "payloads " 548 << "payloads "
559 << ModelTypeInvalidationMapToString(invalidation_map); 549 << ModelTypeInvalidationMapToString(invalidation_map);
560 550
561 SyncSchedulerImpl::ScheduleNudgeImpl(desired_delay, 551 SyncSchedulerImpl::ScheduleNudgeImpl(desired_delay,
562 GetUpdatesFromNudgeSource(source), 552 GetUpdatesFromNudgeSource(source),
563 invalidation_map, 553 invalidation_map,
564 nudge_location); 554 nudge_location);
565 } 555 }
566 556
557
558 // TODO(zea): Consider adding separate throttling/backoff for datatype
559 // refresh requests.
567 void SyncSchedulerImpl::ScheduleNudgeImpl( 560 void SyncSchedulerImpl::ScheduleNudgeImpl(
568 const TimeDelta& delay, 561 const TimeDelta& delay,
569 GetUpdatesCallerInfo::GetUpdatesSource source, 562 GetUpdatesCallerInfo::GetUpdatesSource source,
570 const ModelTypeInvalidationMap& invalidation_map, 563 const ModelTypeInvalidationMap& invalidation_map,
571 const tracked_objects::Location& nudge_location) { 564 const tracked_objects::Location& nudge_location) {
572 DCHECK_EQ(MessageLoop::current(), sync_loop_); 565 DCHECK_EQ(MessageLoop::current(), sync_loop_);
573 DCHECK(!invalidation_map.empty()) << "Nudge scheduled for no types!"; 566 DCHECK(!invalidation_map.empty()) << "Nudge scheduled for no types!";
574 567
568 if (no_scheduling_allowed_) {
569 NOTREACHED() << "Illegal to schedule job while session in progress.";
570 return;
571 }
572
575 if (!started_) { 573 if (!started_) {
576 SDVLOG_LOC(nudge_location, 2) 574 SDVLOG_LOC(nudge_location, 2)
577 << "Dropping nudge, scheduler is not running."; 575 << "Dropping nudge, scheduler is not running.";
578 return; 576 return;
579 } 577 }
580 578
581 SDVLOG_LOC(nudge_location, 2) 579 SDVLOG_LOC(nudge_location, 2)
582 << "In ScheduleNudgeImpl with delay " 580 << "In ScheduleNudgeImpl with delay "
583 << delay.InMilliseconds() << " ms, " 581 << delay.InMilliseconds() << " ms, "
584 << "source " << GetUpdatesSourceString(source) << ", " 582 << "source " << GetUpdatesSourceString(source) << ", "
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 // was previously unscheduled and giving it wings, so take care to reset 622 // was previously unscheduled and giving it wings, so take care to reset
625 // unscheduled nudge storage. 623 // unscheduled nudge storage.
626 job = pending_nudge_->CloneAndAbandon(); 624 job = pending_nudge_->CloneAndAbandon();
627 pending_nudge_ = NULL; 625 pending_nudge_ = NULL;
628 unscheduled_nudge_storage_.reset(); 626 unscheduled_nudge_storage_.reset();
629 // It's also possible we took a canary job, since we allow one nudge 627 // It's also possible we took a canary job, since we allow one nudge
630 // per backoff interval. 628 // per backoff interval.
631 DCHECK(!wait_interval_ || !wait_interval_->had_nudge); 629 DCHECK(!wait_interval_ || !wait_interval_->had_nudge);
632 } 630 }
633 631
634 // TODO(zea): Consider adding separate throttling/backoff for datatype 632 TimeDelta run_delay = job->scheduled_start() - TimeTicks::Now();
635 // refresh requests. 633 if (run_delay < TimeDelta::FromMilliseconds(0))
636 ScheduleSyncSessionJob(nudge_location, job.Pass()); 634 run_delay = TimeDelta::FromMilliseconds(0);
635 SDVLOG_LOC(nudge_location, 2)
636 << "Scheduling a nudge with "
637 << run_delay.InMilliseconds() << " ms delay";
638
639 pending_nudge_ = job.get();
640 PostDelayedTask(nudge_location, "DoSyncSessionJob",
641 base::Bind(base::IgnoreResult(&SyncSchedulerImpl::DoSyncSessionJob),
642 weak_ptr_factory_.GetWeakPtr(),
643 base::Passed(&job),
644 NORMAL_PRIORITY),
645 run_delay);
637 } 646 }
638 647
639 const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) { 648 const char* SyncSchedulerImpl::GetModeString(SyncScheduler::Mode mode) {
640 switch (mode) { 649 switch (mode) {
641 ENUM_CASE(CONFIGURATION_MODE); 650 ENUM_CASE(CONFIGURATION_MODE);
642 ENUM_CASE(NORMAL_MODE); 651 ENUM_CASE(NORMAL_MODE);
643 } 652 }
644 return ""; 653 return "";
645 } 654 }
646 655
(...skipping 25 matching lines...) Expand all
672 SDVLOG_LOC(from_here, 3) << "Posting " << name << " task with " 681 SDVLOG_LOC(from_here, 3) << "Posting " << name << " task with "
673 << delay.InMilliseconds() << " ms delay"; 682 << delay.InMilliseconds() << " ms delay";
674 DCHECK_EQ(MessageLoop::current(), sync_loop_); 683 DCHECK_EQ(MessageLoop::current(), sync_loop_);
675 if (!started_) { 684 if (!started_) {
676 SDVLOG(1) << "Not posting task as scheduler is stopped."; 685 SDVLOG(1) << "Not posting task as scheduler is stopped.";
677 return; 686 return;
678 } 687 }
679 sync_loop_->PostDelayedTask(from_here, task, delay); 688 sync_loop_->PostDelayedTask(from_here, task, delay);
680 } 689 }
681 690
682 void SyncSchedulerImpl::ScheduleSyncSessionJob(
683 const tracked_objects::Location& loc,
684 scoped_ptr<SyncSessionJob> job) {
685 DCHECK_EQ(MessageLoop::current(), sync_loop_);
686 if (no_scheduling_allowed_) {
687 NOTREACHED() << "Illegal to schedule job while session in progress.";
688 return;
689 }
690
691 TimeDelta delay = job->scheduled_start() - TimeTicks::Now();
692 if (delay < TimeDelta::FromMilliseconds(0))
693 delay = TimeDelta::FromMilliseconds(0);
694 SDVLOG_LOC(loc, 2)
695 << "In ScheduleSyncSessionJob with "
696 << SyncSessionJob::GetPurposeString(job->purpose())
697 << " job and " << delay.InMilliseconds() << " ms delay";
698
699 DCHECK(job->purpose() == SyncSessionJob::NUDGE ||
700 job->purpose() == SyncSessionJob::POLL);
701 if (job->purpose() == SyncSessionJob::NUDGE) {
702 SDVLOG_LOC(loc, 2) << "Resetting pending_nudge to ";
703 DCHECK(!pending_nudge_ || pending_nudge_->session() ==
704 job->session());
705 pending_nudge_ = job.get();
706 }
707
708 PostDelayedTask(loc, "DoSyncSessionJob",
709 base::Bind(base::IgnoreResult(&SyncSchedulerImpl::DoSyncSessionJob),
710 weak_ptr_factory_.GetWeakPtr(),
711 base::Passed(&job),
712 NORMAL_PRIORITY),
713 delay);
714 }
715
716 bool SyncSchedulerImpl::DoSyncSessionJob(scoped_ptr<SyncSessionJob> job, 691 bool SyncSchedulerImpl::DoSyncSessionJob(scoped_ptr<SyncSessionJob> job,
717 JobPriority priority) { 692 JobPriority priority) {
718 DCHECK_EQ(MessageLoop::current(), sync_loop_); 693 DCHECK_EQ(MessageLoop::current(), sync_loop_);
719 if (job->purpose() == SyncSessionJob::NUDGE) { 694 if (job->purpose() == SyncSessionJob::NUDGE) {
720 if (pending_nudge_ == NULL || 695 if (pending_nudge_ == NULL ||
721 pending_nudge_->session() != job->session()) { 696 pending_nudge_->session() != job->session()) {
722 // |job| is abandoned. 697 // |job| is abandoned.
723 SDVLOG(2) << "Dropping a nudge in " 698 SDVLOG(2) << "Dropping a nudge in "
724 << "DoSyncSessionJob because another nudge was scheduled"; 699 << "DoSyncSessionJob because another nudge was scheduled";
725 return false; 700 return false;
(...skipping 23 matching lines...) Expand all
749 return false; 724 return false;
750 } 725 }
751 726
752 SDVLOG(2) << "Calling SyncShare with " 727 SDVLOG(2) << "Calling SyncShare with "
753 << SyncSessionJob::GetPurposeString(job->purpose()) << " job"; 728 << SyncSessionJob::GetPurposeString(job->purpose()) << " job";
754 bool premature_exit = !syncer_->SyncShare(job->mutable_session(), 729 bool premature_exit = !syncer_->SyncShare(job->mutable_session(),
755 job->start_step(), 730 job->start_step(),
756 job->end_step()); 731 job->end_step());
757 SDVLOG(2) << "Done SyncShare, returned: " << premature_exit; 732 SDVLOG(2) << "Done SyncShare, returned: " << premature_exit;
758 733
759 return FinishSyncSessionJob(job.Pass(), premature_exit); 734 bool success = FinishSyncSessionJob(job.get(), premature_exit);
735
736 if (IsSyncingCurrentlySilenced()) {
737 SDVLOG(2) << "We are currently throttled; scheduling Unthrottle.";
738 // If we're here, it's because |job| was silenced until a server specified
739 // time. (Note, it had to be |job|, because DecideOnJob would not permit
740 // any job through while in WaitInterval::THROTTLED).
741 scoped_ptr<SyncSessionJob> clone = job->Clone();
742 if (clone->purpose() == SyncSessionJob::NUDGE)
743 pending_nudge_ = clone.get();
744 else if (clone->purpose() == SyncSessionJob::CONFIGURATION)
745 wait_interval_->pending_configure_job = clone.get();
746 else
747 NOTREACHED();
748
749 RestartWaiting(clone.Pass());
750 return success;
751 }
752
753 if (!success)
754 ScheduleNextSync(job.Pass());
755
756 return success;
757 }
758
759 bool SyncSchedulerImpl::ShouldPoll() {
760 if (wait_interval_.get()) {
761 SDVLOG(2) << "Not running poll in wait interval.";
762 return false;
763 }
764
765 if (mode_ == CONFIGURATION_MODE) {
766 SDVLOG(2) << "Not running poll in configuration mode.";
767 return false;
768 }
769
770 // TODO(rlarocque): Refactor decision-making logic common to all types
771 // of jobs into a shared function.
772
773 if (session_context_->connection_manager()->HasInvalidAuthToken()) {
774 SDVLOG(2) << "Not running poll because auth token is invalid.";
775 return false;
776 }
777
778 return true;
779 }
780
781 void SyncSchedulerImpl::DoPollSyncSessionJob(scoped_ptr<SyncSessionJob> job) {
782 DCHECK_EQ(job->purpose(), SyncSessionJob::POLL);
783
784 base::AutoReset<bool> protector(&no_scheduling_allowed_, true);
785
786 if (!ShouldPoll())
787 return;
788
789 SDVLOG(2) << "Calling SyncShare with "
790 << SyncSessionJob::GetPurposeString(job->purpose()) << " job";
791 bool premature_exit = !syncer_->SyncShare(job->mutable_session(),
792 job->start_step(),
793 job->end_step());
794 SDVLOG(2) << "Done SyncShare, returned: " << premature_exit;
795
796 FinishSyncSessionJob(job.get(), premature_exit);
797
798 if (IsSyncingCurrentlySilenced()) {
799 // This will start the countdown to unthrottle. Other kinds of jobs would
800 // schedule themselves as the post-unthrottle canary. A poll job is not
801 // that urgent, so it does not get to be the canary. We still need to start
802 // the timer regardless. Otherwise there could be no one to clear the
803 // WaitInterval when the throttling expires.
804 RestartWaiting(scoped_ptr<SyncSessionJob>());
805 }
760 } 806 }
761 807
762 void SyncSchedulerImpl::UpdateNudgeTimeRecords(const SyncSourceInfo& info) { 808 void SyncSchedulerImpl::UpdateNudgeTimeRecords(const SyncSourceInfo& info) {
763 DCHECK_EQ(MessageLoop::current(), sync_loop_); 809 DCHECK_EQ(MessageLoop::current(), sync_loop_);
764 810
765 // We are interested in recording time between local nudges for datatypes. 811 // We are interested in recording time between local nudges for datatypes.
766 // TODO(tim): Consider tracking LOCAL_NOTIFICATION as well. 812 // TODO(tim): Consider tracking LOCAL_NOTIFICATION as well.
767 if (info.updates_source != GetUpdatesCallerInfo::LOCAL) 813 if (info.updates_source != GetUpdatesCallerInfo::LOCAL)
768 return; 814 return;
769 815
770 base::TimeTicks now = TimeTicks::Now(); 816 base::TimeTicks now = TimeTicks::Now();
771 // Update timing information for how often datatypes are triggering nudges. 817 // Update timing information for how often datatypes are triggering nudges.
772 for (ModelTypeInvalidationMap::const_iterator iter = info.types.begin(); 818 for (ModelTypeInvalidationMap::const_iterator iter = info.types.begin();
773 iter != info.types.end(); 819 iter != info.types.end();
774 ++iter) { 820 ++iter) {
775 base::TimeTicks previous = last_local_nudges_by_model_type_[iter->first]; 821 base::TimeTicks previous = last_local_nudges_by_model_type_[iter->first];
776 last_local_nudges_by_model_type_[iter->first] = now; 822 last_local_nudges_by_model_type_[iter->first] = now;
777 if (previous.is_null()) 823 if (previous.is_null())
778 continue; 824 continue;
779 825
780 #define PER_DATA_TYPE_MACRO(type_str) \ 826 #define PER_DATA_TYPE_MACRO(type_str) \
781 SYNC_FREQ_HISTOGRAM("Sync.Freq" type_str, now - previous); 827 SYNC_FREQ_HISTOGRAM("Sync.Freq" type_str, now - previous);
782 SYNC_DATA_TYPE_HISTOGRAM(iter->first); 828 SYNC_DATA_TYPE_HISTOGRAM(iter->first);
783 #undef PER_DATA_TYPE_MACRO 829 #undef PER_DATA_TYPE_MACRO
784 } 830 }
785 } 831 }
786 832
787 bool SyncSchedulerImpl::FinishSyncSessionJob(scoped_ptr<SyncSessionJob> job, 833 bool SyncSchedulerImpl::FinishSyncSessionJob(SyncSessionJob* job,
788 bool exited_prematurely) { 834 bool exited_prematurely) {
789 DCHECK_EQ(MessageLoop::current(), sync_loop_); 835 DCHECK_EQ(MessageLoop::current(), sync_loop_);
790 836
791 // Let job know that we're through syncing (calling SyncShare) at this point. 837 // Let job know that we're through syncing (calling SyncShare) at this point.
792 bool succeeded = false; 838 bool succeeded = false;
793 { 839 {
794 base::AutoReset<bool> protector(&no_scheduling_allowed_, true); 840 base::AutoReset<bool> protector(&no_scheduling_allowed_, true);
795 succeeded = job->Finish(exited_prematurely); 841 succeeded = job->Finish(exited_prematurely);
796 } 842 }
797 843
798 SDVLOG(2) << "Updating the next polling time after SyncMain"; 844 SDVLOG(2) << "Updating the next polling time after SyncMain";
799 ScheduleNextSync(job.Pass(), succeeded);
800 return succeeded;
801 }
802 845
803 void SyncSchedulerImpl::ScheduleNextSync( 846 AdjustPolling(job);
804 scoped_ptr<SyncSessionJob> finished_job, bool succeeded) {
805 DCHECK_EQ(MessageLoop::current(), sync_loop_);
806
807 AdjustPolling(finished_job.get());
808 847
809 if (succeeded) { 848 if (succeeded) {
810 // No job currently supported by the scheduler could succeed without 849 // No job currently supported by the scheduler could succeed without
811 // successfully reaching the server. Therefore, if we make it here, it is 850 // successfully reaching the server. Therefore, if we make it here, it is
812 // appropriate to reset the backoff interval. 851 // appropriate to reset the backoff interval.
813 wait_interval_.reset(); 852 wait_interval_.reset();
814 NotifyRetryTime(base::Time()); 853 NotifyRetryTime(base::Time());
815 SDVLOG(2) << "Job succeeded so not scheduling more jobs"; 854 SDVLOG(2) << "Job succeeded so not scheduling more jobs";
816 return;
817 } 855 }
818 856
819 if (IsSyncingCurrentlySilenced()) { 857 return succeeded;
820 SDVLOG(2) << "We are currently throttled; scheduling Unthrottle."; 858 }
821 // If we're here, it's because |job| was silenced until a server specified
822 // time. (Note, it had to be |job|, because DecideOnJob would not permit
823 // any job through while in WaitInterval::THROTTLED).
824 scoped_ptr<SyncSessionJob> clone = finished_job->Clone();
825 if (clone->purpose() == SyncSessionJob::NUDGE)
826 pending_nudge_ = clone.get();
827 else if (clone->purpose() == SyncSessionJob::CONFIGURATION)
828 wait_interval_->pending_configure_job = clone.get();
829 else
830 clone.reset(); // Unthrottling is enough, no need to force a canary.
831 859
832 RestartWaiting(clone.Pass()); 860 void SyncSchedulerImpl::ScheduleNextSync(
833 return; 861 scoped_ptr<SyncSessionJob> finished_job) {
834 } 862 DCHECK_EQ(MessageLoop::current(), sync_loop_);
835 863 DCHECK(finished_job->purpose() == SyncSessionJob::CONFIGURATION
836 if (finished_job->purpose() == SyncSessionJob::POLL) { 864 || finished_job->purpose() == SyncSessionJob::NUDGE);
837 return; // We don't retry POLL jobs.
838 }
839 865
840 // TODO(rlarocque): There's no reason why we should blindly backoff and retry 866 // TODO(rlarocque): There's no reason why we should blindly backoff and retry
841 // if we don't succeed. Some types of errors are not likely to disappear on 867 // if we don't succeed. Some types of errors are not likely to disappear on
842 // their own. With the return values now available in the old_job.session, 868 // their own. With the return values now available in the old_job.session,
843 // we should be able to detect such errors and only retry when we detect 869 // we should be able to detect such errors and only retry when we detect
844 // transient errors. 870 // transient errors.
845 871
846 if (IsBackingOff() && wait_interval_->timer.IsRunning() && 872 if (IsBackingOff() && wait_interval_->timer.IsRunning() &&
847 mode_ == NORMAL_MODE) { 873 mode_ == NORMAL_MODE) {
848 // When in normal mode, we allow up to one nudge per backoff interval. It 874 // When in normal mode, we allow up to one nudge per backoff interval. It
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 void SyncSchedulerImpl::DoCanaryJob(scoped_ptr<SyncSessionJob> to_be_canary) { 999 void SyncSchedulerImpl::DoCanaryJob(scoped_ptr<SyncSessionJob> to_be_canary) {
974 DCHECK_EQ(MessageLoop::current(), sync_loop_); 1000 DCHECK_EQ(MessageLoop::current(), sync_loop_);
975 SDVLOG(2) << "Do canary job"; 1001 SDVLOG(2) << "Do canary job";
976 1002
977 if (to_be_canary->purpose() == SyncSessionJob::NUDGE) { 1003 if (to_be_canary->purpose() == SyncSessionJob::NUDGE) {
978 // TODO(tim): Bug 158313. Remove this check. 1004 // TODO(tim): Bug 158313. Remove this check.
979 if (pending_nudge_ == NULL || 1005 if (pending_nudge_ == NULL ||
980 pending_nudge_->session() != to_be_canary->session()) { 1006 pending_nudge_->session() != to_be_canary->session()) {
981 // |job| is abandoned. 1007 // |job| is abandoned.
982 SDVLOG(2) << "Dropping a nudge in " 1008 SDVLOG(2) << "Dropping a nudge in "
983 << "DoSyncSessionJob because another nudge was scheduled"; 1009 << "DoCanaryJob because another nudge was scheduled";
984 return; 1010 return;
985 } 1011 }
986 DCHECK_EQ(pending_nudge_->session(), to_be_canary->session()); 1012 DCHECK_EQ(pending_nudge_->session(), to_be_canary->session());
987 } 1013 }
988 1014
989 // This is the only place where we invoke DoSyncSessionJob with canary 1015 // This is the only place where we invoke DoSyncSessionJob with canary
990 // privileges. Everyone else should use NORMAL_PRIORITY. 1016 // privileges. Everyone else should use NORMAL_PRIORITY.
991 DoSyncSessionJob(to_be_canary.Pass(), CANARY_PRIORITY); 1017 DoSyncSessionJob(to_be_canary.Pass(), CANARY_PRIORITY);
992 } 1018 }
993 1019
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 DCHECK_EQ(MessageLoop::current(), sync_loop_); 1054 DCHECK_EQ(MessageLoop::current(), sync_loop_);
1029 ModelSafeRoutingInfo r; 1055 ModelSafeRoutingInfo r;
1030 ModelTypeInvalidationMap invalidation_map = 1056 ModelTypeInvalidationMap invalidation_map =
1031 ModelSafeRoutingInfoToInvalidationMap(r, std::string()); 1057 ModelSafeRoutingInfoToInvalidationMap(r, std::string());
1032 SyncSourceInfo info(GetUpdatesCallerInfo::PERIODIC, invalidation_map); 1058 SyncSourceInfo info(GetUpdatesCallerInfo::PERIODIC, invalidation_map);
1033 scoped_ptr<SyncSession> s(CreateSyncSession(info)); 1059 scoped_ptr<SyncSession> s(CreateSyncSession(info));
1034 scoped_ptr<SyncSessionJob> job(new SyncSessionJob(SyncSessionJob::POLL, 1060 scoped_ptr<SyncSessionJob> job(new SyncSessionJob(SyncSessionJob::POLL,
1035 TimeTicks::Now(), 1061 TimeTicks::Now(),
1036 s.Pass(), 1062 s.Pass(),
1037 ConfigurationParams())); 1063 ConfigurationParams()));
1038 ScheduleSyncSessionJob(FROM_HERE, job.Pass()); 1064 if (no_scheduling_allowed_) {
1065 // The no_scheduling_allowed_ flag is set by a function-scoped AutoReset in
1066 // functions that are called only on the sync thread. This function is also
1067 // called only on the sync thread, and only when it is posted by an expiring
1068 // timer. If we find that no_scheduling_allowed_ is set here, then
1069 // something is very wrong. Maybe someone mistakenly called us directly, or
1070 // mishandled the book-keeping for no_scheduling_allowed_.
1071 NOTREACHED() << "Illegal to schedule job while session in progress.";
1072 return;
1073 }
1074
1075 DoPollSyncSessionJob(job.Pass());
1039 } 1076 }
1040 1077
1041 void SyncSchedulerImpl::Unthrottle(scoped_ptr<SyncSessionJob> to_be_canary) { 1078 void SyncSchedulerImpl::Unthrottle(scoped_ptr<SyncSessionJob> to_be_canary) {
1042 DCHECK_EQ(MessageLoop::current(), sync_loop_); 1079 DCHECK_EQ(MessageLoop::current(), sync_loop_);
1043 DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode); 1080 DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode);
1044 DCHECK(!to_be_canary.get() || pending_nudge_ == to_be_canary.get() || 1081 DCHECK(!to_be_canary.get() || pending_nudge_ == to_be_canary.get() ||
1045 wait_interval_->pending_configure_job == to_be_canary.get()); 1082 wait_interval_->pending_configure_job == to_be_canary.get());
1046 SDVLOG(2) << "Unthrottled " << (to_be_canary.get() ? "with " : "without ") 1083 SDVLOG(2) << "Unthrottled " << (to_be_canary.get() ? "with " : "without ")
1047 << "canary."; 1084 << "canary.";
1048 1085
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1151 1188
1152 #undef SDVLOG_LOC 1189 #undef SDVLOG_LOC
1153 1190
1154 #undef SDVLOG 1191 #undef SDVLOG
1155 1192
1156 #undef SLOG 1193 #undef SLOG
1157 1194
1158 #undef ENUM_CASE 1195 #undef ENUM_CASE
1159 1196
1160 } // namespace syncer 1197 } // namespace syncer
OLDNEW
« 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