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 "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" |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/location.h" | 14 #include "base/location.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 17 #include "base/time/default_clock.h" |
17 #include "sync/engine/backoff_delay_provider.h" | 18 #include "sync/engine/backoff_delay_provider.h" |
18 #include "sync/engine/syncer.h" | 19 #include "sync/engine/syncer.h" |
19 #include "sync/notifier/object_id_invalidation_map.h" | 20 #include "sync/notifier/object_id_invalidation_map.h" |
20 #include "sync/protocol/proto_enum_conversions.h" | 21 #include "sync/protocol/proto_enum_conversions.h" |
21 #include "sync/protocol/sync.pb.h" | 22 #include "sync/protocol/sync.pb.h" |
22 #include "sync/util/data_type_histogram.h" | 23 #include "sync/util/data_type_histogram.h" |
23 #include "sync/util/logging.h" | 24 #include "sync/util/logging.h" |
24 | 25 |
25 using base::TimeDelta; | 26 using base::TimeDelta; |
26 using base::TimeTicks; | 27 using base::TimeTicks; |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 } | 228 } |
228 | 229 |
229 DCHECK(!session_context_->account_name().empty()); | 230 DCHECK(!session_context_->account_name().empty()); |
230 DCHECK(syncer_.get()); | 231 DCHECK(syncer_.get()); |
231 Mode old_mode = mode_; | 232 Mode old_mode = mode_; |
232 mode_ = mode; | 233 mode_ = mode; |
233 AdjustPolling(UPDATE_INTERVAL); // Will kick start poll timer if needed. | 234 AdjustPolling(UPDATE_INTERVAL); // Will kick start poll timer if needed. |
234 | 235 |
235 if (old_mode != mode_ && | 236 if (old_mode != mode_ && |
236 mode_ == NORMAL_MODE && | 237 mode_ == NORMAL_MODE && |
237 nudge_tracker_.IsSyncRequired() && | 238 (nudge_tracker_.IsSyncRequired() || |
| 239 nudge_tracker_.IsRetryRequired(base::TimeTicks::Now())) && |
238 CanRunNudgeJobNow(NORMAL_PRIORITY)) { | 240 CanRunNudgeJobNow(NORMAL_PRIORITY)) { |
239 // We just got back to normal mode. Let's try to run the work that was | 241 // We just got back to normal mode. Let's try to run the work that was |
240 // queued up while we were configuring. | 242 // queued up while we were configuring. |
241 TrySyncSessionJob(); | 243 TrySyncSessionJob(); |
242 } | 244 } |
243 } | 245 } |
244 | 246 |
245 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnthrottledTypes() { | 247 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnthrottledTypes() { |
246 ModelTypeSet enabled_types = session_context_->enabled_types(); | 248 ModelTypeSet enabled_types = session_context_->enabled_types(); |
247 ModelTypeSet throttled_types = nudge_tracker_.GetThrottledTypes(); | 249 ModelTypeSet throttled_types = nudge_tracker_.GetThrottledTypes(); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 // Don't run poll job till the next time poll timer fires. | 464 // Don't run poll job till the next time poll timer fires. |
463 do_poll_after_credentials_updated_ = false; | 465 do_poll_after_credentials_updated_ = false; |
464 | 466 |
465 bool success = !premature_exit | 467 bool success = !premature_exit |
466 && !sessions::HasSyncerError( | 468 && !sessions::HasSyncerError( |
467 session->status_controller().model_neutral_state()); | 469 session->status_controller().model_neutral_state()); |
468 | 470 |
469 if (success) { | 471 if (success) { |
470 // That cycle took care of any outstanding work we had. | 472 // That cycle took care of any outstanding work we had. |
471 SDVLOG(2) << "Nudge succeeded."; | 473 SDVLOG(2) << "Nudge succeeded."; |
472 nudge_tracker_.RecordSuccessfulSyncCycle(); | 474 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); |
473 scheduled_nudge_time_ = base::TimeTicks(); | 475 scheduled_nudge_time_ = base::TimeTicks(); |
474 | 476 |
475 // If we're here, then we successfully reached the server. End all backoff. | 477 // If we're here, then we successfully reached the server. End all backoff. |
476 wait_interval_.reset(); | 478 wait_interval_.reset(); |
477 NotifyRetryTime(base::Time()); | 479 NotifyRetryTime(base::Time()); |
478 return; | 480 return; |
479 } else { | 481 } else { |
480 HandleFailure(session->status_controller().model_neutral_state()); | 482 HandleFailure(session->status_controller().model_neutral_state()); |
481 } | 483 } |
482 } | 484 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length)); | 544 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length)); |
543 SDVLOG(2) << "Sync cycle failed. Will back off for " | 545 SDVLOG(2) << "Sync cycle failed. Will back off for " |
544 << wait_interval_->length.InMilliseconds() << "ms."; | 546 << wait_interval_->length.InMilliseconds() << "ms."; |
545 RestartWaiting(); | 547 RestartWaiting(); |
546 } | 548 } |
547 } | 549 } |
548 | 550 |
549 void SyncSchedulerImpl::DoPollSyncSessionJob() { | 551 void SyncSchedulerImpl::DoPollSyncSessionJob() { |
550 base::AutoReset<bool> protector(&no_scheduling_allowed_, true); | 552 base::AutoReset<bool> protector(&no_scheduling_allowed_, true); |
551 | 553 |
552 if (!CanRunJobNow(NORMAL_PRIORITY)) { | |
553 SDVLOG(2) << "Unable to run a poll job right now."; | |
554 return; | |
555 } | |
556 | |
557 if (mode_ != NORMAL_MODE) { | |
558 SDVLOG(2) << "Not running poll job in configure mode."; | |
559 return; | |
560 } | |
561 | |
562 SDVLOG(2) << "Polling with types " | 554 SDVLOG(2) << "Polling with types " |
563 << ModelTypeSetToString(session_context_->enabled_types()); | 555 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes()); |
564 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); | 556 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); |
565 syncer_->PollSyncShare( | 557 syncer_->PollSyncShare( |
566 GetEnabledAndUnthrottledTypes(), | 558 GetEnabledAndUnthrottledTypes(), |
567 session.get()); | 559 session.get()); |
568 | 560 |
569 AdjustPolling(FORCE_RESET); | 561 AdjustPolling(FORCE_RESET); |
570 | 562 |
571 if (IsCurrentlyThrottled()) { | 563 if (IsCurrentlyThrottled()) { |
572 SDVLOG(2) << "Poll request got us throttled."; | 564 SDVLOG(2) << "Poll request got us throttled."; |
573 // The OnSilencedUntil() call set up the WaitInterval for us. All we need | 565 // The OnSilencedUntil() call set up the WaitInterval for us. All we need |
574 // to do is start the timer. | 566 // to do is start the timer. |
575 RestartWaiting(); | 567 RestartWaiting(); |
576 } | 568 } |
577 } | 569 } |
578 | 570 |
| 571 void SyncSchedulerImpl::DoRetrySyncSessionJob() { |
| 572 DCHECK(CalledOnValidThread()); |
| 573 DCHECK_EQ(mode_, NORMAL_MODE); |
| 574 |
| 575 base::AutoReset<bool> protector(&no_scheduling_allowed_, true); |
| 576 |
| 577 SDVLOG(2) << "Retrying with types " |
| 578 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes()); |
| 579 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); |
| 580 if (syncer_->RetrySyncShare(GetEnabledAndUnthrottledTypes(), |
| 581 session.get()) && |
| 582 !sessions::HasSyncerError( |
| 583 session->status_controller().model_neutral_state())) { |
| 584 nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); |
| 585 } else { |
| 586 HandleFailure(session->status_controller().model_neutral_state()); |
| 587 } |
| 588 } |
| 589 |
579 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { | 590 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { |
580 DCHECK(CalledOnValidThread()); | 591 DCHECK(CalledOnValidThread()); |
581 base::TimeTicks now = TimeTicks::Now(); | 592 base::TimeTicks now = TimeTicks::Now(); |
582 // Update timing information for how often datatypes are triggering nudges. | 593 // Update timing information for how often datatypes are triggering nudges. |
583 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) { | 594 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) { |
584 base::TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()]; | 595 base::TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()]; |
585 last_local_nudges_by_model_type_[iter.Get()] = now; | 596 last_local_nudges_by_model_type_[iter.Get()] = now; |
586 if (previous.is_null()) | 597 if (previous.is_null()) |
587 continue; | 598 continue; |
588 | 599 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 void SyncSchedulerImpl::TrySyncSessionJobImpl() { | 687 void SyncSchedulerImpl::TrySyncSessionJobImpl() { |
677 JobPriority priority = next_sync_session_job_priority_; | 688 JobPriority priority = next_sync_session_job_priority_; |
678 next_sync_session_job_priority_ = NORMAL_PRIORITY; | 689 next_sync_session_job_priority_ = NORMAL_PRIORITY; |
679 | 690 |
680 DCHECK(CalledOnValidThread()); | 691 DCHECK(CalledOnValidThread()); |
681 if (mode_ == CONFIGURATION_MODE) { | 692 if (mode_ == CONFIGURATION_MODE) { |
682 if (pending_configure_params_) { | 693 if (pending_configure_params_) { |
683 SDVLOG(2) << "Found pending configure job"; | 694 SDVLOG(2) << "Found pending configure job"; |
684 DoConfigurationSyncSessionJob(priority); | 695 DoConfigurationSyncSessionJob(priority); |
685 } | 696 } |
686 } else { | 697 } else if (CanRunNudgeJobNow(priority)) { |
687 DCHECK(mode_ == NORMAL_MODE); | 698 if (nudge_tracker_.IsSyncRequired()) { |
688 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(priority)) { | |
689 SDVLOG(2) << "Found pending nudge job"; | 699 SDVLOG(2) << "Found pending nudge job"; |
690 DoNudgeSyncSessionJob(priority); | 700 DoNudgeSyncSessionJob(priority); |
| 701 } else if (nudge_tracker_.IsRetryRequired(base::TimeTicks::Now())) { |
| 702 DoRetrySyncSessionJob(); |
691 } else if (do_poll_after_credentials_updated_ || | 703 } else if (do_poll_after_credentials_updated_ || |
692 ((base::TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) { | 704 ((base::TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) { |
693 DoPollSyncSessionJob(); | 705 DoPollSyncSessionJob(); |
694 // Poll timer fires infrequently. Usually by this time access token is | 706 // Poll timer fires infrequently. Usually by this time access token is |
695 // already expired and poll job will fail with auth error. Set flag to | 707 // already expired and poll job will fail with auth error. Set flag to |
696 // retry poll once ProfileSyncService gets new access token, TryCanaryJob | 708 // retry poll once ProfileSyncService gets new access token, TryCanaryJob |
697 // will be called after access token is retrieved. | 709 // will be called after access token is retrieved. |
698 if (HttpResponse::SYNC_AUTH_ERROR == | 710 if (HttpResponse::SYNC_AUTH_ERROR == |
699 session_context_->connection_manager()->server_status()) { | 711 session_context_->connection_manager()->server_status()) { |
700 do_poll_after_credentials_updated_ = true; | 712 do_poll_after_credentials_updated_ = true; |
(...skipping 29 matching lines...) Expand all Loading... |
730 // timer. If we find that no_scheduling_allowed_ is set here, then | 742 // timer. If we find that no_scheduling_allowed_ is set here, then |
731 // something is very wrong. Maybe someone mistakenly called us directly, or | 743 // something is very wrong. Maybe someone mistakenly called us directly, or |
732 // mishandled the book-keeping for no_scheduling_allowed_. | 744 // mishandled the book-keeping for no_scheduling_allowed_. |
733 NOTREACHED() << "Illegal to schedule job while session in progress."; | 745 NOTREACHED() << "Illegal to schedule job while session in progress."; |
734 return; | 746 return; |
735 } | 747 } |
736 | 748 |
737 TrySyncSessionJob(); | 749 TrySyncSessionJob(); |
738 } | 750 } |
739 | 751 |
| 752 void SyncSchedulerImpl::RetryTimerCallback() { |
| 753 TrySyncSessionJob(); |
| 754 } |
| 755 |
740 void SyncSchedulerImpl::Unthrottle() { | 756 void SyncSchedulerImpl::Unthrottle() { |
741 DCHECK(CalledOnValidThread()); | 757 DCHECK(CalledOnValidThread()); |
742 DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode); | 758 DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode); |
743 | 759 |
744 // We're no longer throttled, so clear the wait interval. | 760 // We're no longer throttled, so clear the wait interval. |
745 wait_interval_.reset(); | 761 wait_interval_.reset(); |
746 NotifyRetryTime(base::Time()); | 762 NotifyRetryTime(base::Time()); |
747 | 763 |
748 // We treat this as a 'canary' in the sense that it was originally scheduled | 764 // We treat this as a 'canary' in the sense that it was originally scheduled |
749 // to run some time ago, failed, and we now want to retry, versus a job that | 765 // to run some time ago, failed, and we now want to retry, versus a job that |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
883 DCHECK(CalledOnValidThread()); | 899 DCHECK(CalledOnValidThread()); |
884 if (ShouldRequestEarlyExit( | 900 if (ShouldRequestEarlyExit( |
885 snapshot.model_neutral_state().sync_protocol_error)) { | 901 snapshot.model_neutral_state().sync_protocol_error)) { |
886 SDVLOG(2) << "Sync Scheduler requesting early exit."; | 902 SDVLOG(2) << "Sync Scheduler requesting early exit."; |
887 Stop(); | 903 Stop(); |
888 } | 904 } |
889 if (IsActionableError(snapshot.model_neutral_state().sync_protocol_error)) | 905 if (IsActionableError(snapshot.model_neutral_state().sync_protocol_error)) |
890 OnActionableError(snapshot); | 906 OnActionableError(snapshot); |
891 } | 907 } |
892 | 908 |
| 909 void SyncSchedulerImpl::OnReceivedGuRetryDelaySeconds(int delay_seconds) { |
| 910 nudge_tracker_.set_next_retry_time( |
| 911 base::TimeTicks::Now() + base::TimeDelta::FromSeconds(delay_seconds)); |
| 912 retry_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds), |
| 913 this, &SyncSchedulerImpl::RetryTimerCallback); |
| 914 } |
| 915 |
893 void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) { | 916 void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) { |
894 DCHECK(CalledOnValidThread()); | 917 DCHECK(CalledOnValidThread()); |
895 session_context_->set_notifications_enabled(notifications_enabled); | 918 session_context_->set_notifications_enabled(notifications_enabled); |
896 if (notifications_enabled) | 919 if (notifications_enabled) |
897 nudge_tracker_.OnInvalidationsEnabled(); | 920 nudge_tracker_.OnInvalidationsEnabled(); |
898 else | 921 else |
899 nudge_tracker_.OnInvalidationsDisabled(); | 922 nudge_tracker_.OnInvalidationsDisabled(); |
900 } | 923 } |
901 | 924 |
902 base::TimeDelta SyncSchedulerImpl::GetSessionsCommitDelay() const { | 925 base::TimeDelta SyncSchedulerImpl::GetSessionsCommitDelay() const { |
903 DCHECK(CalledOnValidThread()); | 926 DCHECK(CalledOnValidThread()); |
904 return sessions_commit_delay_; | 927 return sessions_commit_delay_; |
905 } | 928 } |
906 | 929 |
907 #undef SDVLOG_LOC | 930 #undef SDVLOG_LOC |
908 | 931 |
909 #undef SDVLOG | 932 #undef SDVLOG |
910 | 933 |
911 #undef SLOG | 934 #undef SLOG |
912 | 935 |
913 #undef ENUM_CASE | 936 #undef ENUM_CASE |
914 | 937 |
915 } // namespace syncer | 938 } // namespace syncer |
OLD | NEW |