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