Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: chrome/browser/sync/engine/sync_scheduler.h

Issue 9699057: [Sync] Move 'sync' target to sync/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Tim's comments Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4 //
5 // A class to schedule syncer tasks intelligently.
6 #ifndef CHROME_BROWSER_SYNC_ENGINE_SYNC_SCHEDULER_H_
7 #define CHROME_BROWSER_SYNC_ENGINE_SYNC_SCHEDULER_H_
8 #pragma once
9
10 #include <string>
11
12 #include "base/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/observer_list.h"
19 #include "base/time.h"
20 #include "base/timer.h"
21 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
22 #include "chrome/browser/sync/engine/nudge_source.h"
23 #include "chrome/browser/sync/engine/polling_constants.h"
24 #include "chrome/browser/sync/engine/syncer.h"
25 #include "chrome/browser/sync/sessions/sync_session_context.h"
26 #include "chrome/browser/sync/sessions/sync_session.h"
27 #include "chrome/browser/sync/syncable/model_type_payload_map.h"
28 #include "chrome/browser/sync/util/weak_handle.h"
29
30 class MessageLoop;
31
32 namespace tracked_objects {
33 class Location;
34 } // namespace tracked_objects
35
36 namespace browser_sync {
37
38 struct ServerConnectionEvent;
39
40 class SyncScheduler : public sessions::SyncSession::Delegate {
41 public:
42 enum Mode {
43 // In this mode, the thread only performs configuration tasks. This is
44 // designed to make the case where we want to download updates for a
45 // specific type only, and not continue syncing until we are moved into
46 // normal mode.
47 CONFIGURATION_MODE,
48 // Resumes polling and allows nudges, drops configuration tasks. Runs
49 // through entire sync cycle.
50 NORMAL_MODE,
51 };
52
53 // All methods of SyncScheduler must be called on the same thread
54 // (except for RequestEarlyExit()).
55
56 // |name| is a display string to identify the syncer thread. Takes
57 // |ownership of both |context| and |syncer|.
58 SyncScheduler(const std::string& name,
59 sessions::SyncSessionContext* context, Syncer* syncer);
60
61 // Calls Stop().
62 virtual ~SyncScheduler();
63
64 // Start the scheduler with the given mode. If the scheduler is
65 // already started, switch to the given mode, although some
66 // scheduled tasks from the old mode may still run. If non-NULL,
67 // |callback| will be invoked when the mode has been changed to
68 // |mode|. Takes ownership of |callback|.
69 void Start(Mode mode, const base::Closure& callback);
70
71 // Request that any running syncer task stop as soon as possible and
72 // cancel all scheduled tasks. This function can be called from any thread,
73 // and should in fact be called from a thread that isn't the sync loop to
74 // allow preempting ongoing sync cycles.
75 // Invokes |callback| from the sync loop once syncer is idle and all tasks
76 // are cancelled.
77 void RequestStop(const base::Closure& callback);
78
79 // The meat and potatoes.
80 void ScheduleNudge(const base::TimeDelta& delay, NudgeSource source,
81 syncable::ModelTypeSet types,
82 const tracked_objects::Location& nudge_location);
83 void ScheduleNudgeWithPayloads(
84 const base::TimeDelta& delay, NudgeSource source,
85 const syncable::ModelTypePayloadMap& types_with_payloads,
86 const tracked_objects::Location& nudge_location);
87
88 // Note: The source argument of this function must come from the subset of
89 // GetUpdatesCallerInfo values related to configurations.
90 void ScheduleConfig(
91 syncable::ModelTypeSet types,
92 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source);
93
94 void ScheduleClearUserData();
95 // If this is called before Start(), the cleanup is guaranteed to
96 // happen before the Start finishes.
97 //
98 // TODO(akalin): Figure out how to test this.
99 void ScheduleCleanupDisabledTypes();
100
101 // Change status of notifications in the SyncSessionContext.
102 void set_notifications_enabled(bool notifications_enabled);
103
104 base::TimeDelta sessions_commit_delay() const;
105
106 // DDOS avoidance function. Calculates how long we should wait before trying
107 // again after a failed sync attempt, where the last delay was |base_delay|.
108 // TODO(tim): Look at URLRequestThrottlerEntryInterface.
109 static base::TimeDelta GetRecommendedDelay(const base::TimeDelta& base_delay);
110
111 // Called when credentials are updated by the user.
112 void OnCredentialsUpdated();
113
114 // Called when the network layer detects a connection status change.
115 void OnConnectionStatusChange();
116
117 // SyncSession::Delegate implementation.
118 virtual void OnSilencedUntil(
119 const base::TimeTicks& silenced_until) OVERRIDE;
120 virtual bool IsSyncingCurrentlySilenced() OVERRIDE;
121 virtual void OnReceivedShortPollIntervalUpdate(
122 const base::TimeDelta& new_interval) OVERRIDE;
123 virtual void OnReceivedLongPollIntervalUpdate(
124 const base::TimeDelta& new_interval) OVERRIDE;
125 virtual void OnReceivedSessionsCommitDelay(
126 const base::TimeDelta& new_delay) OVERRIDE;
127 virtual void OnShouldStopSyncingPermanently() OVERRIDE;
128 virtual void OnSyncProtocolError(
129 const sessions::SyncSessionSnapshot& snapshot) OVERRIDE;
130
131 private:
132 enum JobProcessDecision {
133 // Indicates we should continue with the current job.
134 CONTINUE,
135 // Indicates that we should save it to be processed later.
136 SAVE,
137 // Indicates we should drop this job.
138 DROP,
139 };
140
141 struct SyncSessionJob {
142 // An enum used to describe jobs for scheduling purposes.
143 enum SyncSessionJobPurpose {
144 // Uninitialized state, should never be hit in practice.
145 UNKNOWN = -1,
146 // Our poll timer schedules POLL jobs periodically based on a server
147 // assigned poll interval.
148 POLL,
149 // A nudge task can come from a variety of components needing to force
150 // a sync. The source is inferable from |session.source()|.
151 NUDGE,
152 // The user invoked a function in the UI to clear their entire account
153 // and stop syncing (globally).
154 CLEAR_USER_DATA,
155 // Typically used for fetching updates for a subset of the enabled types
156 // during initial sync or reconfiguration. We don't run all steps of
157 // the sync cycle for these (e.g. CleanupDisabledTypes is skipped).
158 CONFIGURATION,
159 // The user disabled some types and we have to clean up the data
160 // for those.
161 CLEANUP_DISABLED_TYPES,
162 };
163 SyncSessionJob();
164 SyncSessionJob(SyncSessionJobPurpose purpose, base::TimeTicks start,
165 linked_ptr<sessions::SyncSession> session, bool is_canary_job,
166 const tracked_objects::Location& nudge_location);
167 ~SyncSessionJob();
168 static const char* GetPurposeString(SyncSessionJobPurpose purpose);
169
170 SyncSessionJobPurpose purpose;
171 base::TimeTicks scheduled_start;
172 linked_ptr<sessions::SyncSession> session;
173 bool is_canary_job;
174
175 // This is the location the job came from. Used for debugging.
176 // In case of multiple nudges getting coalesced this stores the
177 // first location that came in.
178 tracked_objects::Location from_here;
179 };
180 friend class SyncSchedulerTest;
181 friend class SyncSchedulerWhiteboxTest;
182
183 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
184 DropNudgeWhileExponentialBackOff);
185 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, SaveNudge);
186 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
187 SaveNudgeWhileTypeThrottled);
188 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueNudge);
189 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, DropPoll);
190 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinuePoll);
191 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueConfiguration);
192 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
193 SaveConfigurationWhileThrottled);
194 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
195 SaveNudgeWhileThrottled);
196 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
197 ContinueClearUserDataUnderAllCircumstances);
198 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
199 ContinueCanaryJobConfig);
200 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
201 ContinueNudgeWhileExponentialBackOff);
202 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, TransientPollFailure);
203
204 // A component used to get time delays associated with exponential backoff.
205 // Encapsulated into a class to facilitate testing.
206 class DelayProvider {
207 public:
208 DelayProvider();
209 virtual base::TimeDelta GetDelay(const base::TimeDelta& last_delay);
210 virtual ~DelayProvider();
211 private:
212 DISALLOW_COPY_AND_ASSIGN(DelayProvider);
213 };
214
215 struct WaitInterval {
216 enum Mode {
217 // Uninitialized state, should not be set in practice.
218 UNKNOWN = -1,
219 // A wait interval whose duration has been affected by exponential
220 // backoff.
221 // EXPONENTIAL_BACKOFF intervals are nudge-rate limited to 1 per interval.
222 EXPONENTIAL_BACKOFF,
223 // A server-initiated throttled interval. We do not allow any syncing
224 // during such an interval.
225 THROTTLED,
226 };
227 WaitInterval();
228 ~WaitInterval();
229 WaitInterval(Mode mode, base::TimeDelta length);
230
231 static const char* GetModeString(Mode mode);
232
233 Mode mode;
234
235 // This bool is set to true if we have observed a nudge during this
236 // interval and mode == EXPONENTIAL_BACKOFF.
237 bool had_nudge;
238 base::TimeDelta length;
239 base::OneShotTimer<SyncScheduler> timer;
240
241 // Configure jobs are saved only when backing off or throttling. So we
242 // expose the pointer here.
243 scoped_ptr<SyncSessionJob> pending_configure_job;
244 };
245
246 static const char* GetModeString(Mode mode);
247
248 static const char* GetDecisionString(JobProcessDecision decision);
249
250 // Helpers that log before posting to |sync_loop_|. These will only post
251 // the task in between calls to Start/Stop.
252 void PostTask(const tracked_objects::Location& from_here,
253 const char* name,
254 const base::Closure& task);
255 void PostDelayedTask(const tracked_objects::Location& from_here,
256 const char* name,
257 const base::Closure& task,
258 base::TimeDelta delay);
259
260 // Helper to assemble a job and post a delayed task to sync.
261 void ScheduleSyncSessionJob(const SyncSessionJob& job);
262
263 // Invoke the Syncer to perform a sync.
264 void DoSyncSessionJob(const SyncSessionJob& job);
265
266 // Called after the Syncer has performed the sync represented by |job|, to
267 // reset our state.
268 void FinishSyncSessionJob(const SyncSessionJob& job);
269
270 // Record important state that might be needed in future syncs, such as which
271 // data types may require cleanup.
272 void UpdateCarryoverSessionState(const SyncSessionJob& old_job);
273
274 // Helper to FinishSyncSessionJob to schedule the next sync operation.
275 void ScheduleNextSync(const SyncSessionJob& old_job);
276
277 // Helper to configure polling intervals. Used by Start and ScheduleNextSync.
278 void AdjustPolling(const SyncSessionJob* old_job);
279
280 // Helper to restart waiting with |wait_interval_|'s timer.
281 void RestartWaiting();
282
283 // Helper to ScheduleNextSync in case of consecutive sync errors.
284 void HandleContinuationError(const SyncSessionJob& old_job);
285
286 // Determines if it is legal to run |job| by checking current
287 // operational mode, backoff or throttling, freshness
288 // (so we don't make redundant syncs), and connection.
289 bool ShouldRunJob(const SyncSessionJob& job);
290
291 // Decide whether we should CONTINUE, SAVE or DROP the job.
292 JobProcessDecision DecideOnJob(const SyncSessionJob& job);
293
294 // Decide on whether to CONTINUE, SAVE or DROP the job when we are in
295 // backoff mode.
296 JobProcessDecision DecideWhileInWaitInterval(const SyncSessionJob& job);
297
298 // Saves the job for future execution. Note: It drops all the poll jobs.
299 void SaveJob(const SyncSessionJob& job);
300
301 // Coalesces the current job with the pending nudge.
302 void InitOrCoalescePendingJob(const SyncSessionJob& job);
303
304 // 'Impl' here refers to real implementation of public functions, running on
305 // |thread_|.
306 void StartImpl(Mode mode, const base::Closure& callback);
307 void StopImpl(const base::Closure& callback);
308 void ScheduleNudgeImpl(
309 const base::TimeDelta& delay,
310 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
311 const syncable::ModelTypePayloadMap& types_with_payloads,
312 bool is_canary_job, const tracked_objects::Location& nudge_location);
313 void ScheduleConfigImpl(const ModelSafeRoutingInfo& routing_info,
314 const std::vector<ModelSafeWorker*>& workers,
315 const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source);
316 void ScheduleClearUserDataImpl();
317
318 // Returns true if the client is currently in exponential backoff.
319 bool IsBackingOff() const;
320
321 // Helper to signal all listeners registered with |session_context_|.
322 void Notify(SyncEngineEvent::EventCause cause);
323
324 // Callback to change backoff state.
325 void DoCanaryJob();
326 void Unthrottle();
327
328 // Executes the pending job. Called whenever an event occurs that may
329 // change conditions permitting a job to run. Like when network connection is
330 // re-established, mode changes etc.
331 void DoPendingJobIfPossible(bool is_canary_job);
332
333 // Called when the root cause of the current connection error is fixed.
334 void OnServerConnectionErrorFixed();
335
336 // The pointer is owned by the caller.
337 browser_sync::sessions::SyncSession* CreateSyncSession(
338 const browser_sync::sessions::SyncSourceInfo& info);
339
340 // Creates a session for a poll and performs the sync.
341 void PollTimerCallback();
342
343 // Assign |start| and |end| to appropriate SyncerStep values for the
344 // specified |purpose|.
345 void SetSyncerStepsForPurpose(SyncSessionJob::SyncSessionJobPurpose purpose,
346 SyncerStep* start,
347 SyncerStep* end);
348
349 // Used to update |server_connection_ok_|, see below.
350 void UpdateServerConnectionManagerStatus(
351 HttpResponse::ServerConnectionCode code);
352
353 // Called once the first time thread_ is started to broadcast an initial
354 // session snapshot containing data like initial_sync_ended. Important when
355 // the client starts up and does not need to perform an initial sync.
356 void SendInitialSnapshot();
357
358 virtual void OnActionableError(const sessions::SyncSessionSnapshot& snapshot);
359
360 base::WeakPtrFactory<SyncScheduler> weak_ptr_factory_;
361
362 // A second factory specially for weak_handle_this_, to allow the handle
363 // to be const and alleviate threading concerns.
364 base::WeakPtrFactory<SyncScheduler> weak_ptr_factory_for_weak_handle_;
365
366 // For certain methods that need to worry about X-thread posting.
367 const WeakHandle<SyncScheduler> weak_handle_this_;
368
369 // Used for logging.
370 const std::string name_;
371
372 // The message loop this object is on. Almost all methods have to
373 // be called on this thread.
374 MessageLoop* const sync_loop_;
375
376 // Set in Start(), unset in Stop().
377 bool started_;
378
379 // Modifiable versions of kDefaultLongPollIntervalSeconds which can be
380 // updated by the server.
381 base::TimeDelta syncer_short_poll_interval_seconds_;
382 base::TimeDelta syncer_long_poll_interval_seconds_;
383
384 // Server-tweakable sessions commit delay.
385 base::TimeDelta sessions_commit_delay_;
386
387 // Periodic timer for polling. See AdjustPolling.
388 base::RepeatingTimer<SyncScheduler> poll_timer_;
389
390 // The mode of operation.
391 Mode mode_;
392
393 // TODO(tim): Bug 26339. This needs to track more than just time I think,
394 // since the nudges could be for different types. Current impl doesn't care.
395 base::TimeTicks last_sync_session_end_time_;
396
397 // Have we observed a valid server connection?
398 bool server_connection_ok_;
399
400 // The latest connection code we got while trying to connect.
401 HttpResponse::ServerConnectionCode connection_code_;
402
403 // Tracks in-flight nudges so we can coalesce.
404 scoped_ptr<SyncSessionJob> pending_nudge_;
405
406 // Current wait state. Null if we're not in backoff and not throttled.
407 scoped_ptr<WaitInterval> wait_interval_;
408
409 scoped_ptr<DelayProvider> delay_provider_;
410
411 // Invoked to run through the sync cycle.
412 scoped_ptr<Syncer> syncer_;
413
414 scoped_ptr<sessions::SyncSessionContext> session_context_;
415
416 DISALLOW_COPY_AND_ASSIGN(SyncScheduler);
417 };
418
419 } // namespace browser_sync
420
421 #endif // CHROME_BROWSER_SYNC_ENGINE_SYNC_SCHEDULER_H_
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/store_timestamps_command.cc ('k') | chrome/browser/sync/engine/sync_scheduler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698