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

Side by Side Diff: sync/sessions/nudge_tracker.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 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
« no previous file with comments | « sync/sessions/nudge_tracker.h ('k') | sync/sessions/nudge_tracker_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 #include "sync/sessions/nudge_tracker.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/memory/ptr_util.h"
12 #include "sync/internal_api/public/engine/polling_constants.h"
13 #include "sync/protocol/sync.pb.h"
14
15 namespace syncer {
16 namespace sessions {
17
18 namespace {
19
20 // Delays for syncer nudges.
21 const int kDefaultNudgeDelayMilliseconds = 200;
22 const int kSlowNudgeDelayMilliseconds = 2000;
23 const int kDefaultSessionsCommitDelaySeconds = 10;
24 const int kSyncRefreshDelayMilliseconds = 500;
25 const int kSyncSchedulerDelayMilliseconds = 250;
26
27 base::TimeDelta GetDefaultDelayForType(ModelType model_type,
28 base::TimeDelta minimum_delay) {
29 switch (model_type) {
30 case AUTOFILL:
31 // Accompany types rely on nudges from other types, and hence have long
32 // nudge delays.
33 return base::TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds);
34 case BOOKMARKS:
35 case PREFERENCES:
36 // Types with sometimes automatic changes get longer delays to allow more
37 // coalescing.
38 return base::TimeDelta::FromMilliseconds(kSlowNudgeDelayMilliseconds);
39 case SESSIONS:
40 case FAVICON_IMAGES:
41 case FAVICON_TRACKING:
42 // Types with navigation triggered changes get longer delays to allow more
43 // coalescing.
44 return base::TimeDelta::FromSeconds(kDefaultSessionsCommitDelaySeconds);
45 default:
46 return minimum_delay;
47 }
48 }
49
50 } // namespace
51
52 size_t NudgeTracker::kDefaultMaxPayloadsPerType = 10;
53
54 NudgeTracker::NudgeTracker()
55 : invalidations_enabled_(false),
56 invalidations_out_of_sync_(true),
57 minimum_local_nudge_delay_(
58 base::TimeDelta::FromMilliseconds(kDefaultNudgeDelayMilliseconds)),
59 local_refresh_nudge_delay_(
60 base::TimeDelta::FromMilliseconds(kSyncRefreshDelayMilliseconds)),
61 remote_invalidation_nudge_delay_(
62 base::TimeDelta::FromMilliseconds(kSyncSchedulerDelayMilliseconds)) {
63 ModelTypeSet protocol_types = ProtocolTypes();
64 // Default initialize all the type trackers.
65 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good();
66 it.Inc()) {
67 type_trackers_.insert(
68 std::make_pair(it.Get(), base::WrapUnique(new DataTypeTracker())));
69 }
70 }
71
72 NudgeTracker::~NudgeTracker() { }
73
74 bool NudgeTracker::IsSyncRequired() const {
75 if (IsRetryRequired())
76 return true;
77
78 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
79 it != type_trackers_.end(); ++it) {
80 if (it->second->IsSyncRequired()) {
81 return true;
82 }
83 }
84
85 return false;
86 }
87
88 bool NudgeTracker::IsGetUpdatesRequired() const {
89 if (invalidations_out_of_sync_)
90 return true;
91
92 if (IsRetryRequired())
93 return true;
94
95 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
96 it != type_trackers_.end(); ++it) {
97 if (it->second->IsGetUpdatesRequired()) {
98 return true;
99 }
100 }
101 return false;
102 }
103
104 bool NudgeTracker::IsRetryRequired() const {
105 if (sync_cycle_start_time_.is_null())
106 return false;
107
108 if (current_retry_time_.is_null())
109 return false;
110
111 return current_retry_time_ <= sync_cycle_start_time_;
112 }
113
114 void NudgeTracker::RecordSuccessfulSyncCycle() {
115 // If a retry was required, we've just serviced it. Unset the flag.
116 if (IsRetryRequired())
117 current_retry_time_ = base::TimeTicks();
118
119 // A successful cycle while invalidations are enabled puts us back into sync.
120 invalidations_out_of_sync_ = !invalidations_enabled_;
121
122 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
123 it != type_trackers_.end(); ++it) {
124 it->second->RecordSuccessfulSyncCycle();
125 }
126 }
127
128 base::TimeDelta NudgeTracker::RecordLocalChange(ModelTypeSet types) {
129 // Start with the longest delay.
130 base::TimeDelta delay =
131 base::TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds);
132 for (ModelTypeSet::Iterator type_it = types.First(); type_it.Good();
133 type_it.Inc()) {
134 TypeTrackerMap::const_iterator tracker_it =
135 type_trackers_.find(type_it.Get());
136 DCHECK(tracker_it != type_trackers_.end());
137
138 // Only if the type tracker has a valid delay (non-zero) that is shorter
139 // than the calculated delay do we update the calculated delay.
140 base::TimeDelta type_delay = tracker_it->second->RecordLocalChange();
141 if (type_delay.is_zero()) {
142 type_delay = GetDefaultDelayForType(type_it.Get(),
143 minimum_local_nudge_delay_);
144 }
145 if (type_delay < delay)
146 delay = type_delay;
147 }
148 return delay;
149 }
150
151 base::TimeDelta NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) {
152 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
153 TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(it.Get());
154 DCHECK(tracker_it != type_trackers_.end());
155 tracker_it->second->RecordLocalRefreshRequest();
156 }
157 return local_refresh_nudge_delay_;
158 }
159
160 base::TimeDelta NudgeTracker::RecordRemoteInvalidation(
161 syncer::ModelType type,
162 std::unique_ptr<InvalidationInterface> invalidation) {
163 // Forward the invalidations to the proper recipient.
164 TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(type);
165 DCHECK(tracker_it != type_trackers_.end());
166 tracker_it->second->RecordRemoteInvalidation(std::move(invalidation));
167 return remote_invalidation_nudge_delay_;
168 }
169
170 void NudgeTracker::RecordInitialSyncRequired(syncer::ModelType type) {
171 TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(type);
172 DCHECK(tracker_it != type_trackers_.end());
173 tracker_it->second->RecordInitialSyncRequired();
174 }
175
176 void NudgeTracker::RecordCommitConflict(syncer::ModelType type) {
177 TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(type);
178 DCHECK(tracker_it != type_trackers_.end());
179 tracker_it->second->RecordCommitConflict();
180 }
181
182 void NudgeTracker::OnInvalidationsEnabled() {
183 invalidations_enabled_ = true;
184 }
185
186 void NudgeTracker::OnInvalidationsDisabled() {
187 invalidations_enabled_ = false;
188 invalidations_out_of_sync_ = true;
189 }
190
191 void NudgeTracker::SetTypesThrottledUntil(
192 ModelTypeSet types,
193 base::TimeDelta length,
194 base::TimeTicks now) {
195 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
196 TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(it.Get());
197 tracker_it->second->ThrottleType(length, now);
198 }
199 }
200
201 void NudgeTracker::UpdateTypeThrottlingState(base::TimeTicks now) {
202 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
203 it != type_trackers_.end(); ++it) {
204 it->second->UpdateThrottleState(now);
205 }
206 }
207
208 bool NudgeTracker::IsAnyTypeThrottled() const {
209 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
210 it != type_trackers_.end(); ++it) {
211 if (it->second->IsThrottled()) {
212 return true;
213 }
214 }
215 return false;
216 }
217
218 bool NudgeTracker::IsTypeThrottled(ModelType type) const {
219 DCHECK(type_trackers_.find(type) != type_trackers_.end());
220 return type_trackers_.find(type)->second->IsThrottled();
221 }
222
223 base::TimeDelta NudgeTracker::GetTimeUntilNextUnthrottle(
224 base::TimeTicks now) const {
225 DCHECK(IsAnyTypeThrottled()) << "This function requires a pending unthrottle";
226
227 // Return min of GetTimeUntilUnthrottle() values for all IsThrottled() types.
228 base::TimeDelta time_until_next_unthrottle = base::TimeDelta::Max();
229 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
230 it != type_trackers_.end(); ++it) {
231 if (it->second->IsThrottled()) {
232 time_until_next_unthrottle = std::min(
233 time_until_next_unthrottle, it->second->GetTimeUntilUnthrottle(now));
234 }
235 }
236 DCHECK(!time_until_next_unthrottle.is_max());
237
238 return time_until_next_unthrottle;
239 }
240
241 ModelTypeSet NudgeTracker::GetThrottledTypes() const {
242 ModelTypeSet result;
243 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
244 it != type_trackers_.end(); ++it) {
245 if (it->second->IsThrottled()) {
246 result.Put(it->first);
247 }
248 }
249 return result;
250 }
251
252 ModelTypeSet NudgeTracker::GetNudgedTypes() const {
253 ModelTypeSet result;
254 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
255 it != type_trackers_.end(); ++it) {
256 if (it->second->HasLocalChangePending()) {
257 result.Put(it->first);
258 }
259 }
260 return result;
261 }
262
263 ModelTypeSet NudgeTracker::GetNotifiedTypes() const {
264 ModelTypeSet result;
265 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
266 it != type_trackers_.end(); ++it) {
267 if (it->second->HasPendingInvalidation()) {
268 result.Put(it->first);
269 }
270 }
271 return result;
272 }
273
274 ModelTypeSet NudgeTracker::GetRefreshRequestedTypes() const {
275 ModelTypeSet result;
276 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
277 it != type_trackers_.end(); ++it) {
278 if (it->second->HasRefreshRequestPending()) {
279 result.Put(it->first);
280 }
281 }
282 return result;
283 }
284
285 void NudgeTracker::SetLegacyNotificationHint(
286 ModelType type,
287 sync_pb::DataTypeProgressMarker* progress) const {
288 DCHECK(type_trackers_.find(type) != type_trackers_.end());
289 type_trackers_.find(type)->second->SetLegacyNotificationHint(progress);
290 }
291
292 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::GetLegacySource()
293 const {
294 // There's an order to these sources: NOTIFICATION, DATATYPE_REFRESH, LOCAL,
295 // RETRY. The server makes optimization decisions based on this field, so
296 // it's important to get this right. Setting it wrong could lead to missed
297 // updates.
298 //
299 // This complexity is part of the reason why we're deprecating 'source' in
300 // favor of 'origin'.
301 bool has_invalidation_pending = false;
302 bool has_refresh_request_pending = false;
303 bool has_commit_pending = false;
304 bool is_initial_sync_required = false;
305 bool has_retry = IsRetryRequired();
306
307 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
308 it != type_trackers_.end(); ++it) {
309 const DataTypeTracker& tracker = *it->second;
310 if (!tracker.IsThrottled() && tracker.HasPendingInvalidation()) {
311 has_invalidation_pending = true;
312 }
313 if (!tracker.IsThrottled() && tracker.HasRefreshRequestPending()) {
314 has_refresh_request_pending = true;
315 }
316 if (!tracker.IsThrottled() && tracker.HasLocalChangePending()) {
317 has_commit_pending = true;
318 }
319 if (!tracker.IsThrottled() && tracker.IsInitialSyncRequired()) {
320 is_initial_sync_required = true;
321 }
322 }
323
324 if (has_invalidation_pending) {
325 return sync_pb::GetUpdatesCallerInfo::NOTIFICATION;
326 } else if (has_refresh_request_pending) {
327 return sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH;
328 } else if (is_initial_sync_required) {
329 // Not quite accurate, but good enough for our purposes. This setting of
330 // SOURCE is just a backward-compatibility hack anyway.
331 return sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH;
332 } else if (has_commit_pending) {
333 return sync_pb::GetUpdatesCallerInfo::LOCAL;
334 } else if (has_retry) {
335 return sync_pb::GetUpdatesCallerInfo::RETRY;
336 } else {
337 return sync_pb::GetUpdatesCallerInfo::UNKNOWN;
338 }
339 }
340
341 void NudgeTracker::FillProtoMessage(
342 ModelType type,
343 sync_pb::GetUpdateTriggers* msg) const {
344 DCHECK(type_trackers_.find(type) != type_trackers_.end());
345
346 // Fill what we can from the global data.
347 msg->set_invalidations_out_of_sync(invalidations_out_of_sync_);
348
349 // Delegate the type-specific work to the DataTypeTracker class.
350 type_trackers_.find(type)->second->FillGetUpdatesTriggersMessage(msg);
351 }
352
353 void NudgeTracker::SetSyncCycleStartTime(base::TimeTicks now) {
354 sync_cycle_start_time_ = now;
355
356 // If current_retry_time_ is still set, that means we have an old retry time
357 // left over from a previous cycle. For example, maybe we tried to perform
358 // this retry, hit a network connection error, and now we're in exponential
359 // backoff. In that case, we want this sync cycle to include the GU retry
360 // flag so we leave this variable set regardless of whether or not there is an
361 // overwrite pending.
362 if (!current_retry_time_.is_null()) {
363 return;
364 }
365
366 // If do not have a current_retry_time_, but we do have a next_retry_time_ and
367 // it is ready to go, then we set it as the current_retry_time_. It will stay
368 // there until a GU retry has succeeded.
369 if (!next_retry_time_.is_null() &&
370 next_retry_time_ <= sync_cycle_start_time_) {
371 current_retry_time_ = next_retry_time_;
372 next_retry_time_ = base::TimeTicks();
373 }
374 }
375
376 void NudgeTracker::SetHintBufferSize(size_t size) {
377 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
378 it != type_trackers_.end(); ++it) {
379 it->second->UpdatePayloadBufferSize(size);
380 }
381 }
382
383 void NudgeTracker::SetNextRetryTime(base::TimeTicks retry_time) {
384 next_retry_time_ = retry_time;
385 }
386
387 void NudgeTracker::OnReceivedCustomNudgeDelays(
388 const std::map<ModelType, base::TimeDelta>& delay_map) {
389 for (std::map<ModelType, base::TimeDelta>::const_iterator iter =
390 delay_map.begin();
391 iter != delay_map.end();
392 ++iter) {
393 ModelType type = iter->first;
394 DCHECK(syncer::ProtocolTypes().Has(type));
395 TypeTrackerMap::const_iterator type_iter = type_trackers_.find(type);
396 if (type_iter == type_trackers_.end())
397 continue;
398
399 if (iter->second > minimum_local_nudge_delay_) {
400 type_iter->second->UpdateLocalNudgeDelay(iter->second);
401 } else {
402 type_iter->second->UpdateLocalNudgeDelay(
403 GetDefaultDelayForType(type,
404 minimum_local_nudge_delay_));
405 }
406 }
407 }
408
409 void NudgeTracker::SetDefaultNudgeDelay(base::TimeDelta nudge_delay) {
410 minimum_local_nudge_delay_ = nudge_delay;
411 }
412
413 } // namespace sessions
414 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/sessions/nudge_tracker.h ('k') | sync/sessions/nudge_tracker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698