Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / sync / engine / sync_scheduler_impl.h
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.
4
5 #ifndef SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_
6 #define SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_
7
8 #include <map>
9 #include <string>
10
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"
31
32 namespace syncer {
33
34 class BackoffDelayProvider;
35
36 namespace sessions {
37 struct ModelNeutralState;
38 }
39
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);
50
51   // Calls Stop().
52   virtual ~SyncSchedulerImpl();
53
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       syncer::ModelType type,
69       scoped_ptr<InvalidationInterface> invalidation,
70       const tracked_objects::Location& nudge_location) OVERRIDE;
71   virtual void ScheduleInitialSyncNudge(syncer::ModelType model_type) OVERRIDE;
72   virtual void SetNotificationsEnabled(bool notifications_enabled) OVERRIDE;
73
74   virtual base::TimeDelta GetSessionsCommitDelay() const OVERRIDE;
75
76   virtual void OnCredentialsUpdated() OVERRIDE;
77   virtual void OnConnectionStatusChange() OVERRIDE;
78
79   // SyncSession::Delegate implementation.
80   virtual void OnThrottled(const base::TimeDelta& throttle_duration) OVERRIDE;
81   virtual void OnTypesThrottled(
82       ModelTypeSet types,
83       const base::TimeDelta& throttle_duration) OVERRIDE;
84   virtual bool IsCurrentlyThrottled() OVERRIDE;
85   virtual void OnReceivedShortPollIntervalUpdate(
86       const base::TimeDelta& new_interval) OVERRIDE;
87   virtual void OnReceivedLongPollIntervalUpdate(
88       const base::TimeDelta& new_interval) OVERRIDE;
89   virtual void OnReceivedSessionsCommitDelay(
90       const base::TimeDelta& new_delay) OVERRIDE;
91   virtual void OnReceivedClientInvalidationHintBufferSize(int size) OVERRIDE;
92   virtual void OnSyncProtocolError(
93       const SyncProtocolError& sync_protocol_error) OVERRIDE;
94   virtual void OnReceivedGuRetryDelay(const base::TimeDelta& delay) OVERRIDE;
95   virtual void OnReceivedMigrationRequest(syncer::ModelTypeSet types) OVERRIDE;
96
97   // Returns true if the client is currently in exponential backoff.
98   bool IsBackingOff() const;
99
100  private:
101   enum JobPriority {
102     // Non-canary jobs respect exponential backoff.
103     NORMAL_PRIORITY,
104     // Canary jobs bypass exponential backoff, so use with extreme caution.
105     CANARY_PRIORITY
106   };
107
108   enum PollAdjustType {
109     // Restart the poll interval.
110     FORCE_RESET,
111     // Restart the poll interval only if its length has changed.
112     UPDATE_INTERVAL,
113   };
114
115   friend class SyncSchedulerTest;
116   friend class SyncSchedulerWhiteboxTest;
117   friend class SyncerTest;
118
119   FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, TransientPollFailure);
120   FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest,
121                            ServerConnectionChangeDuringBackoff);
122   FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest,
123                            ConnectionChangeCanaryPreemptedByNudge);
124   FRIEND_TEST_ALL_PREFIXES(BackoffTriggersSyncSchedulerTest,
125                            FailGetEncryptionKey);
126   FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, SuccessfulRetry);
127   FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, FailedRetry);
128   FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, ReceiveNewRetryDelay);
129
130   struct SYNC_EXPORT_PRIVATE WaitInterval {
131     enum Mode {
132       // Uninitialized state, should not be set in practice.
133       UNKNOWN = -1,
134       // We enter a series of increasingly longer WaitIntervals if we experience
135       // repeated transient failures.  We retry at the end of each interval.
136       EXPONENTIAL_BACKOFF,
137       // A server-initiated throttled interval.  We do not allow any syncing
138       // during such an interval.
139       THROTTLED,
140     };
141     WaitInterval();
142     ~WaitInterval();
143     WaitInterval(Mode mode, base::TimeDelta length);
144
145     static const char* GetModeString(Mode mode);
146
147     Mode mode;
148     base::TimeDelta length;
149   };
150
151   static const char* GetModeString(Mode mode);
152
153   // Invoke the syncer to perform a nudge job.
154   void DoNudgeSyncSessionJob(JobPriority priority);
155
156   // Invoke the syncer to perform a configuration job.
157   void DoConfigurationSyncSessionJob(JobPriority priority);
158
159   // Helper function for Do{Nudge,Configuration}SyncSessionJob.
160   void HandleFailure(
161       const sessions::ModelNeutralState& model_neutral_state);
162
163   // Invoke the Syncer to perform a poll job.
164   void DoPollSyncSessionJob();
165
166   // Helper function to calculate poll interval.
167   base::TimeDelta GetPollInterval();
168
169   // Adjusts the poll timer to account for new poll interval, and possibly
170   // resets the poll interval, depedning on the flag's value.
171   void AdjustPolling(PollAdjustType type);
172
173   // Helper to restart waiting with |wait_interval_|'s timer.
174   void RestartWaiting();
175
176   // Determines if we're allowed to contact the server right now.
177   bool CanRunJobNow(JobPriority priority);
178
179   // Determines if we're allowed to contact the server right now.
180   bool CanRunNudgeJobNow(JobPriority priority);
181
182   // If the scheduler's current state supports it, this will create a job based
183   // on the passed in parameters and coalesce it with any other pending jobs,
184   // then post a delayed task to run it.  It may also choose to drop the job or
185   // save it for later, depending on the scheduler's current state.
186   void ScheduleNudgeImpl(
187       const base::TimeDelta& delay,
188       const tracked_objects::Location& nudge_location);
189
190   // Helper to signal listeners about changed retry time.
191   void NotifyRetryTime(base::Time retry_time);
192
193   // Helper to signal listeners about changed throttled types.
194   void NotifyThrottledTypesChanged(ModelTypeSet types);
195
196   // Looks for pending work and, if it finds any, run this work at "canary"
197   // priority.
198   void TryCanaryJob();
199
200   // At the moment TrySyncSessionJob just posts call to TrySyncSessionJobImpl on
201   // current thread. In the future it will request access token here.
202   void TrySyncSessionJob();
203   void TrySyncSessionJobImpl();
204
205   // Transitions out of the THROTTLED WaitInterval then calls TryCanaryJob().
206   void Unthrottle();
207
208   // Called when a per-type throttling interval expires.
209   void TypeUnthrottle(base::TimeTicks unthrottle_time);
210
211   // Runs a normal nudge job when the scheduled timer expires.
212   void PerformDelayedNudge();
213
214   // Attempts to exit EXPONENTIAL_BACKOFF by calling TryCanaryJob().
215   void ExponentialBackoffRetry();
216
217   // Called when the root cause of the current connection error is fixed.
218   void OnServerConnectionErrorFixed();
219
220   // Creates a session for a poll and performs the sync.
221   void PollTimerCallback();
222
223   // Creates a session for a retry and performs the sync.
224   void RetryTimerCallback();
225
226   // Returns the set of types that are enabled and not currently throttled.
227   ModelTypeSet GetEnabledAndUnthrottledTypes();
228
229   // Called as we are started to broadcast an initial session snapshot
230   // containing data like initial_sync_ended.  Important when the client starts
231   // up and does not need to perform an initial sync.
232   void SendInitialSnapshot();
233
234   // This is used for histogramming and analysis of ScheduleNudge* APIs.
235   // SyncScheduler is the ultimate choke-point for all such invocations (with
236   // and without InvalidationState variants, all NudgeSources, etc) and as such
237   // is the most flexible place to do this bookkeeping.
238   void UpdateNudgeTimeRecords(ModelTypeSet types);
239
240   // For certain methods that need to worry about X-thread posting.
241   WeakHandle<SyncSchedulerImpl> weak_handle_this_;
242
243   // Used for logging.
244   const std::string name_;
245
246   // Set in Start(), unset in Stop().
247   bool started_;
248
249   // Modifiable versions of kDefaultLongPollIntervalSeconds which can be
250   // updated by the server.
251   base::TimeDelta syncer_short_poll_interval_seconds_;
252   base::TimeDelta syncer_long_poll_interval_seconds_;
253
254   // Server-tweakable sessions commit delay.
255   base::TimeDelta sessions_commit_delay_;
256
257   // Periodic timer for polling.  See AdjustPolling.
258   base::RepeatingTimer<SyncSchedulerImpl> poll_timer_;
259
260   // The mode of operation.
261   Mode mode_;
262
263   // Current wait state.  Null if we're not in backoff and not throttled.
264   scoped_ptr<WaitInterval> wait_interval_;
265
266   scoped_ptr<BackoffDelayProvider> delay_provider_;
267
268   // The event that will wake us up.
269   base::OneShotTimer<SyncSchedulerImpl> pending_wakeup_timer_;
270
271   // An event that fires when data type throttling expires.
272   base::OneShotTimer<SyncSchedulerImpl> type_unthrottle_timer_;
273
274   // Storage for variables related to an in-progress configure request.  Note
275   // that (mode_ != CONFIGURATION_MODE) \implies !pending_configure_params_.
276   scoped_ptr<ConfigurationParams> pending_configure_params_;
277
278   // If we have a nudge pending to run soon, it will be listed here.
279   base::TimeTicks scheduled_nudge_time_;
280
281   // Keeps track of work that the syncer needs to handle.
282   sessions::NudgeTracker nudge_tracker_;
283
284   // Invoked to run through the sync cycle.
285   scoped_ptr<Syncer> syncer_;
286
287   sessions::SyncSessionContext* session_context_;
288
289   // A map tracking LOCAL NudgeSource invocations of ScheduleNudge* APIs,
290   // organized by datatype. Each datatype that was part of the types requested
291   // in the call will have its TimeTicks value updated.
292   typedef std::map<ModelType, base::TimeTicks> ModelTypeTimeMap;
293   ModelTypeTimeMap last_local_nudges_by_model_type_;
294
295   // Used as an "anti-reentrancy defensive assertion".
296   // While true, it is illegal for any new scheduling activity to take place.
297   // Ensures that higher layers don't break this law in response to events that
298   // take place during a sync cycle. We call this out because such violations
299   // could result in tight sync loops hitting sync servers.
300   bool no_scheduling_allowed_;
301
302   // crbug/251307. This is a workaround for M29. crbug/259913 tracks proper fix
303   // for M30.
304   // The issue is that poll job runs after few hours of inactivity and therefore
305   // will always fail with auth error because of expired access token. Once
306   // fresh access token is requested poll job is not retried.
307   // The change is to remember that poll timer just fired and retry poll job
308   // after credentials are updated.
309   bool do_poll_after_credentials_updated_;
310
311   // TryJob might get called for multiple reasons. It should only call
312   // DoPollSyncSessionJob after some time since the last attempt.
313   // last_poll_reset_ keeps track of when was last attempt.
314   base::TimeTicks last_poll_reset_;
315
316   // next_sync_session_job_priority_ defines which priority will be used next
317   // time TrySyncSessionJobImpl is called. CANARY_PRIORITY allows syncer to run
318   // even if scheduler is in exponential backoff. This is needed for events that
319   // have chance of resolving previous error (e.g. network connection change
320   // after NETWORK_UNAVAILABLE error).
321   // It is reset back to NORMAL_PRIORITY on every call to TrySyncSessionJobImpl.
322   JobPriority next_sync_session_job_priority_;
323
324   // One-shot timer for scheduling GU retry according to delay set by server.
325   base::OneShotTimer<SyncSchedulerImpl> retry_timer_;
326
327   base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_;
328
329   // A second factory specially for weak_handle_this_, to allow the handle
330   // to be const and alleviate threading concerns.
331   base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_for_weak_handle_;
332
333   DISALLOW_COPY_AND_ASSIGN(SyncSchedulerImpl);
334 };
335
336 }  // namespace syncer
337
338 #endif  // SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_