More bring up of ui code on iOS.
[chromium-blink-merge.git] / sync / engine / sync_scheduler_impl.h
blob90ce57c86276aa7c91066be48100a7dfd41b3baf
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_
6 #define SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_
8 #include <map>
9 #include <string>
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/memory/linked_ptr.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/observer_list.h"
18 #include "base/time.h"
19 #include "base/timer.h"
20 #include "sync/engine/net/server_connection_manager.h"
21 #include "sync/engine/nudge_source.h"
22 #include "sync/engine/sync_scheduler.h"
23 #include "sync/engine/syncer.h"
24 #include "sync/internal_api/public/base/model_type_invalidation_map.h"
25 #include "sync/internal_api/public/engine/polling_constants.h"
26 #include "sync/internal_api/public/util/weak_handle.h"
27 #include "sync/sessions/sync_session.h"
28 #include "sync/sessions/sync_session_context.h"
30 namespace syncer {
32 class BackoffDelayProvider;
34 class SyncSchedulerImpl : public SyncScheduler {
35 public:
36 // |name| is a display string to identify the syncer thread. Takes
37 // |ownership of |syncer| and |delay_provider|.
38 SyncSchedulerImpl(const std::string& name,
39 BackoffDelayProvider* delay_provider,
40 sessions::SyncSessionContext* context,
41 Syncer* syncer);
43 // Calls Stop().
44 virtual ~SyncSchedulerImpl();
46 virtual void Start(Mode mode) OVERRIDE;
47 virtual bool ScheduleConfiguration(
48 const ConfigurationParams& params) OVERRIDE;
49 virtual void RequestStop(const base::Closure& callback) OVERRIDE;
50 virtual void ScheduleNudgeAsync(
51 const base::TimeDelta& delay,
52 NudgeSource source,
53 ModelTypeSet types,
54 const tracked_objects::Location& nudge_location) OVERRIDE;
55 virtual void ScheduleNudgeWithStatesAsync(
56 const base::TimeDelta& delay, NudgeSource source,
57 const ModelTypeInvalidationMap& invalidation_map,
58 const tracked_objects::Location& nudge_location) OVERRIDE;
59 virtual void SetNotificationsEnabled(bool notifications_enabled) OVERRIDE;
61 virtual base::TimeDelta GetSessionsCommitDelay() const OVERRIDE;
63 virtual void OnCredentialsUpdated() OVERRIDE;
64 virtual void OnConnectionStatusChange() OVERRIDE;
66 // SyncSession::Delegate implementation.
67 virtual void OnSilencedUntil(
68 const base::TimeTicks& silenced_until) OVERRIDE;
69 virtual bool IsSyncingCurrentlySilenced() OVERRIDE;
70 virtual void OnReceivedShortPollIntervalUpdate(
71 const base::TimeDelta& new_interval) OVERRIDE;
72 virtual void OnReceivedLongPollIntervalUpdate(
73 const base::TimeDelta& new_interval) OVERRIDE;
74 virtual void OnReceivedSessionsCommitDelay(
75 const base::TimeDelta& new_delay) OVERRIDE;
76 virtual void OnShouldStopSyncingPermanently() OVERRIDE;
77 virtual void OnSyncProtocolError(
78 const sessions::SyncSessionSnapshot& snapshot) OVERRIDE;
80 private:
81 enum JobProcessDecision {
82 // Indicates we should continue with the current job.
83 CONTINUE,
84 // Indicates that we should save it to be processed later.
85 SAVE,
86 // Indicates we should drop this job.
87 DROP,
90 struct SyncSessionJob {
91 // An enum used to describe jobs for scheduling purposes.
92 enum SyncSessionJobPurpose {
93 // Uninitialized state, should never be hit in practice.
94 UNKNOWN = -1,
95 // Our poll timer schedules POLL jobs periodically based on a server
96 // assigned poll interval.
97 POLL,
98 // A nudge task can come from a variety of components needing to force
99 // a sync. The source is inferable from |session.source()|.
100 NUDGE,
101 // Typically used for fetching updates for a subset of the enabled types
102 // during initial sync or reconfiguration.
103 CONFIGURATION,
105 SyncSessionJob();
106 SyncSessionJob(SyncSessionJobPurpose purpose, base::TimeTicks start,
107 linked_ptr<sessions::SyncSession> session, bool is_canary_job,
108 const ConfigurationParams& config_params,
109 const tracked_objects::Location& nudge_location);
110 ~SyncSessionJob();
111 static const char* GetPurposeString(SyncSessionJobPurpose purpose);
113 SyncSessionJobPurpose purpose;
114 base::TimeTicks scheduled_start;
115 linked_ptr<sessions::SyncSession> session;
116 bool is_canary_job;
117 ConfigurationParams config_params;
119 // This is the location the job came from. Used for debugging.
120 // In case of multiple nudges getting coalesced this stores the
121 // first location that came in.
122 tracked_objects::Location from_here;
124 friend class SyncSchedulerTest;
125 friend class SyncSchedulerWhiteboxTest;
126 friend class SyncerTest;
128 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
129 DropNudgeWhileExponentialBackOff);
130 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, SaveNudge);
131 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
132 SaveNudgeWhileTypeThrottled);
133 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueNudge);
134 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, DropPoll);
135 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinuePoll);
136 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueConfiguration);
137 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
138 SaveConfigurationWhileThrottled);
139 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
140 SaveNudgeWhileThrottled);
141 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
142 ContinueCanaryJobConfig);
143 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
144 ContinueNudgeWhileExponentialBackOff);
145 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, TransientPollFailure);
146 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, GetInitialBackoffDelay);
148 struct WaitInterval {
149 enum Mode {
150 // Uninitialized state, should not be set in practice.
151 UNKNOWN = -1,
152 // A wait interval whose duration has been affected by exponential
153 // backoff.
154 // EXPONENTIAL_BACKOFF intervals are nudge-rate limited to 1 per interval.
155 EXPONENTIAL_BACKOFF,
156 // A server-initiated throttled interval. We do not allow any syncing
157 // during such an interval.
158 THROTTLED,
160 WaitInterval();
161 ~WaitInterval();
162 WaitInterval(Mode mode, base::TimeDelta length);
164 static const char* GetModeString(Mode mode);
166 Mode mode;
168 // This bool is set to true if we have observed a nudge during this
169 // interval and mode == EXPONENTIAL_BACKOFF.
170 bool had_nudge;
171 base::TimeDelta length;
172 base::OneShotTimer<SyncSchedulerImpl> timer;
174 // Configure jobs are saved only when backing off or throttling. So we
175 // expose the pointer here.
176 scoped_ptr<SyncSessionJob> pending_configure_job;
179 static const char* GetModeString(Mode mode);
181 static const char* GetDecisionString(JobProcessDecision decision);
183 // Assign |start| and |end| to appropriate SyncerStep values for the
184 // specified |purpose|.
185 static void SetSyncerStepsForPurpose(
186 SyncSessionJob::SyncSessionJobPurpose purpose,
187 SyncerStep* start, SyncerStep* end);
189 // Helpers that log before posting to |sync_loop_|. These will only post
190 // the task in between calls to Start/Stop.
191 void PostTask(const tracked_objects::Location& from_here,
192 const char* name,
193 const base::Closure& task);
194 void PostDelayedTask(const tracked_objects::Location& from_here,
195 const char* name,
196 const base::Closure& task,
197 base::TimeDelta delay);
199 // Helper to assemble a job and post a delayed task to sync.
200 void ScheduleSyncSessionJob(const SyncSessionJob& job);
202 // Invoke the Syncer to perform a sync.
203 void DoSyncSessionJob(const SyncSessionJob& job);
205 // Called after the Syncer has performed the sync represented by |job|, to
206 // reset our state.
207 void FinishSyncSessionJob(const SyncSessionJob& job);
209 // Helper to FinishSyncSessionJob to schedule the next sync operation.
210 void ScheduleNextSync(const SyncSessionJob& old_job);
212 // Helper to configure polling intervals. Used by Start and ScheduleNextSync.
213 void AdjustPolling(const SyncSessionJob* old_job);
215 // Helper to restart waiting with |wait_interval_|'s timer.
216 void RestartWaiting();
218 // Helper to ScheduleNextSync in case of consecutive sync errors.
219 void HandleContinuationError(const SyncSessionJob& old_job);
221 // Determines if it is legal to run |job| by checking current
222 // operational mode, backoff or throttling, freshness
223 // (so we don't make redundant syncs), and connection.
224 bool ShouldRunJob(const SyncSessionJob& job);
226 // Decide whether we should CONTINUE, SAVE or DROP the job.
227 JobProcessDecision DecideOnJob(const SyncSessionJob& job);
229 // Decide on whether to CONTINUE, SAVE or DROP the job when we are in
230 // backoff mode.
231 JobProcessDecision DecideWhileInWaitInterval(const SyncSessionJob& job);
233 // Saves the job for future execution. Note: It drops all the poll jobs.
234 void SaveJob(const SyncSessionJob& job);
236 // Coalesces the current job with the pending nudge.
237 void InitOrCoalescePendingJob(const SyncSessionJob& job);
239 // 'Impl' here refers to real implementation of public functions, running on
240 // |thread_|.
241 void StopImpl(const base::Closure& callback);
242 void ScheduleNudgeImpl(
243 const base::TimeDelta& delay,
244 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
245 const ModelTypeInvalidationMap& invalidation_map,
246 bool is_canary_job, const tracked_objects::Location& nudge_location);
248 // Returns true if the client is currently in exponential backoff.
249 bool IsBackingOff() const;
251 // Helper to signal all listeners registered with |session_context_|.
252 void Notify(SyncEngineEvent::EventCause cause);
254 // Callback to change backoff state.
255 void DoCanaryJob();
256 void Unthrottle();
258 // Executes the pending job. Called whenever an event occurs that may
259 // change conditions permitting a job to run. Like when network connection is
260 // re-established, mode changes etc.
261 void DoPendingJobIfPossible(bool is_canary_job);
263 // Called when the root cause of the current connection error is fixed.
264 void OnServerConnectionErrorFixed();
266 // The pointer is owned by the caller.
267 sessions::SyncSession* CreateSyncSession(
268 const sessions::SyncSourceInfo& info);
270 // Creates a session for a poll and performs the sync.
271 void PollTimerCallback();
273 // Used to update |connection_code_|, see below.
274 void UpdateServerConnectionManagerStatus(
275 HttpResponse::ServerConnectionCode code);
277 // Called once the first time thread_ is started to broadcast an initial
278 // session snapshot containing data like initial_sync_ended. Important when
279 // the client starts up and does not need to perform an initial sync.
280 void SendInitialSnapshot();
282 // This is used for histogramming and analysis of ScheduleNudge* APIs.
283 // SyncScheduler is the ultimate choke-point for all such invocations (with
284 // and without InvalidationState variants, all NudgeSources, etc) and as such
285 // is the most flexible place to do this bookkeeping.
286 void UpdateNudgeTimeRecords(const sessions::SyncSourceInfo& info);
288 virtual void OnActionableError(const sessions::SyncSessionSnapshot& snapshot);
290 base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_;
292 // A second factory specially for weak_handle_this_, to allow the handle
293 // to be const and alleviate threading concerns.
294 base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_for_weak_handle_;
296 // For certain methods that need to worry about X-thread posting.
297 const WeakHandle<SyncSchedulerImpl> weak_handle_this_;
299 // Used for logging.
300 const std::string name_;
302 // The message loop this object is on. Almost all methods have to
303 // be called on this thread.
304 MessageLoop* const sync_loop_;
306 // Set in Start(), unset in Stop().
307 bool started_;
309 // Modifiable versions of kDefaultLongPollIntervalSeconds which can be
310 // updated by the server.
311 base::TimeDelta syncer_short_poll_interval_seconds_;
312 base::TimeDelta syncer_long_poll_interval_seconds_;
314 // Server-tweakable sessions commit delay.
315 base::TimeDelta sessions_commit_delay_;
317 // Periodic timer for polling. See AdjustPolling.
318 base::RepeatingTimer<SyncSchedulerImpl> poll_timer_;
320 // The mode of operation.
321 Mode mode_;
323 // The latest connection code we got while trying to connect.
324 HttpResponse::ServerConnectionCode connection_code_;
326 // Tracks in-flight nudges so we can coalesce.
327 scoped_ptr<SyncSessionJob> pending_nudge_;
329 // Current wait state. Null if we're not in backoff and not throttled.
330 scoped_ptr<WaitInterval> wait_interval_;
332 scoped_ptr<BackoffDelayProvider> delay_provider_;
334 // Invoked to run through the sync cycle.
335 scoped_ptr<Syncer> syncer_;
337 sessions::SyncSessionContext* session_context_;
339 // A map tracking LOCAL NudgeSource invocations of ScheduleNudge* APIs,
340 // organized by datatype. Each datatype that was part of the types requested
341 // in the call will have its TimeTicks value updated.
342 typedef std::map<ModelType, base::TimeTicks> ModelTypeTimeMap;
343 ModelTypeTimeMap last_local_nudges_by_model_type_;
345 // Used as an "anti-reentrancy defensive assertion".
346 // While true, it is illegal for any new scheduling activity to take place.
347 // Ensures that higher layers don't break this law in response to events that
348 // take place during a sync cycle. We call this out because such violations
349 // could result in tight sync loops hitting sync servers.
350 bool no_scheduling_allowed_;
352 DISALLOW_COPY_AND_ASSIGN(SyncSchedulerImpl);
355 } // namespace syncer
357 #endif // SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_