Update .DEPS.git
[chromium-blink-merge.git] / sync / engine / sync_scheduler_impl.h
blob68d2a802ed9680b5aea9ed07313e87dca0b431d1
1 // Copyright 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/cancelable_callback.h"
13 #include "base/compiler_specific.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/memory/linked_ptr.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/threading/non_thread_safe.h"
19 #include "base/time/time.h"
20 #include "base/timer/timer.h"
21 #include "sync/base/sync_export.h"
22 #include "sync/engine/net/server_connection_manager.h"
23 #include "sync/engine/nudge_source.h"
24 #include "sync/engine/sync_scheduler.h"
25 #include "sync/engine/syncer.h"
26 #include "sync/internal_api/public/engine/polling_constants.h"
27 #include "sync/internal_api/public/util/weak_handle.h"
28 #include "sync/sessions/nudge_tracker.h"
29 #include "sync/sessions/sync_session.h"
30 #include "sync/sessions/sync_session_context.h"
32 namespace syncer {
34 class BackoffDelayProvider;
36 namespace sessions {
37 struct ModelNeutralState;
40 class SYNC_EXPORT_PRIVATE SyncSchedulerImpl
41 : public SyncScheduler,
42 public base::NonThreadSafe {
43 public:
44 // |name| is a display string to identify the syncer thread. Takes
45 // |ownership of |syncer| and |delay_provider|.
46 SyncSchedulerImpl(const std::string& name,
47 BackoffDelayProvider* delay_provider,
48 sessions::SyncSessionContext* context,
49 Syncer* syncer);
51 // Calls Stop().
52 virtual ~SyncSchedulerImpl();
54 virtual void Start(Mode mode) OVERRIDE;
55 virtual void ScheduleConfiguration(
56 const ConfigurationParams& params) OVERRIDE;
57 virtual void Stop() OVERRIDE;
58 virtual void ScheduleLocalNudge(
59 const base::TimeDelta& desired_delay,
60 ModelTypeSet types,
61 const tracked_objects::Location& nudge_location) OVERRIDE;
62 virtual void ScheduleLocalRefreshRequest(
63 const base::TimeDelta& desired_delay,
64 ModelTypeSet types,
65 const tracked_objects::Location& nudge_location) OVERRIDE;
66 virtual void ScheduleInvalidationNudge(
67 const base::TimeDelta& desired_delay,
68 const ObjectIdInvalidationMap& invalidation_map,
69 const tracked_objects::Location& nudge_location) OVERRIDE;
70 virtual void SetNotificationsEnabled(bool notifications_enabled) OVERRIDE;
72 virtual base::TimeDelta GetSessionsCommitDelay() const OVERRIDE;
74 virtual void OnCredentialsUpdated() OVERRIDE;
75 virtual void OnConnectionStatusChange() OVERRIDE;
77 // SyncSession::Delegate implementation.
78 virtual void OnThrottled(const base::TimeDelta& throttle_duration) OVERRIDE;
79 virtual void OnTypesThrottled(
80 ModelTypeSet types,
81 const base::TimeDelta& throttle_duration) OVERRIDE;
82 virtual bool IsCurrentlyThrottled() OVERRIDE;
83 virtual void OnReceivedShortPollIntervalUpdate(
84 const base::TimeDelta& new_interval) OVERRIDE;
85 virtual void OnReceivedLongPollIntervalUpdate(
86 const base::TimeDelta& new_interval) OVERRIDE;
87 virtual void OnReceivedSessionsCommitDelay(
88 const base::TimeDelta& new_delay) OVERRIDE;
89 virtual void OnReceivedClientInvalidationHintBufferSize(int size) OVERRIDE;
90 virtual void OnSyncProtocolError(
91 const sessions::SyncSessionSnapshot& snapshot) OVERRIDE;
92 virtual void OnReceivedGuRetryDelay(const base::TimeDelta& delay) OVERRIDE;
94 // Returns true if the client is currently in exponential backoff.
95 bool IsBackingOff() const;
97 private:
98 enum JobPriority {
99 // Non-canary jobs respect exponential backoff.
100 NORMAL_PRIORITY,
101 // Canary jobs bypass exponential backoff, so use with extreme caution.
102 CANARY_PRIORITY
105 enum PollAdjustType {
106 // Restart the poll interval.
107 FORCE_RESET,
108 // Restart the poll interval only if its length has changed.
109 UPDATE_INTERVAL,
112 friend class SyncSchedulerTest;
113 friend class SyncSchedulerWhiteboxTest;
114 friend class SyncerTest;
116 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, NoNudgesInConfigureMode);
117 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
118 DropNudgeWhileExponentialBackOff);
119 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, SaveNudge);
120 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
121 SaveNudgeWhileTypeThrottled);
122 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueNudge);
123 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueConfiguration);
124 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
125 SaveConfigurationWhileThrottled);
126 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
127 SaveNudgeWhileThrottled);
128 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
129 ContinueCanaryJobConfig);
130 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, TransientPollFailure);
131 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest,
132 ServerConnectionChangeDuringBackoff);
133 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest,
134 ConnectionChangeCanaryPreemptedByNudge);
135 FRIEND_TEST_ALL_PREFIXES(BackoffTriggersSyncSchedulerTest,
136 FailGetEncryptionKey);
138 struct SYNC_EXPORT_PRIVATE WaitInterval {
139 enum Mode {
140 // Uninitialized state, should not be set in practice.
141 UNKNOWN = -1,
142 // We enter a series of increasingly longer WaitIntervals if we experience
143 // repeated transient failures. We retry at the end of each interval.
144 EXPONENTIAL_BACKOFF,
145 // A server-initiated throttled interval. We do not allow any syncing
146 // during such an interval.
147 THROTTLED,
149 WaitInterval();
150 ~WaitInterval();
151 WaitInterval(Mode mode, base::TimeDelta length);
153 static const char* GetModeString(Mode mode);
155 Mode mode;
156 base::TimeDelta length;
159 static const char* GetModeString(Mode mode);
161 // Invoke the syncer to perform a nudge job.
162 void DoNudgeSyncSessionJob(JobPriority priority);
164 // Invoke the syncer to perform a configuration job.
165 void DoConfigurationSyncSessionJob(JobPriority priority);
167 // Helper function for Do{Nudge,Configuration}SyncSessionJob.
168 void HandleFailure(
169 const sessions::ModelNeutralState& model_neutral_state);
171 // Invoke the Syncer to perform a poll job.
172 void DoPollSyncSessionJob();
174 // Invoke the Syncer to perform a retry job.
175 void DoRetrySyncSessionJob();
177 // Helper function to calculate poll interval.
178 base::TimeDelta GetPollInterval();
180 // Adjusts the poll timer to account for new poll interval, and possibly
181 // resets the poll interval, depedning on the flag's value.
182 void AdjustPolling(PollAdjustType type);
184 // Helper to restart waiting with |wait_interval_|'s timer.
185 void RestartWaiting();
187 // Determines if we're allowed to contact the server right now.
188 bool CanRunJobNow(JobPriority priority);
190 // Determines if we're allowed to contact the server right now.
191 bool CanRunNudgeJobNow(JobPriority priority);
193 // If the scheduler's current state supports it, this will create a job based
194 // on the passed in parameters and coalesce it with any other pending jobs,
195 // then post a delayed task to run it. It may also choose to drop the job or
196 // save it for later, depending on the scheduler's current state.
197 void ScheduleNudgeImpl(
198 const base::TimeDelta& delay,
199 const tracked_objects::Location& nudge_location);
201 // Helper to signal all listeners registered with |session_context_|.
202 void Notify(SyncEngineEvent::EventCause cause);
204 // Helper to signal listeners about changed retry time.
205 void NotifyRetryTime(base::Time retry_time);
207 // Helper to signal listeners about changed throttled types.
208 void NotifyThrottledTypesChanged(ModelTypeSet types);
210 // Looks for pending work and, if it finds any, run this work at "canary"
211 // priority.
212 void TryCanaryJob();
214 // At the moment TrySyncSessionJob just posts call to TrySyncSessionJobImpl on
215 // current thread. In the future it will request access token here.
216 void TrySyncSessionJob();
217 void TrySyncSessionJobImpl();
219 // Transitions out of the THROTTLED WaitInterval then calls TryCanaryJob().
220 void Unthrottle();
222 // Called when a per-type throttling interval expires.
223 void TypeUnthrottle(base::TimeTicks unthrottle_time);
225 // Runs a normal nudge job when the scheduled timer expires.
226 void PerformDelayedNudge();
228 // Attempts to exit EXPONENTIAL_BACKOFF by calling TryCanaryJob().
229 void ExponentialBackoffRetry();
231 // Called when the root cause of the current connection error is fixed.
232 void OnServerConnectionErrorFixed();
234 // Creates a session for a poll and performs the sync.
235 void PollTimerCallback();
237 // Creates a session for a retry and performs the sync.
238 void RetryTimerCallback();
240 // Returns the set of types that are enabled and not currently throttled.
241 ModelTypeSet GetEnabledAndUnthrottledTypes();
243 // Called as we are started to broadcast an initial session snapshot
244 // containing data like initial_sync_ended. Important when the client starts
245 // up and does not need to perform an initial sync.
246 void SendInitialSnapshot();
248 // This is used for histogramming and analysis of ScheduleNudge* APIs.
249 // SyncScheduler is the ultimate choke-point for all such invocations (with
250 // and without InvalidationState variants, all NudgeSources, etc) and as such
251 // is the most flexible place to do this bookkeeping.
252 void UpdateNudgeTimeRecords(ModelTypeSet types);
254 virtual void OnActionableError(const sessions::SyncSessionSnapshot& snapshot);
256 // For certain methods that need to worry about X-thread posting.
257 WeakHandle<SyncSchedulerImpl> weak_handle_this_;
259 // Used for logging.
260 const std::string name_;
262 // Set in Start(), unset in Stop().
263 bool started_;
265 // Modifiable versions of kDefaultLongPollIntervalSeconds which can be
266 // updated by the server.
267 base::TimeDelta syncer_short_poll_interval_seconds_;
268 base::TimeDelta syncer_long_poll_interval_seconds_;
270 // Server-tweakable sessions commit delay.
271 base::TimeDelta sessions_commit_delay_;
273 // Periodic timer for polling. See AdjustPolling.
274 base::RepeatingTimer<SyncSchedulerImpl> poll_timer_;
276 // The mode of operation.
277 Mode mode_;
279 // Current wait state. Null if we're not in backoff and not throttled.
280 scoped_ptr<WaitInterval> wait_interval_;
282 scoped_ptr<BackoffDelayProvider> delay_provider_;
284 // The event that will wake us up.
285 base::OneShotTimer<SyncSchedulerImpl> pending_wakeup_timer_;
287 // An event that fires when data type throttling expires.
288 base::OneShotTimer<SyncSchedulerImpl> type_unthrottle_timer_;
290 // Storage for variables related to an in-progress configure request. Note
291 // that (mode_ != CONFIGURATION_MODE) \implies !pending_configure_params_.
292 scoped_ptr<ConfigurationParams> pending_configure_params_;
294 // If we have a nudge pending to run soon, it will be listed here.
295 base::TimeTicks scheduled_nudge_time_;
297 // Keeps track of work that the syncer needs to handle.
298 sessions::NudgeTracker nudge_tracker_;
300 // Invoked to run through the sync cycle.
301 scoped_ptr<Syncer> syncer_;
303 sessions::SyncSessionContext* session_context_;
305 // A map tracking LOCAL NudgeSource invocations of ScheduleNudge* APIs,
306 // organized by datatype. Each datatype that was part of the types requested
307 // in the call will have its TimeTicks value updated.
308 typedef std::map<ModelType, base::TimeTicks> ModelTypeTimeMap;
309 ModelTypeTimeMap last_local_nudges_by_model_type_;
311 // Used as an "anti-reentrancy defensive assertion".
312 // While true, it is illegal for any new scheduling activity to take place.
313 // Ensures that higher layers don't break this law in response to events that
314 // take place during a sync cycle. We call this out because such violations
315 // could result in tight sync loops hitting sync servers.
316 bool no_scheduling_allowed_;
318 // crbug/251307. This is a workaround for M29. crbug/259913 tracks proper fix
319 // for M30.
320 // The issue is that poll job runs after few hours of inactivity and therefore
321 // will always fail with auth error because of expired access token. Once
322 // fresh access token is requested poll job is not retried.
323 // The change is to remember that poll timer just fired and retry poll job
324 // after credentials are updated.
325 bool do_poll_after_credentials_updated_;
327 // TryJob might get called for multiple reasons. It should only call
328 // DoPollSyncSessionJob after some time since the last attempt.
329 // last_poll_reset_ keeps track of when was last attempt.
330 base::TimeTicks last_poll_reset_;
332 // next_sync_session_job_priority_ defines which priority will be used next
333 // time TrySyncSessionJobImpl is called. CANARY_PRIORITY allows syncer to run
334 // even if scheduler is in exponential backoff. This is needed for events that
335 // have chance of resolving previous error (e.g. network connection change
336 // after NETWORK_UNAVAILABLE error).
337 // It is reset back to NORMAL_PRIORITY on every call to TrySyncSessionJobImpl.
338 JobPriority next_sync_session_job_priority_;
340 base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_;
342 // A second factory specially for weak_handle_this_, to allow the handle
343 // to be const and alleviate threading concerns.
344 base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_for_weak_handle_;
346 // One-shot timer for scheduling GU retry according to delay set by server.
347 base::OneShotTimer<SyncSchedulerImpl> retry_timer_;
349 DISALLOW_COPY_AND_ASSIGN(SyncSchedulerImpl);
352 } // namespace syncer
354 #endif // SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_