diff options
author | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-15 06:18:36 +0000 |
---|---|---|
committer | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-15 06:18:36 +0000 |
commit | f706df5706936983f97b4898997da87029787da2 (patch) | |
tree | a1315c180059844bf0bc6344452f18544da6c91f /sync | |
parent | 639ec914f10c955f3b0c0c7dc2b1cdfd6b9f9527 (diff) | |
download | chromium_src-f706df5706936983f97b4898997da87029787da2.zip chromium_src-f706df5706936983f97b4898997da87029787da2.tar.gz chromium_src-f706df5706936983f97b4898997da87029787da2.tar.bz2 |
sync: add InternalComponentsFactory::Switches to simplify passing switches to internal components.
Cleans up backoff retry override code to use InternalComponentsFactory::Switches rather than
global bool hack.
Also puts keystore encryption flag atop new mechanism.
(TBR sky for new chrome_switch).
TBR=sky@chromium.org
BUG=142029, 139839
Review URL: https://chromiumcodereview.appspot.com/10837231
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151664 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync')
23 files changed, 371 insertions, 201 deletions
diff --git a/sync/engine/backoff_delay_provider.cc b/sync/engine/backoff_delay_provider.cc new file mode 100644 index 0000000..af70442 --- /dev/null +++ b/sync/engine/backoff_delay_provider.cc @@ -0,0 +1,79 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sync/engine/backoff_delay_provider.h" + +#include "base/rand_util.h" +#include "sync/internal_api/public/engine/polling_constants.h" +#include "sync/internal_api/public/sessions/model_neutral_state.h" +#include "sync/internal_api/public/util/syncer_error.h" + +using base::TimeDelta; + +namespace syncer { + +// static +BackoffDelayProvider* BackoffDelayProvider::FromDefaults() { + return new BackoffDelayProvider( + TimeDelta::FromSeconds(kInitialBackoffRetrySeconds), + TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds)); +} + +// static +BackoffDelayProvider* BackoffDelayProvider::WithShortInitialRetryOverride() { + return new BackoffDelayProvider( + TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds), + TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds)); +} + +BackoffDelayProvider::BackoffDelayProvider( + const base::TimeDelta& default_initial_backoff, + const base::TimeDelta& short_initial_backoff) + : default_initial_backoff_(default_initial_backoff), + short_initial_backoff_(short_initial_backoff) { +} + +BackoffDelayProvider::~BackoffDelayProvider() {} + +TimeDelta BackoffDelayProvider::GetDelay(const base::TimeDelta& last_delay) { + if (last_delay.InSeconds() >= kMaxBackoffSeconds) + return TimeDelta::FromSeconds(kMaxBackoffSeconds); + + // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2 + int64 backoff_s = + std::max(static_cast<int64>(1), + last_delay.InSeconds() * kBackoffRandomizationFactor); + + // Flip a coin to randomize backoff interval by +/- 50%. + int rand_sign = base::RandInt(0, 1) * 2 - 1; + + // Truncation is adequate for rounding here. + backoff_s = backoff_s + + (rand_sign * (last_delay.InSeconds() / kBackoffRandomizationFactor)); + + // Cap the backoff interval. + backoff_s = std::max(static_cast<int64>(1), + std::min(backoff_s, kMaxBackoffSeconds)); + + return TimeDelta::FromSeconds(backoff_s); +} + +TimeDelta BackoffDelayProvider::GetInitialDelay( + const sessions::ModelNeutralState& state) const { + if (SyncerErrorIsError(state.last_get_key_result)) + return default_initial_backoff_; + // Note: If we received a MIGRATION_DONE on download updates, then commit + // should not have taken place. Moreover, if we receive a MIGRATION_DONE + // on commit, it means that download updates succeeded. Therefore, we only + // need to check if either code is equal to SERVER_RETURN_MIGRATION_DONE, + // and not if there were any more serious errors requiring the long retry. + if (state.last_download_updates_result == SERVER_RETURN_MIGRATION_DONE || + state.commit_result == SERVER_RETURN_MIGRATION_DONE) { + return short_initial_backoff_; + } + + return default_initial_backoff_; +} + +} // namespace syncer diff --git a/sync/engine/backoff_delay_provider.h b/sync/engine/backoff_delay_provider.h new file mode 100644 index 0000000..84293f9 --- /dev/null +++ b/sync/engine/backoff_delay_provider.h @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SYNC_ENGINE_BACKOFF_DELAY_PROVIDER_H_ +#define SYNC_ENGINE_BACKOFF_DELAY_PROVIDER_H_ + +#include "base/time.h" + +namespace syncer { + +namespace sessions { +struct ModelNeutralState; +} + +// A component used to get time delays associated with exponential backoff. +class BackoffDelayProvider { + public: + // Factory function to create a standard BackoffDelayProvider. + static BackoffDelayProvider* FromDefaults(); + + // Similar to above, but causes sync to retry very quickly (see + // polling_constants.h) when it encounters an error before exponential + // backoff. + // + // *** NOTE *** This should only be used if kSyncShortInitialRetryOverride + // was passed to command line. + static BackoffDelayProvider* WithShortInitialRetryOverride(); + + virtual ~BackoffDelayProvider(); + + // DDOS avoidance function. Calculates how long we should wait before trying + // again after a failed sync attempt, where the last delay was |base_delay|. + // TODO(tim): Look at URLRequestThrottlerEntryInterface. + virtual base::TimeDelta GetDelay(const base::TimeDelta& last_delay); + + // Helper to calculate the initial value for exponential backoff. + // See possible values and comments in polling_constants.h. + virtual base::TimeDelta GetInitialDelay( + const sessions::ModelNeutralState& state) const; + + protected: + BackoffDelayProvider(const base::TimeDelta& default_initial_backoff, + const base::TimeDelta& short_initial_backoff); + + private: + const base::TimeDelta default_initial_backoff_; + const base::TimeDelta short_initial_backoff_; + + DISALLOW_COPY_AND_ASSIGN(BackoffDelayProvider); +}; + +} // namespace syncer + +#endif // SYNC_ENGINE_BACKOFF_DELAY_PROVIDER_H_ diff --git a/sync/engine/backoff_delay_provider_unittest.cc b/sync/engine/backoff_delay_provider_unittest.cc new file mode 100644 index 0000000..31ed515 --- /dev/null +++ b/sync/engine/backoff_delay_provider_unittest.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sync/engine/backoff_delay_provider.h" + +#include "base/memory/scoped_ptr.h" +#include "base/time.h" +#include "sync/internal_api/public/engine/polling_constants.h" +#include "sync/internal_api/public/sessions/model_neutral_state.h" +#include "sync/internal_api/public/util/syncer_error.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::TimeDelta; + +namespace syncer { + +class BackoffDelayProviderTest : public testing::Test {}; + +TEST_F(BackoffDelayProviderTest, GetRecommendedDelay) { + scoped_ptr<BackoffDelayProvider> delay(BackoffDelayProvider::FromDefaults()); + EXPECT_LE(TimeDelta::FromSeconds(0), + delay->GetDelay(TimeDelta::FromSeconds(0))); + EXPECT_LE(TimeDelta::FromSeconds(1), + delay->GetDelay(TimeDelta::FromSeconds(1))); + EXPECT_LE(TimeDelta::FromSeconds(50), + delay->GetDelay(TimeDelta::FromSeconds(50))); + EXPECT_LE(TimeDelta::FromSeconds(10), + delay->GetDelay(TimeDelta::FromSeconds(10))); + EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), + delay->GetDelay(TimeDelta::FromSeconds(kMaxBackoffSeconds))); + EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), + delay->GetDelay(TimeDelta::FromSeconds(kMaxBackoffSeconds + 1))); +} + +TEST_F(BackoffDelayProviderTest, GetInitialDelay) { + scoped_ptr<BackoffDelayProvider> delay(BackoffDelayProvider::FromDefaults()); + sessions::ModelNeutralState state; + state.last_get_key_result = SYNC_SERVER_ERROR; + EXPECT_EQ(kInitialBackoffRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_get_key_result = UNSET; + state.last_download_updates_result = SERVER_RETURN_MIGRATION_DONE; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_download_updates_result = SERVER_RETURN_TRANSIENT_ERROR; + EXPECT_EQ(kInitialBackoffRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_download_updates_result = SERVER_RESPONSE_VALIDATION_FAILED; + EXPECT_EQ(kInitialBackoffRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_download_updates_result = SYNCER_OK; + // Note that updating credentials triggers a canary job, trumping + // the initial delay, but in theory we still expect this function to treat + // it like any other error in the system (except migration). + state.commit_result = SERVER_RETURN_INVALID_CREDENTIAL; + EXPECT_EQ(kInitialBackoffRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.commit_result = SERVER_RETURN_MIGRATION_DONE; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); +} + +TEST_F(BackoffDelayProviderTest, GetInitialDelayWithOverride) { + scoped_ptr<BackoffDelayProvider> delay( + BackoffDelayProvider::WithShortInitialRetryOverride()); + sessions::ModelNeutralState state; + state.last_get_key_result = SYNC_SERVER_ERROR; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_get_key_result = UNSET; + state.last_download_updates_result = SERVER_RETURN_MIGRATION_DONE; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_download_updates_result = SERVER_RETURN_TRANSIENT_ERROR; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_download_updates_result = SERVER_RESPONSE_VALIDATION_FAILED; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.last_download_updates_result = SYNCER_OK; + // Note that updating credentials triggers a canary job, trumping + // the initial delay, but in theory we still expect this function to treat + // it like any other error in the system (except migration). + state.commit_result = SERVER_RETURN_INVALID_CREDENTIAL; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); + + state.commit_result = SERVER_RETURN_MIGRATION_DONE; + EXPECT_EQ(kInitialBackoffShortRetrySeconds, + delay->GetInitialDelay(state).InSeconds()); +} + +} // namespace syncer diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc index 6db3260..ff177b4 100644 --- a/sync/engine/sync_scheduler_impl.cc +++ b/sync/engine/sync_scheduler_impl.cc @@ -12,7 +12,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/message_loop.h" -#include "base/rand_util.h" +#include "sync/engine/backoff_delay_provider.h" #include "sync/engine/syncer.h" #include "sync/engine/throttled_data_type_tracker.h" #include "sync/protocol/proto_enum_conversions.h" @@ -32,11 +32,6 @@ using sync_pb::GetUpdatesCallerInfo; namespace { -// For integration tests only. Override initial backoff value. -// TODO(tim): Remove this egregiousness, use command line flag and plumb -// through. Done this way to reduce diffs in hotfix. -static bool g_force_short_retry = false; - bool ShouldRequestEarlyExit(const SyncProtocolError& error) { switch (error.error_type) { case SYNC_SUCCESS: @@ -85,9 +80,6 @@ ConfigurationParams::ConfigurationParams( } ConfigurationParams::~ConfigurationParams() {} -SyncSchedulerImpl::DelayProvider::DelayProvider() {} -SyncSchedulerImpl::DelayProvider::~DelayProvider() {} - SyncSchedulerImpl::WaitInterval::WaitInterval() : mode(UNKNOWN), had_nudge(false) { @@ -140,11 +132,6 @@ const char* SyncSchedulerImpl::SyncSessionJob::GetPurposeString( return ""; } -TimeDelta SyncSchedulerImpl::DelayProvider::GetDelay( - const base::TimeDelta& last_delay) { - return SyncSchedulerImpl::GetRecommendedDelay(last_delay); -} - GetUpdatesCallerInfo::GetUpdatesSource GetUpdatesFromNudgeSource( NudgeSource source) { switch (source) { @@ -197,6 +184,7 @@ bool IsConfigRelatedUpdateSourceValue( } // namespace SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name, + BackoffDelayProvider* delay_provider, sessions::SyncSessionContext* context, Syncer* syncer) : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), @@ -216,7 +204,7 @@ SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name, // Start with assuming everything is fine with the connection. // At the end of the sync cycle we would have the correct status. connection_code_(HttpResponse::SERVER_CONNECTION_OK), - delay_provider_(new DelayProvider()), + delay_provider_(delay_provider), syncer_(syncer), session_context_(context) { DCHECK(sync_loop_); @@ -903,43 +891,6 @@ void SyncSchedulerImpl::RestartWaiting() { this, &SyncSchedulerImpl::DoCanaryJob); } -namespace { -// TODO(tim): Move this function to syncer_error.h. -// Return true if the command in question was attempted and did not complete -// successfully. -bool IsError(SyncerError error) { - return error != UNSET && error != SYNCER_OK; -} -} // namespace - -// static -void SyncSchedulerImpl::ForceShortInitialBackoffRetry() { - g_force_short_retry = true; -} - -TimeDelta SyncSchedulerImpl::GetInitialBackoffDelay( - const sessions::ModelNeutralState& state) const { - // TODO(tim): Remove this, provide integration-test-only mechanism - // for override. - if (g_force_short_retry) { - return TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds); - } - - if (IsError(state.last_get_key_result)) - return TimeDelta::FromSeconds(kInitialBackoffRetrySeconds); - // Note: If we received a MIGRATION_DONE on download updates, then commit - // should not have taken place. Moreover, if we receive a MIGRATION_DONE - // on commit, it means that download updates succeeded. Therefore, we only - // need to check if either code is equal to SERVER_RETURN_MIGRATION_DONE, - // and not if there were any more serious errors requiring the long retry. - if (state.last_download_updates_result == SERVER_RETURN_MIGRATION_DONE || - state.commit_result == SERVER_RETURN_MIGRATION_DONE) { - return TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds); - } - - return TimeDelta::FromSeconds(kInitialBackoffRetrySeconds); -} - void SyncSchedulerImpl::HandleContinuationError( const SyncSessionJob& old_job) { DCHECK_EQ(MessageLoop::current(), sync_loop_); @@ -951,7 +902,7 @@ void SyncSchedulerImpl::HandleContinuationError( TimeDelta length = delay_provider_->GetDelay( IsBackingOff() ? wait_interval_->length : - GetInitialBackoffDelay( + delay_provider_->GetInitialDelay( old_job.session->status_controller().model_neutral_state())); SDVLOG(2) << "In handle continuation error with " @@ -984,30 +935,6 @@ void SyncSchedulerImpl::HandleContinuationError( RestartWaiting(); } -// static -TimeDelta SyncSchedulerImpl::GetRecommendedDelay(const TimeDelta& last_delay) { - if (last_delay.InSeconds() >= kMaxBackoffSeconds) - return TimeDelta::FromSeconds(kMaxBackoffSeconds); - - // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2 - int64 backoff_s = - std::max(static_cast<int64>(1), - last_delay.InSeconds() * kBackoffRandomizationFactor); - - // Flip a coin to randomize backoff interval by +/- 50%. - int rand_sign = base::RandInt(0, 1) * 2 - 1; - - // Truncation is adequate for rounding here. - backoff_s = backoff_s + - (rand_sign * (last_delay.InSeconds() / kBackoffRandomizationFactor)); - - // Cap the backoff interval. - backoff_s = std::max(static_cast<int64>(1), - std::min(backoff_s, kMaxBackoffSeconds)); - - return TimeDelta::FromSeconds(backoff_s); -} - void SyncSchedulerImpl::RequestStop(const base::Closure& callback) { syncer_->RequestEarlyExit(); // Safe to call from any thread. DCHECK(weak_handle_this_.IsInitialized()); diff --git a/sync/engine/sync_scheduler_impl.h b/sync/engine/sync_scheduler_impl.h index 586ccdc..e5f3acf 100644 --- a/sync/engine/sync_scheduler_impl.h +++ b/sync/engine/sync_scheduler_impl.h @@ -28,12 +28,16 @@ namespace syncer { +class BackoffDelayProvider; + class SyncSchedulerImpl : public SyncScheduler { public: // |name| is a display string to identify the syncer thread. Takes - // |ownership of |syncer|. + // |ownership of |syncer| and |delay_provider|. SyncSchedulerImpl(const std::string& name, - sessions::SyncSessionContext* context, Syncer* syncer); + BackoffDelayProvider* delay_provider, + sessions::SyncSessionContext* context, + Syncer* syncer); // Calls Stop(). virtual ~SyncSchedulerImpl(); @@ -72,16 +76,6 @@ class SyncSchedulerImpl : public SyncScheduler { virtual void OnSyncProtocolError( const sessions::SyncSessionSnapshot& snapshot) OVERRIDE; - // DDOS avoidance function. Calculates how long we should wait before trying - // again after a failed sync attempt, where the last delay was |base_delay|. - // TODO(tim): Look at URLRequestThrottlerEntryInterface. - static base::TimeDelta GetRecommendedDelay(const base::TimeDelta& base_delay); - - // For integration tests only. Override initial backoff value. - // TODO(tim): Remove this, use command line flag and plumb through. Done - // this way to reduce diffs in hotfix. - static void ForceShortInitialBackoffRetry(); - private: enum JobProcessDecision { // Indicates we should continue with the current job. @@ -150,17 +144,6 @@ class SyncSchedulerImpl : public SyncScheduler { FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, TransientPollFailure); FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, GetInitialBackoffDelay); - // A component used to get time delays associated with exponential backoff. - // Encapsulated into a class to facilitate testing. - class DelayProvider { - public: - DelayProvider(); - virtual base::TimeDelta GetDelay(const base::TimeDelta& last_delay); - virtual ~DelayProvider(); - private: - DISALLOW_COPY_AND_ASSIGN(DelayProvider); - }; - struct WaitInterval { enum Mode { // Uninitialized state, should not be set in practice. @@ -234,11 +217,6 @@ class SyncSchedulerImpl : public SyncScheduler { // Helper to ScheduleNextSync in case of consecutive sync errors. void HandleContinuationError(const SyncSessionJob& old_job); - // Helper to calculate the initial value for exponential backoff. - // See possible values and comments in polling_constants.h. - base::TimeDelta GetInitialBackoffDelay( - const sessions::ModelNeutralState& state) const; - // Determines if it is legal to run |job| by checking current // operational mode, backoff or throttling, freshness // (so we don't make redundant syncs), and connection. @@ -348,7 +326,7 @@ class SyncSchedulerImpl : public SyncScheduler { // Current wait state. Null if we're not in backoff and not throttled. scoped_ptr<WaitInterval> wait_interval_; - scoped_ptr<DelayProvider> delay_provider_; + scoped_ptr<BackoffDelayProvider> delay_provider_; // Invoked to run through the sync cycle. scoped_ptr<Syncer> syncer_; diff --git a/sync/engine/sync_scheduler_unittest.cc b/sync/engine/sync_scheduler_unittest.cc index 0420bcb..53d2ed4 100644 --- a/sync/engine/sync_scheduler_unittest.cc +++ b/sync/engine/sync_scheduler_unittest.cc @@ -8,6 +8,7 @@ #include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/test/test_timeouts.h" +#include "sync/engine/backoff_delay_provider.h" #include "sync/engine/sync_scheduler_impl.h" #include "sync/engine/syncer.h" #include "sync/engine/throttled_data_type_tracker.h" @@ -88,8 +89,13 @@ class SyncSchedulerTest : public testing::Test { syncer_(NULL), delay_(NULL) {} - class MockDelayProvider : public SyncSchedulerImpl::DelayProvider { + class MockDelayProvider : public BackoffDelayProvider { public: + MockDelayProvider() : BackoffDelayProvider( + TimeDelta::FromSeconds(kInitialBackoffRetrySeconds), + TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds)) { + } + MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&)); }; @@ -126,7 +132,10 @@ class SyncSchedulerTest : public testing::Test { context_->set_notifications_enabled(true); context_->set_account_name("Test"); scheduler_.reset( - new SyncSchedulerImpl("TestSyncScheduler", context(), syncer_)); + new SyncSchedulerImpl("TestSyncScheduler", + BackoffDelayProvider::FromDefaults(), + context(), + syncer_)); } SyncSchedulerImpl* scheduler() { return scheduler_.get(); } @@ -959,38 +968,6 @@ TEST_F(SyncSchedulerTest, BackoffElevation) { EXPECT_GE(r.times[4] - r.times[3], fifth); } -TEST_F(SyncSchedulerTest, GetInitialBackoffDelay) { - sessions::ModelNeutralState state; - state.last_get_key_result = SYNC_SERVER_ERROR; - EXPECT_EQ(kInitialBackoffRetrySeconds, - scheduler()->GetInitialBackoffDelay(state).InSeconds()); - - state.last_get_key_result = UNSET; - state.last_download_updates_result = SERVER_RETURN_MIGRATION_DONE; - EXPECT_EQ(kInitialBackoffShortRetrySeconds, - scheduler()->GetInitialBackoffDelay(state).InSeconds()); - - state.last_download_updates_result = SERVER_RETURN_TRANSIENT_ERROR; - EXPECT_EQ(kInitialBackoffRetrySeconds, - scheduler()->GetInitialBackoffDelay(state).InSeconds()); - - state.last_download_updates_result = SERVER_RESPONSE_VALIDATION_FAILED; - EXPECT_EQ(kInitialBackoffRetrySeconds, - scheduler()->GetInitialBackoffDelay(state).InSeconds()); - - state.last_download_updates_result = SYNCER_OK; - // Note that updating credentials triggers a canary job, trumping - // the initial delay, but in theory we still expect this function to treat - // it like any other error in the system (except migration). - state.commit_result = SERVER_RETURN_INVALID_CREDENTIAL; - EXPECT_EQ(kInitialBackoffRetrySeconds, - scheduler()->GetInitialBackoffDelay(state).InSeconds()); - - state.commit_result = SERVER_RETURN_MIGRATION_DONE; - EXPECT_EQ(kInitialBackoffShortRetrySeconds, - scheduler()->GetInitialBackoffDelay(state).InSeconds()); -} - // Test that things go back to normal once a retry makes forward progress. TEST_F(SyncSchedulerTest, BackoffRelief) { SyncShareRecords r; @@ -1066,25 +1043,6 @@ TEST_F(SyncSchedulerTest, TransientPollFailure) { EXPECT_FALSE(scheduler()->IsBackingOff()); } -TEST_F(SyncSchedulerTest, GetRecommendedDelay) { - EXPECT_LE(TimeDelta::FromSeconds(0), - SyncSchedulerImpl::GetRecommendedDelay(TimeDelta::FromSeconds(0))); - EXPECT_LE(TimeDelta::FromSeconds(1), - SyncSchedulerImpl::GetRecommendedDelay(TimeDelta::FromSeconds(1))); - EXPECT_LE(TimeDelta::FromSeconds(50), - SyncSchedulerImpl::GetRecommendedDelay( - TimeDelta::FromSeconds(50))); - EXPECT_LE(TimeDelta::FromSeconds(10), - SyncSchedulerImpl::GetRecommendedDelay( - TimeDelta::FromSeconds(10))); - EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), - SyncSchedulerImpl::GetRecommendedDelay( - TimeDelta::FromSeconds(kMaxBackoffSeconds))); - EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), - SyncSchedulerImpl::GetRecommendedDelay( - TimeDelta::FromSeconds(kMaxBackoffSeconds + 1))); -} - // Test that appropriate syncer steps are requested for each job type. TEST_F(SyncSchedulerTest, SyncerSteps) { // Nudges. diff --git a/sync/engine/sync_scheduler_whitebox_unittest.cc b/sync/engine/sync_scheduler_whitebox_unittest.cc index f6f88c2..afc8c6f 100644 --- a/sync/engine/sync_scheduler_whitebox_unittest.cc +++ b/sync/engine/sync_scheduler_whitebox_unittest.cc @@ -4,8 +4,10 @@ #include "base/message_loop.h" #include "base/time.h" +#include "sync/engine/backoff_delay_provider.h" #include "sync/engine/sync_scheduler_impl.h" #include "sync/engine/throttled_data_type_tracker.h" +#include "sync/internal_api/public/engine/polling_constants.h" #include "sync/sessions/sync_session_context.h" #include "sync/sessions/test_util.h" #include "sync/test/engine/fake_model_worker.h" @@ -55,7 +57,10 @@ class SyncSchedulerWhiteboxTest : public testing::Test { context_->set_notifications_enabled(true); context_->set_account_name("Test"); scheduler_.reset( - new SyncSchedulerImpl("TestSyncSchedulerWhitebox", context(), syncer)); + new SyncSchedulerImpl("TestSyncSchedulerWhitebox", + BackoffDelayProvider::FromDefaults(), + context(), + syncer)); } virtual void TearDown() { diff --git a/sync/internal_api/internal_components_factory_impl.cc b/sync/internal_api/internal_components_factory_impl.cc index 3342d09..746d25c 100644 --- a/sync/internal_api/internal_components_factory_impl.cc +++ b/sync/internal_api/internal_components_factory_impl.cc @@ -4,20 +4,32 @@ #include "sync/internal_api/public/internal_components_factory_impl.h" +#include "sync/engine/backoff_delay_provider.h" #include "sync/engine/syncer.h" #include "sync/engine/sync_scheduler_impl.h" #include "sync/sessions/sync_session_context.h" #include "sync/syncable/on_disk_directory_backing_store.h" +using base::TimeDelta; + namespace syncer { -InternalComponentsFactoryImpl::InternalComponentsFactoryImpl() { } +InternalComponentsFactoryImpl::InternalComponentsFactoryImpl( + const Switches& switches) : switches_(switches) { +} + InternalComponentsFactoryImpl::~InternalComponentsFactoryImpl() { } scoped_ptr<SyncScheduler> InternalComponentsFactoryImpl::BuildScheduler( const std::string& name, sessions::SyncSessionContext* context) { + + scoped_ptr<BackoffDelayProvider> delay(BackoffDelayProvider::FromDefaults()); + + if (switches_.backoff_override == BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE) + delay.reset(BackoffDelayProvider::WithShortInitialRetryOverride()); + return scoped_ptr<SyncScheduler>( - new SyncSchedulerImpl(name, context, new Syncer())); + new SyncSchedulerImpl(name, delay.release(), context, new Syncer())); } scoped_ptr<sessions::SyncSessionContext> @@ -29,14 +41,13 @@ InternalComponentsFactoryImpl::BuildContext( ThrottledDataTypeTracker* throttled_data_type_tracker, const std::vector<SyncEngineEventListener*>& listeners, sessions::DebugInfoGetter* debug_info_getter, - TrafficRecorder* traffic_recorder, - bool keystore_encryption_enabled) { + TrafficRecorder* traffic_recorder) { return scoped_ptr<sessions::SyncSessionContext>( new sessions::SyncSessionContext( connection_manager, directory, workers, monitor, throttled_data_type_tracker, listeners, debug_info_getter, traffic_recorder, - keystore_encryption_enabled)); + switches_.encryption_method == ENCRYPTION_KEYSTORE)); } scoped_ptr<syncable::DirectoryBackingStore> @@ -46,4 +57,9 @@ InternalComponentsFactoryImpl::BuildDirectoryBackingStore( new syncable::OnDiskDirectoryBackingStore(dir_name, backing_filepath)); } +InternalComponentsFactory::Switches +InternalComponentsFactoryImpl::GetSwitches() const { + return switches_; +} + } // namespace syncer diff --git a/sync/internal_api/public/internal_components_factory.h b/sync/internal_api/public/internal_components_factory.h index 145c225..4830ce1 100644 --- a/sync/internal_api/public/internal_components_factory.h +++ b/sync/internal_api/public/internal_components_factory.h @@ -37,6 +37,30 @@ class DirectoryBackingStore; class InternalComponentsFactory { public: + enum EncryptionMethod { + ENCRYPTION_LEGACY, + // Option to enable support for keystore key based encryption. + ENCRYPTION_KEYSTORE + }; + + enum BackoffOverride { + BACKOFF_NORMAL, + // Use this value for integration testing to avoid long delays / + // timing out tests. Uses kInitialBackoffShortRetrySeconds (see + // polling_constants.h) for all initial retries. + BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE + }; + + // Configuration options for internal components. This struct is expected + // to grow and shrink over time with transient features / experiments, + // roughly following command line flags in chrome. Implementations of + // InternalComponentsFactory can use this information to build components + // with appropriate bells and whistles. + struct Switches { + EncryptionMethod encryption_method; + BackoffOverride backoff_override; + }; + virtual ~InternalComponentsFactory() {} virtual scoped_ptr<SyncScheduler> BuildScheduler( @@ -51,13 +75,16 @@ class InternalComponentsFactory { ThrottledDataTypeTracker* throttled_data_type_tracker, const std::vector<SyncEngineEventListener*>& listeners, sessions::DebugInfoGetter* debug_info_getter, - TrafficRecorder* traffic_recorder, - bool keystore_encryption_enabled) = 0; + TrafficRecorder* traffic_recorder) = 0; virtual scoped_ptr<syncable::DirectoryBackingStore> BuildDirectoryBackingStore( const std::string& dir_name, const FilePath& backing_filepath) = 0; + + // Returns the Switches struct that this object is using as configuration, if + // the implementation is making use of one. + virtual Switches GetSwitches() const = 0; }; } // namespace syncer diff --git a/sync/internal_api/public/internal_components_factory_impl.h b/sync/internal_api/public/internal_components_factory_impl.h index c8f76ed..1b64d0b 100644 --- a/sync/internal_api/public/internal_components_factory_impl.h +++ b/sync/internal_api/public/internal_components_factory_impl.h @@ -14,7 +14,7 @@ namespace syncer { class InternalComponentsFactoryImpl : public InternalComponentsFactory { public: - InternalComponentsFactoryImpl(); + InternalComponentsFactoryImpl(const Switches& switches); virtual ~InternalComponentsFactoryImpl(); virtual scoped_ptr<SyncScheduler> BuildScheduler( @@ -29,15 +29,17 @@ class InternalComponentsFactoryImpl : public InternalComponentsFactory { ThrottledDataTypeTracker* throttled_data_type_tracker, const std::vector<SyncEngineEventListener*>& listeners, sessions::DebugInfoGetter* debug_info_getter, - TrafficRecorder* traffic_recorder, - bool keystore_encryption_enabled) OVERRIDE; + TrafficRecorder* traffic_recorder) OVERRIDE; virtual scoped_ptr<syncable::DirectoryBackingStore> BuildDirectoryBackingStore( const std::string& dir_name, const FilePath& backing_filepath) OVERRIDE; + virtual Switches GetSwitches() const OVERRIDE; + private: + const Switches switches_; DISALLOW_COPY_AND_ASSIGN(InternalComponentsFactoryImpl); }; diff --git a/sync/internal_api/public/sync_manager.h b/sync/internal_api/public/sync_manager.h index 01d919c..8e64f32 100644 --- a/sync/internal_api/public/sync_manager.h +++ b/sync/internal_api/public/sync_manager.h @@ -378,7 +378,6 @@ class SyncManager { scoped_ptr<SyncNotifier> sync_notifier, const std::string& restored_key_for_bootstrapping, const std::string& restored_keystore_key_for_bootstrapping, - bool keystore_encryption_enabled, scoped_ptr<InternalComponentsFactory> internal_components_factory, Encryptor* encryptor, UnrecoverableErrorHandler* unrecoverable_error_handler, diff --git a/sync/internal_api/public/test/fake_sync_manager.h b/sync/internal_api/public/test/fake_sync_manager.h index 71fe35e..dcd877a 100644 --- a/sync/internal_api/public/test/fake_sync_manager.h +++ b/sync/internal_api/public/test/fake_sync_manager.h @@ -82,7 +82,6 @@ class FakeSyncManager : public SyncManager { scoped_ptr<SyncNotifier> sync_notifier, const std::string& restored_key_for_bootstrapping, const std::string& restored_keystore_key_for_bootstrapping, - bool keystore_encryption_enabled, scoped_ptr<InternalComponentsFactory> internal_components_factory, Encryptor* encryptor, UnrecoverableErrorHandler* unrecoverable_error_handler, diff --git a/sync/internal_api/public/test/test_internal_components_factory.h b/sync/internal_api/public/test/test_internal_components_factory.h index e9ca613..d48855b 100644 --- a/sync/internal_api/public/test/test_internal_components_factory.h +++ b/sync/internal_api/public/test/test_internal_components_factory.h @@ -21,7 +21,8 @@ enum StorageOption { class TestInternalComponentsFactory : public InternalComponentsFactory { public: - explicit TestInternalComponentsFactory(StorageOption option); + explicit TestInternalComponentsFactory(const Switches& switches, + StorageOption option); virtual ~TestInternalComponentsFactory(); virtual scoped_ptr<SyncScheduler> BuildScheduler( @@ -36,15 +37,17 @@ class TestInternalComponentsFactory : public InternalComponentsFactory { ThrottledDataTypeTracker* throttled_data_type_tracker, const std::vector<SyncEngineEventListener*>& listeners, sessions::DebugInfoGetter* debug_info_getter, - TrafficRecorder* traffic_recorder, - bool keystore_encryption_enabled) OVERRIDE; + TrafficRecorder* traffic_recorder) OVERRIDE; virtual scoped_ptr<syncable::DirectoryBackingStore> BuildDirectoryBackingStore( const std::string& dir_name, const FilePath& backing_filepath) OVERRIDE; + virtual Switches GetSwitches() const OVERRIDE; + private: + const Switches switches_; const StorageOption storage_option_; DISALLOW_COPY_AND_ASSIGN(TestInternalComponentsFactory); diff --git a/sync/internal_api/public/util/syncer_error.cc b/sync/internal_api/public/util/syncer_error.cc index d77821d..b5d8899 100644 --- a/sync/internal_api/public/util/syncer_error.cc +++ b/sync/internal_api/public/util/syncer_error.cc @@ -32,4 +32,8 @@ const char* GetSyncerErrorString(SyncerError value) { } #undef ENUM_CASE +bool SyncerErrorIsError(SyncerError error) { + return error != UNSET && error != SYNCER_OK; +} + } // namespace syncer diff --git a/sync/internal_api/public/util/syncer_error.h b/sync/internal_api/public/util/syncer_error.h index 3dd4dd0..69959ab 100644 --- a/sync/internal_api/public/util/syncer_error.h +++ b/sync/internal_api/public/util/syncer_error.h @@ -40,6 +40,10 @@ enum SyncerError { const char * GetSyncerErrorString(SyncerError); +// Helper to check that |error| is set to something (not UNSET) and is not +// SYNCER_OK. +bool SyncerErrorIsError(SyncerError error); + } // namespace syncer #endif // SYNC_INTERNAL_API_PUBLIC_UTIL_SYNCER_ERROR_H_ diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc index 28d6b3c..95d650c 100644 --- a/sync/internal_api/sync_manager_impl.cc +++ b/sync/internal_api/sync_manager_impl.cc @@ -377,7 +377,6 @@ void SyncManagerImpl::Init( scoped_ptr<SyncNotifier> sync_notifier, const std::string& restored_key_for_bootstrapping, const std::string& restored_keystore_key_for_bootstrapping, - bool keystore_encryption_enabled, scoped_ptr<InternalComponentsFactory> internal_components_factory, Encryptor* encryptor, UnrecoverableErrorHandler* unrecoverable_error_handler, @@ -468,8 +467,7 @@ void SyncManagerImpl::Init( &throttled_data_type_tracker_, listeners, &debug_info_event_listener_, - &traffic_recorder_, - keystore_encryption_enabled).Pass(); + &traffic_recorder_).Pass(); session_context_->set_account_name(credentials.email); scheduler_ = internal_components_factory->BuildScheduler( name_, session_context_.get()).Pass(); diff --git a/sync/internal_api/sync_manager_impl.h b/sync/internal_api/sync_manager_impl.h index 1c4541f..19bad68 100644 --- a/sync/internal_api/sync_manager_impl.h +++ b/sync/internal_api/sync_manager_impl.h @@ -73,7 +73,6 @@ class SyncManagerImpl : public SyncManager, scoped_ptr<SyncNotifier> sync_notifier, const std::string& restored_key_for_bootstrapping, const std::string& restored_keystore_key_for_bootstrapping, - bool keystore_encryption_enabled, scoped_ptr<InternalComponentsFactory> internal_components_factory, Encryptor* encryptor, UnrecoverableErrorHandler* unrecoverable_error_handler, diff --git a/sync/internal_api/sync_manager_impl_unittest.cc b/sync/internal_api/sync_manager_impl_unittest.cc index 841ffd0..c41215c 100644 --- a/sync/internal_api/sync_manager_impl_unittest.cc +++ b/sync/internal_api/sync_manager_impl_unittest.cc @@ -725,7 +725,10 @@ class SyncManagerTest : public testing::Test, SyncManagerTest() : sync_notifier_mock_(NULL), - sync_manager_("Test sync manager") {} + sync_manager_("Test sync manager") { + switches_.encryption_method = + InternalComponentsFactory::ENCRYPTION_KEYSTORE; + } virtual ~SyncManagerTest() { EXPECT_FALSE(sync_notifier_mock_); @@ -770,7 +773,6 @@ class SyncManagerTest : public testing::Test, credentials, scoped_ptr<SyncNotifier>(sync_notifier_mock_), "", "", // bootstrap tokens - true, // enable keystore encryption scoped_ptr<InternalComponentsFactory>(GetFactory()), &encryptor_, &handler_, @@ -888,7 +890,7 @@ class SyncManagerTest : public testing::Test, } virtual InternalComponentsFactory* GetFactory() { - return new TestInternalComponentsFactory(STORAGE_IN_MEMORY); + return new TestInternalComponentsFactory(GetSwitches(), STORAGE_IN_MEMORY); } // Returns true if we are currently encrypting all sync data. May @@ -941,6 +943,10 @@ class SyncManagerTest : public testing::Test, sync_manager_.directory()->set_initial_sync_ended_for_type(type, value); } + InternalComponentsFactory::Switches GetSwitches() const { + return switches_; + } + private: // Needed by |sync_manager_|. MessageLoop message_loop_; @@ -957,6 +963,7 @@ class SyncManagerTest : public testing::Test, SyncManagerImpl sync_manager_; WeakHandle<JsBackend> js_backend_; StrictMock<SyncManagerObserverMock> observer_; + InternalComponentsFactory::Switches switches_; }; TEST_F(SyncManagerTest, UpdateEnabledTypes) { @@ -2541,10 +2548,10 @@ class MockSyncScheduler : public FakeSyncScheduler { class ComponentsFactory : public TestInternalComponentsFactory { public: - ComponentsFactory(SyncScheduler* scheduler_to_use, + ComponentsFactory(const Switches& switches, + SyncScheduler* scheduler_to_use, sessions::SyncSessionContext** session_context) - : TestInternalComponentsFactory( - syncer::STORAGE_IN_MEMORY), + : TestInternalComponentsFactory(switches, syncer::STORAGE_IN_MEMORY), scheduler_to_use_(scheduler_to_use), session_context_(session_context) {} virtual ~ComponentsFactory() {} @@ -2566,7 +2573,7 @@ class SyncManagerTestWithMockScheduler : public SyncManagerTest { SyncManagerTestWithMockScheduler() : scheduler_(NULL) {} virtual InternalComponentsFactory* GetFactory() OVERRIDE { scheduler_ = new MockSyncScheduler(); - return new ComponentsFactory(scheduler_, &session_context_); + return new ComponentsFactory(GetSwitches(), scheduler_, &session_context_); } MockSyncScheduler* scheduler() { return scheduler_; } diff --git a/sync/internal_api/test/fake_sync_manager.cc b/sync/internal_api/test/fake_sync_manager.cc index e6b415a..0e1e24b 100644 --- a/sync/internal_api/test/fake_sync_manager.cc +++ b/sync/internal_api/test/fake_sync_manager.cc @@ -111,7 +111,6 @@ void FakeSyncManager::Init( scoped_ptr<SyncNotifier> sync_notifier, const std::string& restored_key_for_bootstrapping, const std::string& restored_keystore_key_for_bootstrapping, - bool keystore_encryption_enabled, scoped_ptr<InternalComponentsFactory> internal_components_factory, Encryptor* encryptor, UnrecoverableErrorHandler* unrecoverable_error_handler, diff --git a/sync/internal_api/test/test_internal_components_factory.cc b/sync/internal_api/test/test_internal_components_factory.cc index 75c559a..a195609 100644 --- a/sync/internal_api/test/test_internal_components_factory.cc +++ b/sync/internal_api/test/test_internal_components_factory.cc @@ -13,8 +13,10 @@ namespace syncer { TestInternalComponentsFactory::TestInternalComponentsFactory( + const Switches& switches, StorageOption option) - : storage_option_(option) { + : switches_(switches), + storage_option_(option) { } TestInternalComponentsFactory::~TestInternalComponentsFactory() { } @@ -33,8 +35,7 @@ TestInternalComponentsFactory::BuildContext( ThrottledDataTypeTracker* throttled_data_type_tracker, const std::vector<SyncEngineEventListener*>& listeners, sessions::DebugInfoGetter* debug_info_getter, - TrafficRecorder* traffic_recorder, - bool keystore_encryption_enabled) { + TrafficRecorder* traffic_recorder) { // Tests don't wire up listeners. std::vector<SyncEngineEventListener*> empty_listeners; @@ -43,7 +44,7 @@ TestInternalComponentsFactory::BuildContext( connection_manager, directory, workers, monitor, throttled_data_type_tracker, empty_listeners, debug_info_getter, traffic_recorder, - keystore_encryption_enabled)); + switches_.encryption_method == ENCRYPTION_KEYSTORE)); } @@ -66,4 +67,9 @@ TestInternalComponentsFactory::BuildDirectoryBackingStore( return scoped_ptr<syncable::DirectoryBackingStore>(); } +InternalComponentsFactory::Switches +TestInternalComponentsFactory::GetSwitches() const { + return switches_; +} + } // namespace syncer diff --git a/sync/sessions/sync_session.cc b/sync/sessions/sync_session.cc index f432978..ee29668 100644 --- a/sync/sessions/sync_session.cc +++ b/sync/sessions/sync_session.cc @@ -239,18 +239,13 @@ std::set<ModelSafeGroup> } namespace { -// Return true if the command in question was attempted and did not complete -// successfully. -bool IsError(SyncerError error) { - return error != UNSET && error != SYNCER_OK; -} // Returns false iff one of the command results had an error. bool HadErrors(const ModelNeutralState& state) { - const bool get_key_error = IsError(state.last_get_key_result); + const bool get_key_error = SyncerErrorIsError(state.last_get_key_result); const bool download_updates_error = - IsError(state.last_download_updates_result); - const bool commit_error = IsError(state.commit_result); + SyncerErrorIsError(state.last_download_updates_result); + const bool commit_error = SyncerErrorIsError(state.commit_result); return get_key_error || download_updates_error || commit_error; } } // namespace diff --git a/sync/sync.gyp b/sync/sync.gyp index 0851271..ea2caac 100644 --- a/sync/sync.gyp +++ b/sync/sync.gyp @@ -74,6 +74,8 @@ 'engine/all_status.h', 'engine/apply_updates_command.cc', 'engine/apply_updates_command.h', + 'engine/backoff_delay_provider.cc', + 'engine/backoff_delay_provider.h', 'engine/build_commit_command.cc', 'engine/build_commit_command.h', 'engine/commit.cc', @@ -562,6 +564,7 @@ 'internal_api/public/engine/model_safe_worker_unittest.cc', 'internal_api/public/util/immutable_unittest.cc', 'engine/apply_updates_command_unittest.cc', + 'engine/backoff_delay_provider_unittest.cc', 'engine/build_commit_command_unittest.cc', 'engine/download_updates_command_unittest.cc', 'engine/model_changing_syncer_command_unittest.cc', diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc index f671edc..5f6de2a 100644 --- a/sync/tools/sync_client.cc +++ b/sync/tools/sync_client.cc @@ -351,6 +351,11 @@ int SyncClientMain(int argc, char* argv[]) { const char kRestoredKeystoreKeyForBootstrapping[] = ""; NullEncryptor null_encryptor; LoggingUnrecoverableErrorHandler unrecoverable_error_handler; + InternalComponentsFactoryImpl::Switches factory_switches = { + InternalComponentsFactory::ENCRYPTION_KEYSTORE, + InternalComponentsFactory::BACKOFF_NORMAL + }; + sync_manager->Init(database_dir.path(), WeakHandle<JsEventHandler>( js_event_handler.AsWeakPtr()), @@ -367,9 +372,8 @@ int SyncClientMain(int argc, char* argv[]) { sync_notifier_factory.CreateSyncNotifier()), kRestoredKeyForBootstrapping, kRestoredKeystoreKeyForBootstrapping, - true, // enable keystore encryption scoped_ptr<InternalComponentsFactory>( - new InternalComponentsFactoryImpl()), + new InternalComponentsFactoryImpl(factory_switches)), &null_encryptor, &unrecoverable_error_handler, &LogUnrecoverableErrorContext); |