summaryrefslogtreecommitdiffstats
path: root/sync/engine/sync_scheduler.h
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-15 09:35:42 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-15 09:35:42 +0000
commitc1c32c85357f14756247b04b8b5ae41b05bf2e16 (patch)
tree58f25f64e1fa592e8daf276ef69901cd2218f929 /sync/engine/sync_scheduler.h
parent63ee33bde2ec8471a70f0f0ec6a1962dd07fc8ab (diff)
downloadchromium_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.h421
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_