| 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 |