diff options
author | haitaol@chromium.org <haitaol@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-14 16:17:43 +0000 |
---|---|---|
committer | haitaol@chromium.org <haitaol@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-14 16:17:43 +0000 |
commit | 3dfc7b7970b85378523b53bea33b1139dceaca6e (patch) | |
tree | 74450de20b350f2995db44f319b8da0f4911e97d /sync/engine | |
parent | ea7f19230d44bd71eef8082ee79740d11ac047d1 (diff) | |
download | chromium_src-3dfc7b7970b85378523b53bea33b1139dceaca6e.zip chromium_src-3dfc7b7970b85378523b53bea33b1139dceaca6e.tar.gz chromium_src-3dfc7b7970b85378523b53bea33b1139dceaca6e.tar.bz2 |
[Recommit]
Support GU retry command in sync engine. The command specifies a delay after which syncer should issue a GU to pick up updates missed by last GU.
TBR=rlarocque@chromium.org
Review URL: https://codereview.chromium.org/133763007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244736 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/engine')
-rw-r--r-- | sync/engine/download.cc | 40 | ||||
-rw-r--r-- | sync/engine/download.h | 15 | ||||
-rw-r--r-- | sync/engine/download_unittest.cc | 37 | ||||
-rw-r--r-- | sync/engine/sync_scheduler_impl.cc | 53 | ||||
-rw-r--r-- | sync/engine/sync_scheduler_impl.h | 16 | ||||
-rw-r--r-- | sync/engine/sync_scheduler_unittest.cc | 122 | ||||
-rw-r--r-- | sync/engine/syncer.cc | 16 | ||||
-rw-r--r-- | sync/engine/syncer.h | 2 | ||||
-rw-r--r-- | sync/engine/syncer_proto_util.cc | 5 | ||||
-rw-r--r-- | sync/engine/syncer_unittest.cc | 5 |
10 files changed, 276 insertions, 35 deletions
diff --git a/sync/engine/download.cc b/sync/engine/download.cc index 2bc7f7a..448481f 100644 --- a/sync/engine/download.cc +++ b/sync/engine/download.cc @@ -234,6 +234,8 @@ void BuildNormalDownloadUpdatesImpl( // Set the new and improved version of source, too. get_updates->set_get_updates_origin(sync_pb::SyncEnums::GU_TRIGGER); + get_updates->set_is_retry( + nudge_tracker.IsRetryRequired(base::TimeTicks::Now())); // Fill in the notification hints. for (int i = 0; i < get_updates->from_progress_marker_size(); ++i) { @@ -331,6 +333,44 @@ void BuildDownloadUpdatesForPollImpl( get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC); } +void BuildDownloadUpdatesForRetry( + SyncSession* session, + bool create_mobile_bookmarks_folder, + ModelTypeSet request_types, + sync_pb::ClientToServerMessage* client_to_server_message) { + DVLOG(1) << "Retrying for types " + << ModelTypeSetToString(request_types); + + InitDownloadUpdatesContext( + session, + create_mobile_bookmarks_folder, + client_to_server_message); + BuildDownloadUpdatesForRetryImpl( + Intersection(request_types, ProtocolTypes()), + session->context()->update_handler_map(), + client_to_server_message->mutable_get_updates()); +} + +void BuildDownloadUpdatesForRetryImpl( + ModelTypeSet proto_request_types, + UpdateHandlerMap* update_handler_map, + sync_pb::GetUpdatesMessage* get_updates) { + DCHECK(!proto_request_types.Empty()); + + InitDownloadUpdatesProgress( + proto_request_types, + update_handler_map, + get_updates); + + // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. + get_updates->mutable_caller_info()->set_source( + sync_pb::GetUpdatesCallerInfo::RETRY); + + // Set the new and improved version of source, too. + get_updates->set_get_updates_origin(sync_pb::SyncEnums::RETRY); + get_updates->set_is_retry(true); +} + SyncerError ExecuteDownloadUpdates( ModelTypeSet request_types, SyncSession* session, diff --git a/sync/engine/download.h b/sync/engine/download.h index 5bc08d4..e3230d8 100644 --- a/sync/engine/download.h +++ b/sync/engine/download.h @@ -75,6 +75,21 @@ SYNC_EXPORT_PRIVATE void BuildDownloadUpdatesForPollImpl( UpdateHandlerMap* update_handler_map, sync_pb::GetUpdatesMessage* get_updates); +// Same as BuildDownloadUpdatesForPoll() except the update origin/source is +// RETRY. +SYNC_EXPORT_PRIVATE void BuildDownloadUpdatesForRetry( + sessions::SyncSession* session, + bool create_mobile_bookmarks_folder, + ModelTypeSet request_types, + sync_pb::ClientToServerMessage* client_to_server_message); + +// Same as BuildDownloadUpdatesForPollImpl() except the update origin/source is +// RETRY. +SYNC_EXPORT_PRIVATE void BuildDownloadUpdatesForRetryImpl( + ModelTypeSet proto_request_types, + UpdateHandlerMap* update_handler_map, + sync_pb::GetUpdatesMessage* get_updates); + // Sends the specified message to the server and stores the response in a member // of the |session|'s StatusController. SYNC_EXPORT_PRIVATE SyncerError diff --git a/sync/engine/download_unittest.cc b/sync/engine/download_unittest.cc index eae6277..134f441 100644 --- a/sync/engine/download_unittest.cc +++ b/sync/engine/download_unittest.cc @@ -219,6 +219,43 @@ TEST_F(DownloadUpdatesTest, PollTest) { EXPECT_TRUE(proto_request_types().Equals(progress_types)); } +TEST_F(DownloadUpdatesTest, RetryTest) { + sync_pb::ClientToServerMessage msg; + download::BuildDownloadUpdatesForRetryImpl( + proto_request_types(), + update_handler_map(), + msg.mutable_get_updates()); + + const sync_pb::GetUpdatesMessage& gu_msg = msg.get_updates(); + + EXPECT_EQ(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin()); + EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY, + gu_msg.caller_info().source()); + EXPECT_TRUE(gu_msg.is_retry()); + + ModelTypeSet progress_types; + for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) { + syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber( + gu_msg.from_progress_marker(i).data_type_id()); + progress_types.Put(type); + } + EXPECT_TRUE(proto_request_types().Equals(progress_types)); +} + +TEST_F(DownloadUpdatesTest, NudgeWithRetryTest) { + sessions::NudgeTracker nudge_tracker; + nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS)); + nudge_tracker.set_next_retry_time( + base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1)); + + sync_pb::ClientToServerMessage msg; + download::BuildNormalDownloadUpdatesImpl(proto_request_types(), + update_handler_map(), + nudge_tracker, + msg.mutable_get_updates()); + EXPECT_TRUE(msg.get_updates().is_retry()); +} + // Verify that a bogus response message is detected. TEST_F(DownloadUpdatesTest, InvalidResponse) { sync_pb::GetUpdatesResponse gu_response; diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc index 6a4f1ef..6c784bc 100644 --- a/sync/engine/sync_scheduler_impl.cc +++ b/sync/engine/sync_scheduler_impl.cc @@ -234,7 +234,8 @@ void SyncSchedulerImpl::Start(Mode mode) { if (old_mode != mode_ && mode_ == NORMAL_MODE && - nudge_tracker_.IsSyncRequired() && + (nudge_tracker_.IsSyncRequired() || + nudge_tracker_.IsRetryRequired(base::TimeTicks::Now())) && CanRunNudgeJobNow(NORMAL_PRIORITY)) { // We just got back to normal mode. Let's try to run the work that was // queued up while we were configuring. @@ -469,7 +470,7 @@ void SyncSchedulerImpl::DoNudgeSyncSessionJob(JobPriority priority) { if (success) { // That cycle took care of any outstanding work we had. SDVLOG(2) << "Nudge succeeded."; - nudge_tracker_.RecordSuccessfulSyncCycle(); + nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); scheduled_nudge_time_ = base::TimeTicks(); // If we're here, then we successfully reached the server. End all backoff. @@ -549,18 +550,8 @@ void SyncSchedulerImpl::HandleFailure( void SyncSchedulerImpl::DoPollSyncSessionJob() { base::AutoReset<bool> protector(&no_scheduling_allowed_, true); - if (!CanRunJobNow(NORMAL_PRIORITY)) { - SDVLOG(2) << "Unable to run a poll job right now."; - return; - } - - if (mode_ != NORMAL_MODE) { - SDVLOG(2) << "Not running poll job in configure mode."; - return; - } - SDVLOG(2) << "Polling with types " - << ModelTypeSetToString(session_context_->enabled_types()); + << ModelTypeSetToString(GetEnabledAndUnthrottledTypes()); scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); syncer_->PollSyncShare( GetEnabledAndUnthrottledTypes(), @@ -576,6 +567,25 @@ void SyncSchedulerImpl::DoPollSyncSessionJob() { } } +void SyncSchedulerImpl::DoRetrySyncSessionJob() { + DCHECK(CalledOnValidThread()); + DCHECK_EQ(mode_, NORMAL_MODE); + + base::AutoReset<bool> protector(&no_scheduling_allowed_, true); + + SDVLOG(2) << "Retrying with types " + << ModelTypeSetToString(GetEnabledAndUnthrottledTypes()); + scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); + if (syncer_->RetrySyncShare(GetEnabledAndUnthrottledTypes(), + session.get()) && + !sessions::HasSyncerError( + session->status_controller().model_neutral_state())) { + nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); + } else { + HandleFailure(session->status_controller().model_neutral_state()); + } +} + void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { DCHECK(CalledOnValidThread()); base::TimeTicks now = TimeTicks::Now(); @@ -683,11 +693,12 @@ void SyncSchedulerImpl::TrySyncSessionJobImpl() { SDVLOG(2) << "Found pending configure job"; DoConfigurationSyncSessionJob(priority); } - } else { - DCHECK(mode_ == NORMAL_MODE); - if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(priority)) { + } else if (CanRunNudgeJobNow(priority)) { + if (nudge_tracker_.IsSyncRequired()) { SDVLOG(2) << "Found pending nudge job"; DoNudgeSyncSessionJob(priority); + } else if (nudge_tracker_.IsRetryRequired(base::TimeTicks::Now())) { + DoRetrySyncSessionJob(); } else if (do_poll_after_credentials_updated_ || ((base::TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) { DoPollSyncSessionJob(); @@ -737,6 +748,10 @@ void SyncSchedulerImpl::PollTimerCallback() { TrySyncSessionJob(); } +void SyncSchedulerImpl::RetryTimerCallback() { + TrySyncSessionJob(); +} + void SyncSchedulerImpl::Unthrottle() { DCHECK(CalledOnValidThread()); DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode); @@ -890,6 +905,12 @@ void SyncSchedulerImpl::OnSyncProtocolError( OnActionableError(snapshot); } +void SyncSchedulerImpl::OnReceivedGuRetryDelay(const base::TimeDelta& delay) { + nudge_tracker_.set_next_retry_time(base::TimeTicks::Now() + delay); + retry_timer_.Start(FROM_HERE, delay, this, + &SyncSchedulerImpl::RetryTimerCallback); +} + void SyncSchedulerImpl::SetNotificationsEnabled(bool notifications_enabled) { DCHECK(CalledOnValidThread()); session_context_->set_notifications_enabled(notifications_enabled); diff --git a/sync/engine/sync_scheduler_impl.h b/sync/engine/sync_scheduler_impl.h index 81a4fcf..68d2a80 100644 --- a/sync/engine/sync_scheduler_impl.h +++ b/sync/engine/sync_scheduler_impl.h @@ -89,6 +89,10 @@ class SYNC_EXPORT_PRIVATE SyncSchedulerImpl virtual void OnReceivedClientInvalidationHintBufferSize(int size) OVERRIDE; virtual void OnSyncProtocolError( const sessions::SyncSessionSnapshot& snapshot) OVERRIDE; + virtual void OnReceivedGuRetryDelay(const base::TimeDelta& delay) OVERRIDE; + + // Returns true if the client is currently in exponential backoff. + bool IsBackingOff() const; private: enum JobPriority { @@ -167,6 +171,9 @@ class SYNC_EXPORT_PRIVATE SyncSchedulerImpl // Invoke the Syncer to perform a poll job. void DoPollSyncSessionJob(); + // Invoke the Syncer to perform a retry job. + void DoRetrySyncSessionJob(); + // Helper function to calculate poll interval. base::TimeDelta GetPollInterval(); @@ -191,9 +198,6 @@ class SYNC_EXPORT_PRIVATE SyncSchedulerImpl const base::TimeDelta& delay, const tracked_objects::Location& nudge_location); - // Returns true if the client is currently in exponential backoff. - bool IsBackingOff() const; - // Helper to signal all listeners registered with |session_context_|. void Notify(SyncEngineEvent::EventCause cause); @@ -230,6 +234,9 @@ class SYNC_EXPORT_PRIVATE SyncSchedulerImpl // Creates a session for a poll and performs the sync. void PollTimerCallback(); + // Creates a session for a retry and performs the sync. + void RetryTimerCallback(); + // Returns the set of types that are enabled and not currently throttled. ModelTypeSet GetEnabledAndUnthrottledTypes(); @@ -336,6 +343,9 @@ class SYNC_EXPORT_PRIVATE SyncSchedulerImpl // to be const and alleviate threading concerns. base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_for_weak_handle_; + // One-shot timer for scheduling GU retry according to delay set by server. + base::OneShotTimer<SyncSchedulerImpl> retry_timer_; + DISALLOW_COPY_AND_ASSIGN(SyncSchedulerImpl); }; diff --git a/sync/engine/sync_scheduler_unittest.cc b/sync/engine/sync_scheduler_unittest.cc index 97d9ab8..62aa2c9 100644 --- a/sync/engine/sync_scheduler_unittest.cc +++ b/sync/engine/sync_scheduler_unittest.cc @@ -34,6 +34,7 @@ using testing::Mock; using testing::Return; using testing::WithArg; using testing::WithArgs; +using testing::WithoutArgs; namespace syncer { using sessions::SyncSession; @@ -51,6 +52,7 @@ class MockSyncer : public Syncer { sync_pb::GetUpdatesCallerInfo::GetUpdatesSource, SyncSession*)); MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, sessions::SyncSession*)); + MOCK_METHOD2(RetrySyncShare, bool(ModelTypeSet, sessions::SyncSession*)); }; MockSyncer::MockSyncer() @@ -210,6 +212,11 @@ class SyncSchedulerTest : public testing::Test { return scheduler_->nudge_tracker_.GetThrottledTypes(); } + base::TimeDelta GetRetryTimerDelay() { + EXPECT_TRUE(scheduler_->retry_timer_.IsRunning()); + return scheduler_->retry_timer_.GetCurrentDelay(); + } + private: syncable::Directory* directory() { return dir_maker_.directory(); @@ -539,8 +546,9 @@ TEST_F(SyncSchedulerTest, Polling) { SyncShareTimes times; TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples)) - .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess), - RecordSyncShareMultiple(×, kMinNumSamples))); + .WillRepeatedly( + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), + RecordSyncShareMultiple(×, kMinNumSamples))); scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval); @@ -559,8 +567,9 @@ TEST_F(SyncSchedulerTest, PollNotificationsDisabled) { SyncShareTimes times; TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples)) - .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess), - RecordSyncShareMultiple(×, kMinNumSamples))); + .WillRepeatedly( + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), + RecordSyncShareMultiple(×, kMinNumSamples))); scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval); scheduler()->SetNotificationsEnabled(false); @@ -587,7 +596,7 @@ TEST_F(SyncSchedulerTest, PollIntervalUpdate) { sessions::test_util::SimulatePollIntervalUpdate(poll2)), Return(true))) .WillRepeatedly( - DoAll(Invoke(sessions::test_util::SimulatePollSuccess), + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), WithArg<1>( RecordSyncShareMultiple(×, kMinNumSamples)))); @@ -678,8 +687,9 @@ TEST_F(SyncSchedulerTest, ThrottlingExpiresFromPoll) { Return(true))) .RetiresOnSaturation(); EXPECT_CALL(*syncer(), PollSyncShare(_,_)) - .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess), - RecordSyncShareMultiple(×, kMinNumSamples))); + .WillRepeatedly( + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), + RecordSyncShareMultiple(×, kMinNumSamples))); TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1; StartSyncScheduler(SyncScheduler::NORMAL_MODE); @@ -1111,7 +1121,7 @@ TEST_F(SyncSchedulerTest, BackoffRelief) { // Now let the Poll timer do its thing. EXPECT_CALL(*syncer(), PollSyncShare(_,_)) .WillRepeatedly(DoAll( - Invoke(sessions::test_util::SimulatePollSuccess), + Invoke(sessions::test_util::SimulatePollRetrySuccess), RecordSyncShareMultiple(×, kMinNumSamples))); RunLoop(); Mock::VerifyAndClearExpectations(syncer()); @@ -1134,9 +1144,9 @@ TEST_F(SyncSchedulerTest, TransientPollFailure) { UseMockDelayProvider(); // Will cause test failure if backoff is initiated. EXPECT_CALL(*syncer(), PollSyncShare(_,_)) - .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollFailed), + .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollRetryFailed), RecordSyncShare(×))) - .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess), + .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), RecordSyncShare(×))); StartSyncScheduler(SyncScheduler::NORMAL_MODE); @@ -1269,8 +1279,9 @@ TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) { ::testing::InSequence seq; EXPECT_CALL(*syncer(), PollSyncShare(_,_)) - .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess), - RecordSyncShareMultiple(×, kMinNumSamples))); + .WillRepeatedly( + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), + RecordSyncShareMultiple(×, kMinNumSamples))); connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR); StartSyncScheduler(SyncScheduler::NORMAL_MODE); @@ -1282,7 +1293,7 @@ TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) { // but after poll finished with auth error from poll timer it should retry // poll once more EXPECT_CALL(*syncer(), PollSyncShare(_,_)) - .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess), + .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), RecordSyncShare(×))); scheduler()->OnCredentialsUpdated(); connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK); @@ -1290,4 +1301,89 @@ TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) { StopSyncScheduler(); } +TEST_F(SyncSchedulerTest, SuccessfulRetry) { + StartSyncScheduler(SyncScheduler::NORMAL_MODE); + + SyncShareTimes times; + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1); + scheduler()->OnReceivedGuRetryDelay(delay); + EXPECT_EQ(delay, GetRetryTimerDelay()); + + EXPECT_CALL(*syncer(), RetrySyncShare(_,_)) + .WillOnce( + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), + RecordSyncShare(×))); + + // Run to wait for retrying. + RunLoop(); + + StopSyncScheduler(); +} + +TEST_F(SyncSchedulerTest, FailedRetry) { + UseMockDelayProvider(); + EXPECT_CALL(*delay(), GetDelay(_)) + .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1))); + + StartSyncScheduler(SyncScheduler::NORMAL_MODE); + + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1); + scheduler()->OnReceivedGuRetryDelay(delay); + + EXPECT_CALL(*syncer(), RetrySyncShare(_,_)) + .WillOnce( + DoAll(Invoke(sessions::test_util::SimulatePollRetryFailed), + QuitLoopNowAction())); + + // Run to wait for retrying. + RunLoop(); + + EXPECT_TRUE(scheduler()->IsBackingOff()); + EXPECT_CALL(*syncer(), RetrySyncShare(_,_)) + .WillOnce( + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), + QuitLoopNowAction())); + + // Run to wait for second retrying. + RunLoop(); + + StopSyncScheduler(); +} + +ACTION_P2(VerifyRetryTimerDelay, scheduler_test, expected_delay) { + EXPECT_EQ(expected_delay, scheduler_test->GetRetryTimerDelay()); +} + +TEST_F(SyncSchedulerTest, ReceiveNewRetryDelay) { + StartSyncScheduler(SyncScheduler::NORMAL_MODE); + + SyncShareTimes times; + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(100); + base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(200); + + scheduler()->ScheduleLocalRefreshRequest(zero(), ModelTypeSet(BOOKMARKS), + FROM_HERE); + scheduler()->OnReceivedGuRetryDelay(delay1); + + EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_)) + .WillOnce(DoAll( + WithoutArgs(VerifyRetryTimerDelay(this, delay1)), + WithArg<2>(sessions::test_util::SimulateGuRetryDelayCommand(delay2)), + WithoutArgs(VerifyRetryTimerDelay(this, delay2)), + RecordSyncShare(×))); + + // Run nudge GU. + RunLoop(); + + EXPECT_CALL(*syncer(), RetrySyncShare(_,_)) + .WillOnce( + DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess), + RecordSyncShare(×))); + + // Run to wait for retrying. + RunLoop(); + + StopSyncScheduler(); +} + } // namespace syncer diff --git a/sync/engine/syncer.cc b/sync/engine/syncer.cc index 13e1f79..e75c1c6 100644 --- a/sync/engine/syncer.cc +++ b/sync/engine/syncer.cc @@ -57,7 +57,7 @@ bool Syncer::NormalSyncShare(ModelTypeSet request_types, SyncSession* session) { HandleCycleBegin(session); VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types); - if (nudge_tracker.IsGetUpdatesRequired() || + if (nudge_tracker.IsGetUpdatesRequired(base::TimeTicks::Now()) || session->context()->ShouldFetchUpdatesBeforeCommit()) { if (!DownloadAndApplyUpdates( request_types, @@ -109,6 +109,20 @@ bool Syncer::PollSyncShare(ModelTypeSet request_types, return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::PERIODIC); } +bool Syncer::RetrySyncShare(ModelTypeSet request_types, + SyncSession* session) { + HandleCycleBegin(session); + VLOG(1) << "Retrying types " << ModelTypeSetToString(request_types); + DownloadAndApplyUpdates( + request_types, + session, + base::Bind(&download::BuildDownloadUpdatesForRetry, + session, + kCreateMobileBookmarksFolder, + request_types)); + return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::RETRY); +} + void Syncer::ApplyUpdates(SyncSession* session) { TRACE_EVENT0("sync", "ApplyUpdates"); diff --git a/sync/engine/syncer.h b/sync/engine/syncer.h index 6154f91..225b4e3 100644 --- a/sync/engine/syncer.h +++ b/sync/engine/syncer.h @@ -65,6 +65,8 @@ class SYNC_EXPORT_PRIVATE Syncer { // in sync despite bugs or transient failures. virtual bool PollSyncShare(ModelTypeSet request_types, sessions::SyncSession* session); + virtual bool RetrySyncShare(ModelTypeSet request_types, + sessions::SyncSession* session); private: void ApplyUpdates(sessions::SyncSession* session); diff --git a/sync/engine/syncer_proto_util.cc b/sync/engine/syncer_proto_util.cc index bfd8151..bcc0bd4 100644 --- a/sync/engine/syncer_proto_util.cc +++ b/sync/engine/syncer_proto_util.cc @@ -433,6 +433,11 @@ SyncerError SyncerProtoUtil::PostClientToServerMessage( session->delegate()->OnReceivedClientInvalidationHintBufferSize( command.client_invalidation_hint_buffer_size()); } + + if (command.has_gu_retry_delay_seconds()) { + session->delegate()->OnReceivedGuRetryDelay( + base::TimeDelta::FromSeconds(command.gu_retry_delay_seconds())); + } } // Now do any special handling for the error type and decide on the return diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc index 951d443c..119deb1 100644 --- a/sync/engine/syncer_unittest.cc +++ b/sync/engine/syncer_unittest.cc @@ -150,6 +150,7 @@ class SyncerTest : public testing::Test, int size) OVERRIDE { last_client_invalidation_hint_buffer_size_ = size; } + virtual void OnReceivedGuRetryDelay(const base::TimeDelta& delay) OVERRIDE {} virtual void OnSyncProtocolError( const sessions::SyncSessionSnapshot& snapshot) OVERRIDE { } @@ -465,10 +466,10 @@ class SyncerTest : public testing::Test, void ConfigureNoGetUpdatesRequired() { context_->set_server_enabled_pre_commit_update_avoidance(true); nudge_tracker_.OnInvalidationsEnabled(); - nudge_tracker_.RecordSuccessfulSyncCycle(); + nudge_tracker_.RecordSuccessfulSyncCycle(base::TimeTicks::Now()); ASSERT_FALSE(context_->ShouldFetchUpdatesBeforeCommit()); - ASSERT_FALSE(nudge_tracker_.IsGetUpdatesRequired()); + ASSERT_FALSE(nudge_tracker_.IsGetUpdatesRequired(base::TimeTicks::Now())); } base::MessageLoop message_loop_; |