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 ~SyncSchedulerImpl() override
;
54 void Start(Mode mode
, base::Time last_poll_time
) override
;
55 void ScheduleConfiguration(const ConfigurationParams
& params
) override
;
57 void ScheduleLocalNudge(
59 const tracked_objects::Location
& nudge_location
) override
;
60 void ScheduleLocalRefreshRequest(
62 const tracked_objects::Location
& nudge_location
) override
;
63 void ScheduleInvalidationNudge(
64 syncer::ModelType type
,
65 scoped_ptr
<InvalidationInterface
> invalidation
,
66 const tracked_objects::Location
& nudge_location
) override
;
67 void ScheduleInitialSyncNudge(syncer::ModelType model_type
) override
;
68 void SetNotificationsEnabled(bool notifications_enabled
) override
;
70 void OnCredentialsUpdated() override
;
71 void OnConnectionStatusChange() override
;
73 // SyncSession::Delegate implementation.
74 void OnThrottled(const base::TimeDelta
& throttle_duration
) override
;
75 void OnTypesThrottled(ModelTypeSet types
,
76 const base::TimeDelta
& throttle_duration
) override
;
77 bool IsCurrentlyThrottled() override
;
78 void OnReceivedShortPollIntervalUpdate(
79 const base::TimeDelta
& new_interval
) override
;
80 void OnReceivedLongPollIntervalUpdate(
81 const base::TimeDelta
& new_interval
) override
;
82 void OnReceivedCustomNudgeDelays(
83 const std::map
<ModelType
, base::TimeDelta
>& nudge_delays
) override
;
84 void OnReceivedClientInvalidationHintBufferSize(int size
) override
;
85 void OnSyncProtocolError(
86 const SyncProtocolError
& sync_protocol_error
) override
;
87 void OnReceivedGuRetryDelay(const base::TimeDelta
& delay
) override
;
88 void OnReceivedMigrationRequest(syncer::ModelTypeSet types
) override
;
90 // Returns true if the client is currently in exponential backoff.
91 bool IsBackingOff() const;
95 // Non-canary jobs respect exponential backoff.
97 // Canary jobs bypass exponential backoff, so use with extreme caution.
101 enum PollAdjustType
{
102 // Restart the poll interval.
104 // Restart the poll interval only if its length has changed.
108 friend class SyncSchedulerTest
;
109 friend class SyncSchedulerWhiteboxTest
;
110 friend class SyncerTest
;
112 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
, TransientPollFailure
);
113 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
,
114 ServerConnectionChangeDuringBackoff
);
115 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
,
116 ConnectionChangeCanaryPreemptedByNudge
);
117 FRIEND_TEST_ALL_PREFIXES(BackoffTriggersSyncSchedulerTest
,
118 FailGetEncryptionKey
);
119 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
, SuccessfulRetry
);
120 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
, FailedRetry
);
121 FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest
, ReceiveNewRetryDelay
);
123 struct SYNC_EXPORT_PRIVATE WaitInterval
{
125 // Uninitialized state, should not be set in practice.
127 // We enter a series of increasingly longer WaitIntervals if we experience
128 // repeated transient failures. We retry at the end of each interval.
130 // A server-initiated throttled interval. We do not allow any syncing
131 // during such an interval.
136 WaitInterval(Mode mode
, base::TimeDelta length
);
138 static const char* GetModeString(Mode mode
);
141 base::TimeDelta length
;
144 static const char* GetModeString(Mode mode
);
146 void SetDefaultNudgeDelay(base::TimeDelta delay_ms
);
148 // Invoke the syncer to perform a nudge job.
149 void DoNudgeSyncSessionJob(JobPriority priority
);
151 // Invoke the syncer to perform a configuration job.
152 void DoConfigurationSyncSessionJob(JobPriority priority
);
154 // Helper function for Do{Nudge,Configuration,Poll}SyncSessionJob.
155 void HandleSuccess();
157 // Helper function for Do{Nudge,Configuration,Poll}SyncSessionJob.
159 const sessions::ModelNeutralState
& model_neutral_state
);
161 // Invoke the Syncer to perform a poll job.
162 void DoPollSyncSessionJob();
164 // Helper function to calculate poll interval.
165 base::TimeDelta
GetPollInterval();
167 // Adjusts the poll timer to account for new poll interval, and possibly
168 // resets the poll interval, depedning on the flag's value.
169 void AdjustPolling(PollAdjustType type
);
171 // Helper to restart waiting with |wait_interval_|'s timer.
172 void RestartWaiting();
174 // Determines if we're allowed to contact the server right now.
175 bool CanRunJobNow(JobPriority priority
);
177 // Determines if we're allowed to contact the server right now.
178 bool CanRunNudgeJobNow(JobPriority priority
);
180 // If the scheduler's current state supports it, this will create a job based
181 // on the passed in parameters and coalesce it with any other pending jobs,
182 // then post a delayed task to run it. It may also choose to drop the job or
183 // save it for later, depending on the scheduler's current state.
184 void ScheduleNudgeImpl(
185 const base::TimeDelta
& delay
,
186 const tracked_objects::Location
& nudge_location
);
188 // Helper to signal listeners about changed retry time.
189 void NotifyRetryTime(base::Time retry_time
);
191 // Helper to signal listeners about changed throttled types.
192 void NotifyThrottledTypesChanged(ModelTypeSet types
);
194 // Looks for pending work and, if it finds any, run this work at "canary"
198 // At the moment TrySyncSessionJob just posts call to TrySyncSessionJobImpl on
199 // current thread. In the future it will request access token here.
200 void TrySyncSessionJob();
201 void TrySyncSessionJobImpl();
203 // Transitions out of the THROTTLED WaitInterval then calls TryCanaryJob().
206 // Called when a per-type throttling interval expires.
207 void TypeUnthrottle(base::TimeTicks unthrottle_time
);
209 // Runs a normal nudge job when the scheduled timer expires.
210 void PerformDelayedNudge();
212 // Attempts to exit EXPONENTIAL_BACKOFF by calling TryCanaryJob().
213 void ExponentialBackoffRetry();
215 // Called when the root cause of the current connection error is fixed.
216 void OnServerConnectionErrorFixed();
218 // Creates a session for a poll and performs the sync.
219 void PollTimerCallback();
221 // Creates a session for a retry and performs the sync.
222 void RetryTimerCallback();
224 // Returns the set of types that are enabled and not currently throttled.
225 ModelTypeSet
GetEnabledAndUnthrottledTypes();
227 // Called as we are started to broadcast an initial session snapshot
228 // containing data like initial_sync_ended. Important when the client starts
229 // up and does not need to perform an initial sync.
230 void SendInitialSnapshot();
232 // This is used for histogramming and analysis of ScheduleNudge* APIs.
233 // SyncScheduler is the ultimate choke-point for all such invocations (with
234 // and without InvalidationState variants, all NudgeSources, etc) and as such
235 // is the most flexible place to do this bookkeeping.
236 void UpdateNudgeTimeRecords(ModelTypeSet types
);
238 // For certain methods that need to worry about X-thread posting.
239 WeakHandle
<SyncSchedulerImpl
> weak_handle_this_
;
242 const std::string name_
;
244 // Set in Start(), unset in Stop().
247 // Modifiable versions of kDefaultLongPollIntervalSeconds which can be
248 // updated by the server.
249 base::TimeDelta syncer_short_poll_interval_seconds_
;
250 base::TimeDelta syncer_long_poll_interval_seconds_
;
252 // Timer for polling. Restarted on each successful poll, and when entering
253 // normal sync mode or exiting an error state. Not active in configuration
255 base::OneShotTimer
<SyncSchedulerImpl
> poll_timer_
;
257 // The mode of operation.
260 // Current wait state. Null if we're not in backoff and not throttled.
261 scoped_ptr
<WaitInterval
> wait_interval_
;
263 scoped_ptr
<BackoffDelayProvider
> delay_provider_
;
265 // The event that will wake us up.
266 base::OneShotTimer
<SyncSchedulerImpl
> pending_wakeup_timer_
;
268 // An event that fires when data type throttling expires.
269 base::OneShotTimer
<SyncSchedulerImpl
> type_unthrottle_timer_
;
271 // Storage for variables related to an in-progress configure request. Note
272 // that (mode_ != CONFIGURATION_MODE) \implies !pending_configure_params_.
273 scoped_ptr
<ConfigurationParams
> pending_configure_params_
;
275 // If we have a nudge pending to run soon, it will be listed here.
276 base::TimeTicks scheduled_nudge_time_
;
278 // Keeps track of work that the syncer needs to handle.
279 sessions::NudgeTracker nudge_tracker_
;
281 // Invoked to run through the sync cycle.
282 scoped_ptr
<Syncer
> syncer_
;
284 sessions::SyncSessionContext
* session_context_
;
286 // A map tracking LOCAL NudgeSource invocations of ScheduleNudge* APIs,
287 // organized by datatype. Each datatype that was part of the types requested
288 // in the call will have its TimeTicks value updated.
289 typedef std::map
<ModelType
, base::TimeTicks
> ModelTypeTimeMap
;
290 ModelTypeTimeMap last_local_nudges_by_model_type_
;
292 // Used as an "anti-reentrancy defensive assertion".
293 // While true, it is illegal for any new scheduling activity to take place.
294 // Ensures that higher layers don't break this law in response to events that
295 // take place during a sync cycle. We call this out because such violations
296 // could result in tight sync loops hitting sync servers.
297 bool no_scheduling_allowed_
;
299 // TryJob might get called for multiple reasons. It should only call
300 // DoPollSyncSessionJob after some time since the last attempt.
301 // last_poll_reset_ keeps track of when was last attempt.
302 base::TimeTicks last_poll_reset_
;
304 // next_sync_session_job_priority_ defines which priority will be used next
305 // time TrySyncSessionJobImpl is called. CANARY_PRIORITY allows syncer to run
306 // even if scheduler is in exponential backoff. This is needed for events that
307 // have chance of resolving previous error (e.g. network connection change
308 // after NETWORK_UNAVAILABLE error).
309 // It is reset back to NORMAL_PRIORITY on every call to TrySyncSessionJobImpl.
310 JobPriority next_sync_session_job_priority_
;
312 // One-shot timer for scheduling GU retry according to delay set by server.
313 base::OneShotTimer
<SyncSchedulerImpl
> retry_timer_
;
315 base::WeakPtrFactory
<SyncSchedulerImpl
> weak_ptr_factory_
;
317 // A second factory specially for weak_handle_this_, to allow the handle
318 // to be const and alleviate threading concerns.
319 base::WeakPtrFactory
<SyncSchedulerImpl
> weak_ptr_factory_for_weak_handle_
;
321 DISALLOW_COPY_AND_ASSIGN(SyncSchedulerImpl
);
324 } // namespace syncer
326 #endif // SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_