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_
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"
34 class BackoffDelayProvider
;
37 struct ModelNeutralState
;
40 class SYNC_EXPORT_PRIVATE SyncSchedulerImpl
41 : public SyncScheduler
,
42 public base::NonThreadSafe
{
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
,
52 virtual ~SyncSchedulerImpl();
54 virtual void Start(Mode mode
) OVERRIDE
;
55 virtual bool ScheduleConfiguration(
56 const ConfigurationParams
& params
) OVERRIDE
;
57 virtual void Stop() OVERRIDE
;
58 virtual void ScheduleLocalNudge(
59 const base::TimeDelta
& desired_delay
,
61 const tracked_objects::Location
& nudge_location
) OVERRIDE
;
62 virtual void ScheduleLocalRefreshRequest(
63 const base::TimeDelta
& desired_delay
,
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(
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 OnShouldStopSyncingPermanently() OVERRIDE
;
91 virtual void OnSyncProtocolError(
92 const sessions::SyncSessionSnapshot
& snapshot
) OVERRIDE
;
96 // Non-canary jobs respect exponential backoff.
98 // Canary jobs bypass exponential backoff, so use with extreme caution.
102 enum PollAdjustType
{
103 // Restart the poll interval.
105 // Restart the poll interval only if its length has changed.
109 friend class SyncSchedulerTest
;
110 friend class SyncSchedulerWhiteboxTest
;
111 friend class SyncerTest
;
113 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
, NoNudgesInConfigureMode
);
114 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
,
115 DropNudgeWhileExponentialBackOff
);
116 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
, SaveNudge
);
117 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
,
118 SaveNudgeWhileTypeThrottled
);
119 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
, ContinueNudge
);
120 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
, ContinueConfiguration
);
121 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
,
122 SaveConfigurationWhileThrottled
);
123 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
,
124 SaveNudgeWhileThrottled
);
125 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest
,
126 ContinueCanaryJobConfig
);
127 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
, TransientPollFailure
);
128 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
,
129 ServerConnectionChangeDuringBackoff
);
130 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
,
131 ConnectionChangeCanaryPreemptedByNudge
);
132 FRIEND_TEST_ALL_PREFIXES(BackoffTriggersSyncSchedulerTest
,
133 FailGetEncryptionKey
);
135 struct SYNC_EXPORT_PRIVATE WaitInterval
{
137 // Uninitialized state, should not be set in practice.
139 // We enter a series of increasingly longer WaitIntervals if we experience
140 // repeated transient failures. We retry at the end of each interval.
142 // A server-initiated throttled interval. We do not allow any syncing
143 // during such an interval.
148 WaitInterval(Mode mode
, base::TimeDelta length
);
150 static const char* GetModeString(Mode mode
);
153 base::TimeDelta length
;
156 static const char* GetModeString(Mode mode
);
158 // Invoke the syncer to perform a nudge job.
159 void DoNudgeSyncSessionJob(JobPriority priority
);
161 // Invoke the syncer to perform a configuration job.
162 bool DoConfigurationSyncSessionJob(JobPriority priority
);
164 // Helper function for Do{Nudge,Configuration}SyncSessionJob.
166 const sessions::ModelNeutralState
& model_neutral_state
);
168 // Invoke the Syncer to perform a poll job.
169 void DoPollSyncSessionJob();
171 // Adjusts the poll timer to account for new poll interval, and possibly
172 // resets the poll interval, depedning on the flag's value.
173 void AdjustPolling(PollAdjustType type
);
175 // Helper to restart waiting with |wait_interval_|'s timer.
176 void RestartWaiting();
178 // Determines if we're allowed to contact the server right now.
179 bool CanRunJobNow(JobPriority priority
);
181 // Determines if we're allowed to contact the server right now.
182 bool CanRunNudgeJobNow(JobPriority priority
);
184 // If the scheduler's current state supports it, this will create a job based
185 // on the passed in parameters and coalesce it with any other pending jobs,
186 // then post a delayed task to run it. It may also choose to drop the job or
187 // save it for later, depending on the scheduler's current state.
188 void ScheduleNudgeImpl(
189 const base::TimeDelta
& delay
,
190 const tracked_objects::Location
& nudge_location
);
192 // Returns true if the client is currently in exponential backoff.
193 bool IsBackingOff() const;
195 // Helper to signal all listeners registered with |session_context_|.
196 void Notify(SyncEngineEvent::EventCause cause
);
198 // Helper to signal listeners about changed retry time.
199 void NotifyRetryTime(base::Time retry_time
);
201 // Helper to signal listeners about changed throttled types.
202 void NotifyThrottledTypesChanged(ModelTypeSet types
);
204 // Looks for pending work and, if it finds any, run this work at "canary"
208 // Transitions out of the THROTTLED WaitInterval then calls TryCanaryJob().
211 // Called when a per-type throttling interval expires.
212 void TypeUnthrottle(base::TimeTicks unthrottle_time
);
214 // Runs a normal nudge job when the scheduled timer expires.
215 void PerformDelayedNudge();
217 // Attempts to exit EXPONENTIAL_BACKOFF by calling TryCanaryJob().
218 void ExponentialBackoffRetry();
220 // Called when the root cause of the current connection error is fixed.
221 void OnServerConnectionErrorFixed();
223 // Creates a session for a poll and performs the sync.
224 void PollTimerCallback();
226 // Returns the set of types that are enabled and not currently throttled.
227 ModelTypeSet
GetEnabledAndUnthrottledTypes();
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();
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
);
240 virtual void OnActionableError(const sessions::SyncSessionSnapshot
& snapshot
);
242 // For certain methods that need to worry about X-thread posting.
243 WeakHandle
<SyncSchedulerImpl
> weak_handle_this_
;
246 const std::string name_
;
248 // Set in Start(), unset in Stop().
251 // Modifiable versions of kDefaultLongPollIntervalSeconds which can be
252 // updated by the server.
253 base::TimeDelta syncer_short_poll_interval_seconds_
;
254 base::TimeDelta syncer_long_poll_interval_seconds_
;
256 // Server-tweakable sessions commit delay.
257 base::TimeDelta sessions_commit_delay_
;
259 // Periodic timer for polling. See AdjustPolling.
260 base::RepeatingTimer
<SyncSchedulerImpl
> poll_timer_
;
262 // The mode of operation.
265 // Current wait state. Null if we're not in backoff and not throttled.
266 scoped_ptr
<WaitInterval
> wait_interval_
;
268 scoped_ptr
<BackoffDelayProvider
> delay_provider_
;
270 // The event that will wake us up.
271 base::OneShotTimer
<SyncSchedulerImpl
> pending_wakeup_timer_
;
273 // An event that fires when data type throttling expires.
274 base::OneShotTimer
<SyncSchedulerImpl
> type_unthrottle_timer_
;
276 // Storage for variables related to an in-progress configure request. Note
277 // that (mode_ != CONFIGURATION_MODE) \implies !pending_configure_params_.
278 scoped_ptr
<ConfigurationParams
> pending_configure_params_
;
280 // If we have a nudge pending to run soon, it will be listed here.
281 base::TimeTicks scheduled_nudge_time_
;
283 // Keeps track of work that the syncer needs to handle.
284 sessions::NudgeTracker nudge_tracker_
;
286 // Invoked to run through the sync cycle.
287 scoped_ptr
<Syncer
> syncer_
;
289 sessions::SyncSessionContext
* session_context_
;
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_
;
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_
;
304 // crbug/251307. This is a workaround for M29. crbug/259913 tracks proper fix
306 // The issue is that poll job runs after few hours of inactivity and therefore
307 // will always fail with auth error because of expired access token. Once
308 // fresh access token is requested poll job is not retried.
309 // The change is to remember that poll timer just fired and retry poll job
310 // after credentials are updated.
311 bool do_poll_after_credentials_updated_
;
313 base::WeakPtrFactory
<SyncSchedulerImpl
> weak_ptr_factory_
;
315 // A second factory specially for weak_handle_this_, to allow the handle
316 // to be const and alleviate threading concerns.
317 base::WeakPtrFactory
<SyncSchedulerImpl
> weak_ptr_factory_for_weak_handle_
;
319 DISALLOW_COPY_AND_ASSIGN(SyncSchedulerImpl
);
322 } // namespace syncer
324 #endif // SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_