| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 run the syncer on a thread. | |
| 6 #ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD2_H_ | |
| 7 #define CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD2_H_ | |
| 8 #pragma once | |
| 9 | |
| 10 #include "base/callback.h" | |
| 11 #include "base/memory/linked_ptr.h" | |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "base/observer_list.h" | |
| 14 #include "base/task.h" | |
| 15 #include "base/threading/thread.h" | |
| 16 #include "base/time.h" | |
| 17 #include "base/timer.h" | |
| 18 #include "chrome/browser/sync/engine/nudge_source.h" | |
| 19 #include "chrome/browser/sync/engine/polling_constants.h" | |
| 20 #include "chrome/browser/sync/engine/syncer.h" | |
| 21 #include "chrome/browser/sync/syncable/model_type_payload_map.h" | |
| 22 #include "chrome/browser/sync/engine/net/server_connection_manager.h" | |
| 23 #include "chrome/browser/sync/sessions/sync_session.h" | |
| 24 #include "chrome/browser/sync/sessions/sync_session_context.h" | |
| 25 | |
| 26 namespace browser_sync { | |
| 27 | |
| 28 struct ServerConnectionEvent; | |
| 29 | |
| 30 namespace s3 { | |
| 31 | |
| 32 class SyncerThread : public sessions::SyncSession::Delegate, | |
| 33 public ServerConnectionEventListener { | |
| 34 public: | |
| 35 enum Mode { | |
| 36 // In this mode, the thread only performs configuration tasks. This is | |
| 37 // designed to make the case where we want to download updates for a | |
| 38 // specific type only, and not continue syncing until we are moved into | |
| 39 // normal mode. | |
| 40 CONFIGURATION_MODE, | |
| 41 // Resumes polling and allows nudges, drops configuration tasks. Runs | |
| 42 // through entire sync cycle. | |
| 43 NORMAL_MODE, | |
| 44 }; | |
| 45 | |
| 46 // Takes ownership of both |context| and |syncer|. | |
| 47 SyncerThread(sessions::SyncSessionContext* context, Syncer* syncer); | |
| 48 virtual ~SyncerThread(); | |
| 49 | |
| 50 typedef Callback0::Type ModeChangeCallback; | |
| 51 | |
| 52 // Change the mode of operation. | |
| 53 // We don't use a lock when changing modes, so we won't cause currently | |
| 54 // scheduled jobs to adhere to the new mode. We could protect it, but it | |
| 55 // doesn't buy very much as a) a session could already be in progress and it | |
| 56 // will continue no matter what, b) the scheduled sessions already contain | |
| 57 // all their required state and won't be affected by potential change at | |
| 58 // higher levels (i.e. the registrar), and c) we service tasks FIFO, so once | |
| 59 // the mode changes all future jobs will be run against the updated mode. | |
| 60 // If supplied, |callback| will be invoked when the mode has been | |
| 61 // changed to |mode| *from the SyncerThread*, and not from the caller | |
| 62 // thread. | |
| 63 void Start(Mode mode, ModeChangeCallback* callback); | |
| 64 | |
| 65 // Joins on the thread as soon as possible (currently running session | |
| 66 // completes). | |
| 67 void Stop(); | |
| 68 | |
| 69 // The meat and potatoes. | |
| 70 void ScheduleNudge(const base::TimeDelta& delay, NudgeSource source, | |
| 71 const syncable::ModelTypeBitSet& types, | |
| 72 const tracked_objects::Location& nudge_location); | |
| 73 void ScheduleNudgeWithPayloads( | |
| 74 const base::TimeDelta& delay, NudgeSource source, | |
| 75 const syncable::ModelTypePayloadMap& types_with_payloads, | |
| 76 const tracked_objects::Location& nudge_location); | |
| 77 void ScheduleConfig(const syncable::ModelTypeBitSet& types); | |
| 78 void ScheduleClearUserData(); | |
| 79 | |
| 80 // Change status of notifications in the SyncSessionContext. | |
| 81 void set_notifications_enabled(bool notifications_enabled); | |
| 82 | |
| 83 // DDOS avoidance function. Calculates how long we should wait before trying | |
| 84 // again after a failed sync attempt, where the last delay was |base_delay|. | |
| 85 // TODO(tim): Look at URLRequestThrottlerEntryInterface. | |
| 86 static base::TimeDelta GetRecommendedDelay(const base::TimeDelta& base_delay); | |
| 87 | |
| 88 // SyncSession::Delegate implementation. | |
| 89 virtual void OnSilencedUntil(const base::TimeTicks& silenced_until); | |
| 90 virtual bool IsSyncingCurrentlySilenced(); | |
| 91 virtual void OnReceivedShortPollIntervalUpdate( | |
| 92 const base::TimeDelta& new_interval); | |
| 93 virtual void OnReceivedLongPollIntervalUpdate( | |
| 94 const base::TimeDelta& new_interval); | |
| 95 virtual void OnShouldStopSyncingPermanently(); | |
| 96 | |
| 97 // ServerConnectionEventListener implementation. | |
| 98 // TODO(tim): schedule a nudge when valid connection detected? in 1 minute? | |
| 99 virtual void OnServerConnectionEvent(const ServerConnectionEvent2& event); | |
| 100 | |
| 101 private: | |
| 102 enum JobProcessDecision { | |
| 103 // Indicates we should continue with the current job. | |
| 104 CONTINUE, | |
| 105 // Indicates that we should save it to be processed later. | |
| 106 SAVE, | |
| 107 // Indicates we should drop this job. | |
| 108 DROP, | |
| 109 }; | |
| 110 | |
| 111 struct SyncSessionJob { | |
| 112 // An enum used to describe jobs for scheduling purposes. | |
| 113 enum SyncSessionJobPurpose { | |
| 114 // Our poll timer schedules POLL jobs periodically based on a server | |
| 115 // assigned poll interval. | |
| 116 POLL, | |
| 117 // A nudge task can come from a variety of components needing to force | |
| 118 // a sync. The source is inferable from |session.source()|. | |
| 119 NUDGE, | |
| 120 // The user invoked a function in the UI to clear their entire account | |
| 121 // and stop syncing (globally). | |
| 122 CLEAR_USER_DATA, | |
| 123 // Typically used for fetching updates for a subset of the enabled types | |
| 124 // during initial sync or reconfiguration. We don't run all steps of | |
| 125 // the sync cycle for these (e.g. CleanupDisabledTypes is skipped). | |
| 126 CONFIGURATION, | |
| 127 }; | |
| 128 SyncSessionJob(); | |
| 129 SyncSessionJob(SyncSessionJobPurpose purpose, base::TimeTicks start, | |
| 130 linked_ptr<sessions::SyncSession> session, bool is_canary_job, | |
| 131 const tracked_objects::Location& nudge_location); | |
| 132 ~SyncSessionJob(); | |
| 133 SyncSessionJobPurpose purpose; | |
| 134 base::TimeTicks scheduled_start; | |
| 135 linked_ptr<sessions::SyncSession> session; | |
| 136 bool is_canary_job; | |
| 137 | |
| 138 // This is the location the nudge came from. used for debugging purpose. | |
| 139 // In case of multiple nudges getting coalesced this stores the first nudge | |
| 140 // that came in. | |
| 141 tracked_objects::Location nudge_location; | |
| 142 }; | |
| 143 friend class SyncerThread2Test; | |
| 144 friend class SyncerThread2WhiteboxTest; | |
| 145 | |
| 146 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, | |
| 147 DropNudgeWhileExponentialBackOff); | |
| 148 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, SaveNudge); | |
| 149 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, ContinueNudge); | |
| 150 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, DropPoll); | |
| 151 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, ContinuePoll); | |
| 152 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, ContinueConfiguration); | |
| 153 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, | |
| 154 SaveConfigurationWhileThrottled); | |
| 155 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, | |
| 156 SaveNudgeWhileThrottled); | |
| 157 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, | |
| 158 ContinueClearUserDataUnderAllCircumstances); | |
| 159 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, | |
| 160 ContinueCanaryJobConfig); | |
| 161 FRIEND_TEST_ALL_PREFIXES(SyncerThread2WhiteboxTest, | |
| 162 ContinueNudgeWhileExponentialBackOff); | |
| 163 | |
| 164 // A component used to get time delays associated with exponential backoff. | |
| 165 // Encapsulated into a class to facilitate testing. | |
| 166 class DelayProvider { | |
| 167 public: | |
| 168 DelayProvider(); | |
| 169 virtual base::TimeDelta GetDelay(const base::TimeDelta& last_delay); | |
| 170 virtual ~DelayProvider(); | |
| 171 private: | |
| 172 DISALLOW_COPY_AND_ASSIGN(DelayProvider); | |
| 173 }; | |
| 174 | |
| 175 struct WaitInterval { | |
| 176 enum Mode { | |
| 177 // A wait interval whose duration has been affected by exponential | |
| 178 // backoff. | |
| 179 // EXPONENTIAL_BACKOFF intervals are nudge-rate limited to 1 per interval. | |
| 180 EXPONENTIAL_BACKOFF, | |
| 181 // A server-initiated throttled interval. We do not allow any syncing | |
| 182 // during such an interval. | |
| 183 THROTTLED, | |
| 184 }; | |
| 185 WaitInterval(); | |
| 186 ~WaitInterval(); | |
| 187 | |
| 188 Mode mode; | |
| 189 | |
| 190 // This bool is set to true if we have observed a nudge during this | |
| 191 // interval and mode == EXPONENTIAL_BACKOFF. | |
| 192 bool had_nudge; | |
| 193 base::TimeDelta length; | |
| 194 base::OneShotTimer<SyncerThread> timer; | |
| 195 | |
| 196 // Configure jobs are saved only when backing off or throttling. So we | |
| 197 // expose the pointer here. | |
| 198 scoped_ptr<SyncSessionJob> pending_configure_job; | |
| 199 WaitInterval(Mode mode, base::TimeDelta length); | |
| 200 }; | |
| 201 | |
| 202 // Helper to assemble a job and post a delayed task to sync. | |
| 203 void ScheduleSyncSessionJob( | |
| 204 const base::TimeDelta& delay, | |
| 205 SyncSessionJob::SyncSessionJobPurpose purpose, | |
| 206 sessions::SyncSession* session, | |
| 207 const tracked_objects::Location& nudge_location); | |
| 208 | |
| 209 // Invoke the Syncer to perform a sync. | |
| 210 void DoSyncSessionJob(const SyncSessionJob& job); | |
| 211 | |
| 212 // Called after the Syncer has performed the sync represented by |job|, to | |
| 213 // reset our state. | |
| 214 void FinishSyncSessionJob(const SyncSessionJob& job); | |
| 215 | |
| 216 // Record important state that might be needed in future syncs, such as which | |
| 217 // data types may require cleanup. | |
| 218 void UpdateCarryoverSessionState(const SyncSessionJob& old_job); | |
| 219 | |
| 220 // Helper to FinishSyncSessionJob to schedule the next sync operation. | |
| 221 void ScheduleNextSync(const SyncSessionJob& old_job); | |
| 222 | |
| 223 // Helper to configure polling intervals. Used by Start and ScheduleNextSync. | |
| 224 void AdjustPolling(const SyncSessionJob* old_job); | |
| 225 | |
| 226 // Helper to ScheduleNextSync in case of consecutive sync errors. | |
| 227 void HandleConsecutiveContinuationError(const SyncSessionJob& old_job); | |
| 228 | |
| 229 // Determines if it is legal to run |job| by checking current | |
| 230 // operational mode, backoff or throttling, freshness | |
| 231 // (so we don't make redundant syncs), and connection. | |
| 232 bool ShouldRunJob(const SyncSessionJob& job); | |
| 233 | |
| 234 // Decide whether we should CONTINUE, SAVE or DROP the job. | |
| 235 JobProcessDecision DecideOnJob(const SyncSessionJob& job); | |
| 236 | |
| 237 // Decide on whether to CONTINUE, SAVE or DROP the job when we are in | |
| 238 // backoff mode. | |
| 239 JobProcessDecision DecideWhileInWaitInterval(const SyncSessionJob& job); | |
| 240 | |
| 241 // Saves the job for future execution. Note: It drops all the poll jobs. | |
| 242 void SaveJob(const SyncSessionJob& job); | |
| 243 | |
| 244 // Coalesces the current job with the pending nudge. | |
| 245 void InitOrCoalescePendingJob(const SyncSessionJob& job); | |
| 246 | |
| 247 // 'Impl' here refers to real implementation of public functions, running on | |
| 248 // |thread_|. | |
| 249 void StartImpl(Mode mode, linked_ptr<ModeChangeCallback> callback); | |
| 250 void ScheduleNudgeImpl( | |
| 251 const base::TimeDelta& delay, | |
| 252 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, | |
| 253 const syncable::ModelTypePayloadMap& types_with_payloads, | |
| 254 bool is_canary_job, const tracked_objects::Location& nudge_location); | |
| 255 void ScheduleConfigImpl(const ModelSafeRoutingInfo& routing_info, | |
| 256 const std::vector<ModelSafeWorker*>& workers, | |
| 257 const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source); | |
| 258 void ScheduleClearUserDataImpl(); | |
| 259 | |
| 260 // Returns true if the client is currently in exponential backoff. | |
| 261 bool IsBackingOff() const; | |
| 262 | |
| 263 // Helper to signal all listeners registered with |session_context_|. | |
| 264 void Notify(SyncEngineEvent::EventCause cause); | |
| 265 | |
| 266 // Callback to change backoff state. | |
| 267 void DoCanaryJob(); | |
| 268 void Unthrottle(); | |
| 269 | |
| 270 // Executes the pending job. Called whenever an event occurs that may | |
| 271 // change conditions permitting a job to run. Like when network connection is | |
| 272 // re-established, mode changes etc. | |
| 273 void DoPendingJobIfPossible(bool is_canary_job); | |
| 274 | |
| 275 // The pointer is owned by the caller. | |
| 276 browser_sync::sessions::SyncSession* CreateSyncSession( | |
| 277 const browser_sync::sessions::SyncSourceInfo& info); | |
| 278 | |
| 279 // Creates a session for a poll and performs the sync. | |
| 280 void PollTimerCallback(); | |
| 281 | |
| 282 // Assign |start| and |end| to appropriate SyncerStep values for the | |
| 283 // specified |purpose|. | |
| 284 void SetSyncerStepsForPurpose(SyncSessionJob::SyncSessionJobPurpose purpose, | |
| 285 SyncerStep* start, | |
| 286 SyncerStep* end); | |
| 287 | |
| 288 // Initializes the hookup between the ServerConnectionManager and us. | |
| 289 void WatchConnectionManager(); | |
| 290 | |
| 291 // Used to update |server_connection_ok_|, see below. | |
| 292 void CheckServerConnectionManagerStatus( | |
| 293 HttpResponse::ServerConnectionCode code); | |
| 294 | |
| 295 // Called once the first time thread_ is started to broadcast an initial | |
| 296 // session snapshot containing data like initial_sync_ended. Important when | |
| 297 // the client starts up and does not need to perform an initial sync. | |
| 298 void SendInitialSnapshot(); | |
| 299 | |
| 300 base::Thread thread_; | |
| 301 | |
| 302 // Modifiable versions of kDefaultLongPollIntervalSeconds which can be | |
| 303 // updated by the server. | |
| 304 base::TimeDelta syncer_short_poll_interval_seconds_; | |
| 305 base::TimeDelta syncer_long_poll_interval_seconds_; | |
| 306 | |
| 307 // Periodic timer for polling. See AdjustPolling. | |
| 308 base::RepeatingTimer<SyncerThread> poll_timer_; | |
| 309 | |
| 310 // The mode of operation. We don't use a lock, see Start(...) comment. | |
| 311 Mode mode_; | |
| 312 | |
| 313 // TODO(tim): Bug 26339. This needs to track more than just time I think, | |
| 314 // since the nudges could be for different types. Current impl doesn't care. | |
| 315 base::TimeTicks last_sync_session_end_time_; | |
| 316 | |
| 317 // Have we observed a valid server connection? | |
| 318 bool server_connection_ok_; | |
| 319 | |
| 320 // Tracks in-flight nudges so we can coalesce. | |
| 321 scoped_ptr<SyncSessionJob> pending_nudge_; | |
| 322 | |
| 323 // Current wait state. Null if we're not in backoff and not throttled. | |
| 324 scoped_ptr<WaitInterval> wait_interval_; | |
| 325 | |
| 326 scoped_ptr<DelayProvider> delay_provider_; | |
| 327 | |
| 328 // Invoked to run through the sync cycle. | |
| 329 scoped_ptr<Syncer> syncer_; | |
| 330 | |
| 331 scoped_ptr<sessions::SyncSessionContext> session_context_; | |
| 332 | |
| 333 DISALLOW_COPY_AND_ASSIGN(SyncerThread); | |
| 334 }; | |
| 335 | |
| 336 } // namespace s3 | |
| 337 | |
| 338 } // namespace browser_sync | |
| 339 | |
| 340 // The SyncerThread manages its own internal thread and thus outlives it. We | |
| 341 // don't need refcounting for posting tasks to this internal thread. | |
| 342 DISABLE_RUNNABLE_METHOD_REFCOUNT(browser_sync::s3::SyncerThread); | |
| 343 | |
| 344 #endif // CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD2_H_ | |
| OLD | NEW |