diff options
author | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-15 09:35:42 +0000 |
---|---|---|
committer | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-15 09:35:42 +0000 |
commit | c1c32c85357f14756247b04b8b5ae41b05bf2e16 (patch) | |
tree | 58f25f64e1fa592e8daf276ef69901cd2218f929 /sync/engine/sync_scheduler.h | |
parent | 63ee33bde2ec8471a70f0f0ec6a1962dd07fc8ab (diff) | |
download | chromium_src-c1c32c85357f14756247b04b8b5ae41b05bf2e16.zip chromium_src-c1c32c85357f14756247b04b8b5ae41b05bf2e16.tar.gz chromium_src-c1c32c85357f14756247b04b8b5ae41b05bf2e16.tar.bz2 |
[Sync] Move 'sync' target to sync/
Also move related test files.
Move WriteNode::UpdateEntryWithEncryption to nigori_util.h.
Clean up defines and dependencies. In particular, get rid of SYNC_ENGINE_VERSION_STRING and hard-code the string in the single place it's used.
Rename data_encryption.* to data_encryption_win.* and add a pragma for crypt32.lib.
Clean up exit-time constructor warnings in sync{able,er}_unittest.cc.
Remove some unused files.
BUG=117585
TEST=
TBR=jhawkins@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9699057
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126872 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/engine/sync_scheduler.h')
-rw-r--r-- | sync/engine/sync_scheduler.h | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/sync/engine/sync_scheduler.h b/sync/engine/sync_scheduler.h new file mode 100644 index 0000000..8540484 --- /dev/null +++ b/sync/engine/sync_scheduler.h @@ -0,0 +1,421 @@ +// 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. +// +// A class to schedule syncer tasks intelligently. +#ifndef SYNC_ENGINE_SYNC_SCHEDULER_H_ +#define SYNC_ENGINE_SYNC_SCHEDULER_H_ +#pragma once + +#include <string> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "base/memory/linked_ptr.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/time.h" +#include "base/timer.h" +#include "sync/engine/net/server_connection_manager.h" +#include "sync/engine/nudge_source.h" +#include "sync/engine/polling_constants.h" +#include "sync/engine/syncer.h" +#include "sync/sessions/sync_session.h" +#include "sync/sessions/sync_session_context.h" +#include "sync/syncable/model_type_payload_map.h" +#include "sync/util/weak_handle.h" + +class MessageLoop; + +namespace tracked_objects { +class Location; +} // namespace tracked_objects + +namespace browser_sync { + +struct ServerConnectionEvent; + +class SyncScheduler : public sessions::SyncSession::Delegate { + public: + enum Mode { + // In this mode, the thread only performs configuration tasks. This is + // designed to make the case where we want to download updates for a + // specific type only, and not continue syncing until we are moved into + // normal mode. + CONFIGURATION_MODE, + // Resumes polling and allows nudges, drops configuration tasks. Runs + // through entire sync cycle. + NORMAL_MODE, + }; + + // All methods of SyncScheduler must be called on the same thread + // (except for RequestEarlyExit()). + + // |name| is a display string to identify the syncer thread. Takes + // |ownership of both |context| and |syncer|. + SyncScheduler(const std::string& name, + sessions::SyncSessionContext* context, Syncer* syncer); + + // Calls Stop(). + virtual ~SyncScheduler(); + + // Start the scheduler with the given mode. If the scheduler is + // already started, switch to the given mode, although some + // scheduled tasks from the old mode may still run. If non-NULL, + // |callback| will be invoked when the mode has been changed to + // |mode|. Takes ownership of |callback|. + void Start(Mode mode, const base::Closure& callback); + + // Request that any running syncer task stop as soon as possible and + // cancel all scheduled tasks. This function can be called from any thread, + // and should in fact be called from a thread that isn't the sync loop to + // allow preempting ongoing sync cycles. + // Invokes |callback| from the sync loop once syncer is idle and all tasks + // are cancelled. + void RequestStop(const base::Closure& callback); + + // The meat and potatoes. + void ScheduleNudge(const base::TimeDelta& delay, NudgeSource source, + syncable::ModelTypeSet types, + const tracked_objects::Location& nudge_location); + void ScheduleNudgeWithPayloads( + const base::TimeDelta& delay, NudgeSource source, + const syncable::ModelTypePayloadMap& types_with_payloads, + const tracked_objects::Location& nudge_location); + + // Note: The source argument of this function must come from the subset of + // GetUpdatesCallerInfo values related to configurations. + void ScheduleConfig( + syncable::ModelTypeSet types, + sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source); + + void ScheduleClearUserData(); + // If this is called before Start(), the cleanup is guaranteed to + // happen before the Start finishes. + // + // TODO(akalin): Figure out how to test this. + void ScheduleCleanupDisabledTypes(); + + // Change status of notifications in the SyncSessionContext. + void set_notifications_enabled(bool notifications_enabled); + + base::TimeDelta sessions_commit_delay() const; + + // 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); + + // Called when credentials are updated by the user. + void OnCredentialsUpdated(); + + // Called when the network layer detects a connection status change. + void OnConnectionStatusChange(); + + // SyncSession::Delegate implementation. + virtual void OnSilencedUntil( + const base::TimeTicks& silenced_until) OVERRIDE; + virtual bool IsSyncingCurrentlySilenced() OVERRIDE; + virtual void OnReceivedShortPollIntervalUpdate( + const base::TimeDelta& new_interval) OVERRIDE; + virtual void OnReceivedLongPollIntervalUpdate( + const base::TimeDelta& new_interval) OVERRIDE; + virtual void OnReceivedSessionsCommitDelay( + const base::TimeDelta& new_delay) OVERRIDE; + virtual void OnShouldStopSyncingPermanently() OVERRIDE; + virtual void OnSyncProtocolError( + const sessions::SyncSessionSnapshot& snapshot) OVERRIDE; + + private: + enum JobProcessDecision { + // Indicates we should continue with the current job. + CONTINUE, + // Indicates that we should save it to be processed later. + SAVE, + // Indicates we should drop this job. + DROP, + }; + + struct SyncSessionJob { + // An enum used to describe jobs for scheduling purposes. + enum SyncSessionJobPurpose { + // Uninitialized state, should never be hit in practice. + UNKNOWN = -1, + // Our poll timer schedules POLL jobs periodically based on a server + // assigned poll interval. + POLL, + // A nudge task can come from a variety of components needing to force + // a sync. The source is inferable from |session.source()|. + NUDGE, + // The user invoked a function in the UI to clear their entire account + // and stop syncing (globally). + CLEAR_USER_DATA, + // Typically used for fetching updates for a subset of the enabled types + // during initial sync or reconfiguration. We don't run all steps of + // the sync cycle for these (e.g. CleanupDisabledTypes is skipped). + CONFIGURATION, + // The user disabled some types and we have to clean up the data + // for those. + CLEANUP_DISABLED_TYPES, + }; + SyncSessionJob(); + SyncSessionJob(SyncSessionJobPurpose purpose, base::TimeTicks start, + linked_ptr<sessions::SyncSession> session, bool is_canary_job, + const tracked_objects::Location& nudge_location); + ~SyncSessionJob(); + static const char* GetPurposeString(SyncSessionJobPurpose purpose); + + SyncSessionJobPurpose purpose; + base::TimeTicks scheduled_start; + linked_ptr<sessions::SyncSession> session; + bool is_canary_job; + + // This is the location the job came from. Used for debugging. + // In case of multiple nudges getting coalesced this stores the + // first location that came in. + tracked_objects::Location from_here; + }; + friend class SyncSchedulerTest; + friend class SyncSchedulerWhiteboxTest; + + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, + DropNudgeWhileExponentialBackOff); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, SaveNudge); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, + SaveNudgeWhileTypeThrottled); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueNudge); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, DropPoll); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinuePoll); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueConfiguration); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, + SaveConfigurationWhileThrottled); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, + SaveNudgeWhileThrottled); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, + ContinueClearUserDataUnderAllCircumstances); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, + ContinueCanaryJobConfig); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, + ContinueNudgeWhileExponentialBackOff); + FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, TransientPollFailure); + + // 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. + UNKNOWN = -1, + // A wait interval whose duration has been affected by exponential + // backoff. + // EXPONENTIAL_BACKOFF intervals are nudge-rate limited to 1 per interval. + EXPONENTIAL_BACKOFF, + // A server-initiated throttled interval. We do not allow any syncing + // during such an interval. + THROTTLED, + }; + WaitInterval(); + ~WaitInterval(); + WaitInterval(Mode mode, base::TimeDelta length); + + static const char* GetModeString(Mode mode); + + Mode mode; + + // This bool is set to true if we have observed a nudge during this + // interval and mode == EXPONENTIAL_BACKOFF. + bool had_nudge; + base::TimeDelta length; + base::OneShotTimer<SyncScheduler> timer; + + // Configure jobs are saved only when backing off or throttling. So we + // expose the pointer here. + scoped_ptr<SyncSessionJob> pending_configure_job; + }; + + static const char* GetModeString(Mode mode); + + static const char* GetDecisionString(JobProcessDecision decision); + + // Helpers that log before posting to |sync_loop_|. These will only post + // the task in between calls to Start/Stop. + void PostTask(const tracked_objects::Location& from_here, + const char* name, + const base::Closure& task); + void PostDelayedTask(const tracked_objects::Location& from_here, + const char* name, + const base::Closure& task, + base::TimeDelta delay); + + // Helper to assemble a job and post a delayed task to sync. + void ScheduleSyncSessionJob(const SyncSessionJob& job); + + // Invoke the Syncer to perform a sync. + void DoSyncSessionJob(const SyncSessionJob& job); + + // Called after the Syncer has performed the sync represented by |job|, to + // reset our state. + void FinishSyncSessionJob(const SyncSessionJob& job); + + // Record important state that might be needed in future syncs, such as which + // data types may require cleanup. + void UpdateCarryoverSessionState(const SyncSessionJob& old_job); + + // Helper to FinishSyncSessionJob to schedule the next sync operation. + void ScheduleNextSync(const SyncSessionJob& old_job); + + // Helper to configure polling intervals. Used by Start and ScheduleNextSync. + void AdjustPolling(const SyncSessionJob* old_job); + + // Helper to restart waiting with |wait_interval_|'s timer. + void RestartWaiting(); + + // Helper to ScheduleNextSync in case of consecutive sync errors. + void HandleContinuationError(const SyncSessionJob& old_job); + + // 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. + bool ShouldRunJob(const SyncSessionJob& job); + + // Decide whether we should CONTINUE, SAVE or DROP the job. + JobProcessDecision DecideOnJob(const SyncSessionJob& job); + + // Decide on whether to CONTINUE, SAVE or DROP the job when we are in + // backoff mode. + JobProcessDecision DecideWhileInWaitInterval(const SyncSessionJob& job); + + // Saves the job for future execution. Note: It drops all the poll jobs. + void SaveJob(const SyncSessionJob& job); + + // Coalesces the current job with the pending nudge. + void InitOrCoalescePendingJob(const SyncSessionJob& job); + + // 'Impl' here refers to real implementation of public functions, running on + // |thread_|. + void StartImpl(Mode mode, const base::Closure& callback); + void StopImpl(const base::Closure& callback); + void ScheduleNudgeImpl( + const base::TimeDelta& delay, + sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, + const syncable::ModelTypePayloadMap& types_with_payloads, + bool is_canary_job, const tracked_objects::Location& nudge_location); + void ScheduleConfigImpl(const ModelSafeRoutingInfo& routing_info, + const std::vector<ModelSafeWorker*>& workers, + const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source); + void ScheduleClearUserDataImpl(); + + // 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); + + // Callback to change backoff state. + void DoCanaryJob(); + void Unthrottle(); + + // Executes the pending job. Called whenever an event occurs that may + // change conditions permitting a job to run. Like when network connection is + // re-established, mode changes etc. + void DoPendingJobIfPossible(bool is_canary_job); + + // Called when the root cause of the current connection error is fixed. + void OnServerConnectionErrorFixed(); + + // The pointer is owned by the caller. + browser_sync::sessions::SyncSession* CreateSyncSession( + const browser_sync::sessions::SyncSourceInfo& info); + + // Creates a session for a poll and performs the sync. + void PollTimerCallback(); + + // Assign |start| and |end| to appropriate SyncerStep values for the + // specified |purpose|. + void SetSyncerStepsForPurpose(SyncSessionJob::SyncSessionJobPurpose purpose, + SyncerStep* start, + SyncerStep* end); + + // Used to update |server_connection_ok_|, see below. + void UpdateServerConnectionManagerStatus( + HttpResponse::ServerConnectionCode code); + + // Called once the first time thread_ is started to broadcast an initial + // session snapshot containing data like initial_sync_ended. Important when + // the client starts up and does not need to perform an initial sync. + void SendInitialSnapshot(); + + virtual void OnActionableError(const sessions::SyncSessionSnapshot& snapshot); + + base::WeakPtrFactory<SyncScheduler> weak_ptr_factory_; + + // A second factory specially for weak_handle_this_, to allow the handle + // to be const and alleviate threading concerns. + base::WeakPtrFactory<SyncScheduler> weak_ptr_factory_for_weak_handle_; + + // For certain methods that need to worry about X-thread posting. + const WeakHandle<SyncScheduler> weak_handle_this_; + + // Used for logging. + const std::string name_; + + // The message loop this object is on. Almost all methods have to + // be called on this thread. + MessageLoop* const sync_loop_; + + // Set in Start(), unset in Stop(). + bool started_; + + // Modifiable versions of kDefaultLongPollIntervalSeconds which can be + // updated by the server. + base::TimeDelta syncer_short_poll_interval_seconds_; + base::TimeDelta syncer_long_poll_interval_seconds_; + + // Server-tweakable sessions commit delay. + base::TimeDelta sessions_commit_delay_; + + // Periodic timer for polling. See AdjustPolling. + base::RepeatingTimer<SyncScheduler> poll_timer_; + + // The mode of operation. + Mode mode_; + + // TODO(tim): Bug 26339. This needs to track more than just time I think, + // since the nudges could be for different types. Current impl doesn't care. + base::TimeTicks last_sync_session_end_time_; + + // Have we observed a valid server connection? + bool server_connection_ok_; + + // The latest connection code we got while trying to connect. + HttpResponse::ServerConnectionCode connection_code_; + + // Tracks in-flight nudges so we can coalesce. + scoped_ptr<SyncSessionJob> pending_nudge_; + + // Current wait state. Null if we're not in backoff and not throttled. + scoped_ptr<WaitInterval> wait_interval_; + + scoped_ptr<DelayProvider> delay_provider_; + + // Invoked to run through the sync cycle. + scoped_ptr<Syncer> syncer_; + + scoped_ptr<sessions::SyncSessionContext> session_context_; + + DISALLOW_COPY_AND_ASSIGN(SyncScheduler); +}; + +} // namespace browser_sync + +#endif // SYNC_ENGINE_SYNC_SCHEDULER_H_ |