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

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

Issue 322333004: sync: Inject sync/'s dependency on invalidations (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 6 years, 5 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 | Annotate | Revision Log
« 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/sessions/nudge_tracker.h" 5 #include "sync/sessions/nudge_tracker.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "sync/internal_api/public/base/invalidation.h" 8 #include "sync/internal_api/public/base/invalidation.h"
9 #include "sync/notifier/invalidation_util.h" 9 #include "sync/notifier/invalidation_util.h"
10 #include "sync/notifier/object_id_invalidation_map.h" 10 #include "sync/notifier/object_id_invalidation_map.h"
11 #include "sync/protocol/sync.pb.h" 11 #include "sync/protocol/sync.pb.h"
12 12
13 namespace syncer { 13 namespace syncer {
14 namespace sessions { 14 namespace sessions {
15 15
16 size_t NudgeTracker::kDefaultMaxPayloadsPerType = 10; 16 size_t NudgeTracker::kDefaultMaxPayloadsPerType = 10;
17 17
18 NudgeTracker::NudgeTracker() 18 NudgeTracker::NudgeTracker()
19 : invalidations_enabled_(false), 19 : type_tracker_deleter_(&type_trackers_),
20 invalidations_enabled_(false),
20 invalidations_out_of_sync_(true) { 21 invalidations_out_of_sync_(true) {
21 ModelTypeSet protocol_types = ProtocolTypes(); 22 ModelTypeSet protocol_types = ProtocolTypes();
22 // Default initialize all the type trackers. 23 // Default initialize all the type trackers.
23 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good(); 24 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good();
24 it.Inc()) { 25 it.Inc()) {
25 invalidation::ObjectId id; 26 type_trackers_.insert(std::make_pair(it.Get(), new DataTypeTracker()));
26 if (!RealModelTypeToObjectId(it.Get(), &id)) {
27 NOTREACHED();
28 } else {
29 type_trackers_.insert(std::make_pair(it.Get(), DataTypeTracker(id)));
30 }
31 } 27 }
32 } 28 }
33 29
34 NudgeTracker::~NudgeTracker() { } 30 NudgeTracker::~NudgeTracker() { }
35 31
36 bool NudgeTracker::IsSyncRequired() const { 32 bool NudgeTracker::IsSyncRequired() const {
37 if (IsRetryRequired()) 33 if (IsRetryRequired())
38 return true; 34 return true;
39 35
40 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 36 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
41 it != type_trackers_.end(); ++it) { 37 it != type_trackers_.end(); ++it) {
42 if (it->second.IsSyncRequired()) { 38 if (it->second->IsSyncRequired()) {
43 return true; 39 return true;
44 } 40 }
45 } 41 }
46 42
47 return false; 43 return false;
48 } 44 }
49 45
50 bool NudgeTracker::IsGetUpdatesRequired() const { 46 bool NudgeTracker::IsGetUpdatesRequired() const {
51 if (invalidations_out_of_sync_) 47 if (invalidations_out_of_sync_)
52 return true; 48 return true;
53 49
54 if (IsRetryRequired()) 50 if (IsRetryRequired())
55 return true; 51 return true;
56 52
57 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 53 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
58 it != type_trackers_.end(); ++it) { 54 it != type_trackers_.end(); ++it) {
59 if (it->second.IsGetUpdatesRequired()) { 55 if (it->second->IsGetUpdatesRequired()) {
60 return true; 56 return true;
61 } 57 }
62 } 58 }
63 return false; 59 return false;
64 } 60 }
65 61
66 bool NudgeTracker::IsRetryRequired() const { 62 bool NudgeTracker::IsRetryRequired() const {
67 if (sync_cycle_start_time_.is_null()) 63 if (sync_cycle_start_time_.is_null())
68 return false; 64 return false;
69 65
70 if (current_retry_time_.is_null()) 66 if (current_retry_time_.is_null())
71 return false; 67 return false;
72 68
73 return current_retry_time_ < sync_cycle_start_time_; 69 return current_retry_time_ < sync_cycle_start_time_;
74 } 70 }
75 71
76 void NudgeTracker::RecordSuccessfulSyncCycle() { 72 void NudgeTracker::RecordSuccessfulSyncCycle() {
77 // If a retry was required, we've just serviced it. Unset the flag. 73 // If a retry was required, we've just serviced it. Unset the flag.
78 if (IsRetryRequired()) 74 if (IsRetryRequired())
79 current_retry_time_ = base::TimeTicks(); 75 current_retry_time_ = base::TimeTicks();
80 76
81 // A successful cycle while invalidations are enabled puts us back into sync. 77 // A successful cycle while invalidations are enabled puts us back into sync.
82 invalidations_out_of_sync_ = !invalidations_enabled_; 78 invalidations_out_of_sync_ = !invalidations_enabled_;
83 79
84 for (TypeTrackerMap::iterator it = type_trackers_.begin(); 80 for (TypeTrackerMap::iterator it = type_trackers_.begin();
85 it != type_trackers_.end(); ++it) { 81 it != type_trackers_.end(); ++it) {
86 it->second.RecordSuccessfulSyncCycle(); 82 it->second->RecordSuccessfulSyncCycle();
87 } 83 }
88 } 84 }
89 85
90 void NudgeTracker::RecordLocalChange(ModelTypeSet types) { 86 void NudgeTracker::RecordLocalChange(ModelTypeSet types) {
91 for (ModelTypeSet::Iterator type_it = types.First(); type_it.Good(); 87 for (ModelTypeSet::Iterator type_it = types.First(); type_it.Good();
92 type_it.Inc()) { 88 type_it.Inc()) {
93 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type_it.Get()); 89 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type_it.Get());
94 DCHECK(tracker_it != type_trackers_.end()); 90 DCHECK(tracker_it != type_trackers_.end());
95 tracker_it->second.RecordLocalChange(); 91 tracker_it->second->RecordLocalChange();
96 } 92 }
97 } 93 }
98 94
99 void NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) { 95 void NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) {
100 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) { 96 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
101 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get()); 97 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get());
102 DCHECK(tracker_it != type_trackers_.end()); 98 DCHECK(tracker_it != type_trackers_.end());
103 tracker_it->second.RecordLocalRefreshRequest(); 99 tracker_it->second->RecordLocalRefreshRequest();
104 } 100 }
105 } 101 }
106 102
107 void NudgeTracker::RecordRemoteInvalidation( 103 void NudgeTracker::RecordRemoteInvalidation(
108 const ObjectIdInvalidationMap& invalidation_map) { 104 syncer::ModelType type,
109 // Be very careful here. The invalidations acknowledgement system requires a 105 scoped_ptr<InvalidationInterface> invalidation) {
110 // sort of manual memory management. We'll leak a small amount of memory if 106 // Forward the invalidations to the proper recipient.
111 // we fail to acknowledge or drop any of these incoming invalidations. 107 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type);
112 108 DCHECK(tracker_it != type_trackers_.end());
113 ObjectIdSet id_set = invalidation_map.GetObjectIds(); 109 tracker_it->second->RecordRemoteInvalidation(invalidation.Pass());
114 for (ObjectIdSet::iterator it = id_set.begin(); it != id_set.end(); ++it) {
115 ModelType type;
116
117 // This should never happen. If it does, we'll start to leak memory.
118 if (!ObjectIdToRealModelType(*it, &type)) {
119 NOTREACHED()
120 << "Object ID " << ObjectIdToString(*it)
121 << " does not map to valid model type";
122 continue;
123 }
124
125 // Forward the invalidations to the proper recipient.
126 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type);
127 DCHECK(tracker_it != type_trackers_.end());
128 tracker_it->second.RecordRemoteInvalidations(
129 invalidation_map.ForObject(*it));
130 }
131 } 110 }
132 111
133 void NudgeTracker::OnInvalidationsEnabled() { 112 void NudgeTracker::OnInvalidationsEnabled() {
134 invalidations_enabled_ = true; 113 invalidations_enabled_ = true;
135 } 114 }
136 115
137 void NudgeTracker::OnInvalidationsDisabled() { 116 void NudgeTracker::OnInvalidationsDisabled() {
138 invalidations_enabled_ = false; 117 invalidations_enabled_ = false;
139 invalidations_out_of_sync_ = true; 118 invalidations_out_of_sync_ = true;
140 } 119 }
141 120
142 void NudgeTracker::SetTypesThrottledUntil( 121 void NudgeTracker::SetTypesThrottledUntil(
143 ModelTypeSet types, 122 ModelTypeSet types,
144 base::TimeDelta length, 123 base::TimeDelta length,
145 base::TimeTicks now) { 124 base::TimeTicks now) {
146 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) { 125 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
147 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get()); 126 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get());
148 tracker_it->second.ThrottleType(length, now); 127 tracker_it->second->ThrottleType(length, now);
149 } 128 }
150 } 129 }
151 130
152 void NudgeTracker::UpdateTypeThrottlingState(base::TimeTicks now) { 131 void NudgeTracker::UpdateTypeThrottlingState(base::TimeTicks now) {
153 for (TypeTrackerMap::iterator it = type_trackers_.begin(); 132 for (TypeTrackerMap::iterator it = type_trackers_.begin();
154 it != type_trackers_.end(); ++it) { 133 it != type_trackers_.end(); ++it) {
155 it->second.UpdateThrottleState(now); 134 it->second->UpdateThrottleState(now);
156 } 135 }
157 } 136 }
158 137
159 bool NudgeTracker::IsAnyTypeThrottled() const { 138 bool NudgeTracker::IsAnyTypeThrottled() const {
160 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 139 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
161 it != type_trackers_.end(); ++it) { 140 it != type_trackers_.end(); ++it) {
162 if (it->second.IsThrottled()) { 141 if (it->second->IsThrottled()) {
163 return true; 142 return true;
164 } 143 }
165 } 144 }
166 return false; 145 return false;
167 } 146 }
168 147
169 bool NudgeTracker::IsTypeThrottled(ModelType type) const { 148 bool NudgeTracker::IsTypeThrottled(ModelType type) const {
170 DCHECK(type_trackers_.find(type) != type_trackers_.end()); 149 DCHECK(type_trackers_.find(type) != type_trackers_.end());
171 return type_trackers_.find(type)->second.IsThrottled(); 150 return type_trackers_.find(type)->second->IsThrottled();
172 } 151 }
173 152
174 base::TimeDelta NudgeTracker::GetTimeUntilNextUnthrottle( 153 base::TimeDelta NudgeTracker::GetTimeUntilNextUnthrottle(
175 base::TimeTicks now) const { 154 base::TimeTicks now) const {
176 DCHECK(IsAnyTypeThrottled()) << "This function requires a pending unthrottle"; 155 DCHECK(IsAnyTypeThrottled()) << "This function requires a pending unthrottle";
177 156
178 // Return min of GetTimeUntilUnthrottle() values for all IsThrottled() types. 157 // Return min of GetTimeUntilUnthrottle() values for all IsThrottled() types.
179 base::TimeDelta time_until_next_unthrottle = base::TimeDelta::Max(); 158 base::TimeDelta time_until_next_unthrottle = base::TimeDelta::Max();
180 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 159 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
181 it != type_trackers_.end(); ++it) { 160 it != type_trackers_.end(); ++it) {
182 if (it->second.IsThrottled()) { 161 if (it->second->IsThrottled()) {
183 time_until_next_unthrottle = 162 time_until_next_unthrottle = std::min(
184 std::min(time_until_next_unthrottle, 163 time_until_next_unthrottle, it->second->GetTimeUntilUnthrottle(now));
185 it->second.GetTimeUntilUnthrottle(now));
186 } 164 }
187 } 165 }
188 DCHECK(!time_until_next_unthrottle.is_max()); 166 DCHECK(!time_until_next_unthrottle.is_max());
189 167
190 return time_until_next_unthrottle; 168 return time_until_next_unthrottle;
191 } 169 }
192 170
193 ModelTypeSet NudgeTracker::GetThrottledTypes() const { 171 ModelTypeSet NudgeTracker::GetThrottledTypes() const {
194 ModelTypeSet result; 172 ModelTypeSet result;
195 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 173 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
196 it != type_trackers_.end(); ++it) { 174 it != type_trackers_.end(); ++it) {
197 if (it->second.IsThrottled()) { 175 if (it->second->IsThrottled()) {
198 result.Put(it->first); 176 result.Put(it->first);
199 } 177 }
200 } 178 }
201 return result; 179 return result;
202 } 180 }
203 181
204 ModelTypeSet NudgeTracker::GetNudgedTypes() const { 182 ModelTypeSet NudgeTracker::GetNudgedTypes() const {
205 ModelTypeSet result; 183 ModelTypeSet result;
206 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 184 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
207 it != type_trackers_.end(); ++it) { 185 it != type_trackers_.end(); ++it) {
208 if (it->second.HasLocalChangePending()) { 186 if (it->second->HasLocalChangePending()) {
209 result.Put(it->first); 187 result.Put(it->first);
210 } 188 }
211 } 189 }
212 return result; 190 return result;
213 } 191 }
214 192
215 ModelTypeSet NudgeTracker::GetNotifiedTypes() const { 193 ModelTypeSet NudgeTracker::GetNotifiedTypes() const {
216 ModelTypeSet result; 194 ModelTypeSet result;
217 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 195 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
218 it != type_trackers_.end(); ++it) { 196 it != type_trackers_.end(); ++it) {
219 if (it->second.HasPendingInvalidation()) { 197 if (it->second->HasPendingInvalidation()) {
220 result.Put(it->first); 198 result.Put(it->first);
221 } 199 }
222 } 200 }
223 return result; 201 return result;
224 } 202 }
225 203
226 ModelTypeSet NudgeTracker::GetRefreshRequestedTypes() const { 204 ModelTypeSet NudgeTracker::GetRefreshRequestedTypes() const {
227 ModelTypeSet result; 205 ModelTypeSet result;
228 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 206 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
229 it != type_trackers_.end(); ++it) { 207 it != type_trackers_.end(); ++it) {
230 if (it->second.HasRefreshRequestPending()) { 208 if (it->second->HasRefreshRequestPending()) {
231 result.Put(it->first); 209 result.Put(it->first);
232 } 210 }
233 } 211 }
234 return result; 212 return result;
235 } 213 }
236 214
237 void NudgeTracker::SetLegacyNotificationHint( 215 void NudgeTracker::SetLegacyNotificationHint(
238 ModelType type, 216 ModelType type,
239 sync_pb::DataTypeProgressMarker* progress) const { 217 sync_pb::DataTypeProgressMarker* progress) const {
240 DCHECK(type_trackers_.find(type) != type_trackers_.end()); 218 DCHECK(type_trackers_.find(type) != type_trackers_.end());
241 type_trackers_.find(type)->second.SetLegacyNotificationHint(progress); 219 type_trackers_.find(type)->second->SetLegacyNotificationHint(progress);
242 } 220 }
243 221
244 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::GetLegacySource() 222 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::GetLegacySource()
245 const { 223 const {
246 // There's an order to these sources: NOTIFICATION, DATATYPE_REFRESH, LOCAL, 224 // There's an order to these sources: NOTIFICATION, DATATYPE_REFRESH, LOCAL,
247 // RETRY. The server makes optimization decisions based on this field, so 225 // RETRY. The server makes optimization decisions based on this field, so
248 // it's important to get this right. Setting it wrong could lead to missed 226 // it's important to get this right. Setting it wrong could lead to missed
249 // updates. 227 // updates.
250 // 228 //
251 // This complexity is part of the reason why we're deprecating 'source' in 229 // This complexity is part of the reason why we're deprecating 'source' in
252 // favor of 'origin'. 230 // favor of 'origin'.
253 bool has_invalidation_pending = false; 231 bool has_invalidation_pending = false;
254 bool has_refresh_request_pending = false; 232 bool has_refresh_request_pending = false;
255 bool has_commit_pending = false; 233 bool has_commit_pending = false;
256 bool has_retry = IsRetryRequired(); 234 bool has_retry = IsRetryRequired();
257 235
258 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); 236 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
259 it != type_trackers_.end(); ++it) { 237 it != type_trackers_.end(); ++it) {
260 const DataTypeTracker& tracker = it->second; 238 const DataTypeTracker& tracker = *it->second;
261 if (!tracker.IsThrottled() && tracker.HasPendingInvalidation()) { 239 if (!tracker.IsThrottled() && tracker.HasPendingInvalidation()) {
262 has_invalidation_pending = true; 240 has_invalidation_pending = true;
263 } 241 }
264 if (!tracker.IsThrottled() && tracker.HasRefreshRequestPending()) { 242 if (!tracker.IsThrottled() && tracker.HasRefreshRequestPending()) {
265 has_refresh_request_pending = true; 243 has_refresh_request_pending = true;
266 } 244 }
267 if (!tracker.IsThrottled() && tracker.HasLocalChangePending()) { 245 if (!tracker.IsThrottled() && tracker.HasLocalChangePending()) {
268 has_commit_pending = true; 246 has_commit_pending = true;
269 } 247 }
270 } 248 }
(...skipping 13 matching lines...) Expand all
284 262
285 void NudgeTracker::FillProtoMessage( 263 void NudgeTracker::FillProtoMessage(
286 ModelType type, 264 ModelType type,
287 sync_pb::GetUpdateTriggers* msg) const { 265 sync_pb::GetUpdateTriggers* msg) const {
288 DCHECK(type_trackers_.find(type) != type_trackers_.end()); 266 DCHECK(type_trackers_.find(type) != type_trackers_.end());
289 267
290 // Fill what we can from the global data. 268 // Fill what we can from the global data.
291 msg->set_invalidations_out_of_sync(invalidations_out_of_sync_); 269 msg->set_invalidations_out_of_sync(invalidations_out_of_sync_);
292 270
293 // Delegate the type-specific work to the DataTypeTracker class. 271 // Delegate the type-specific work to the DataTypeTracker class.
294 type_trackers_.find(type)->second.FillGetUpdatesTriggersMessage(msg); 272 type_trackers_.find(type)->second->FillGetUpdatesTriggersMessage(msg);
295 } 273 }
296 274
297 void NudgeTracker::SetSyncCycleStartTime(base::TimeTicks now) { 275 void NudgeTracker::SetSyncCycleStartTime(base::TimeTicks now) {
298 sync_cycle_start_time_ = now; 276 sync_cycle_start_time_ = now;
299 277
300 // If current_retry_time_ is still set, that means we have an old retry time 278 // If current_retry_time_ is still set, that means we have an old retry time
301 // left over from a previous cycle. For example, maybe we tried to perform 279 // left over from a previous cycle. For example, maybe we tried to perform
302 // this retry, hit a network connection error, and now we're in exponential 280 // this retry, hit a network connection error, and now we're in exponential
303 // backoff. In that case, we want this sync cycle to include the GU retry 281 // backoff. In that case, we want this sync cycle to include the GU retry
304 // flag so we leave this variable set regardless of whether or not there is an 282 // flag so we leave this variable set regardless of whether or not there is an
305 // overwrite pending. 283 // overwrite pending.
306 if (!current_retry_time_.is_null()) { 284 if (!current_retry_time_.is_null()) {
307 return; 285 return;
308 } 286 }
309 287
310 // If do not have a current_retry_time_, but we do have a next_retry_time_ and 288 // If do not have a current_retry_time_, but we do have a next_retry_time_ and
311 // it is ready to go, then we set it as the current_retry_time_. It will stay 289 // it is ready to go, then we set it as the current_retry_time_. It will stay
312 // there until a GU retry has succeeded. 290 // there until a GU retry has succeeded.
313 if (!next_retry_time_.is_null() && 291 if (!next_retry_time_.is_null() &&
314 next_retry_time_ < sync_cycle_start_time_) { 292 next_retry_time_ < sync_cycle_start_time_) {
315 current_retry_time_ = next_retry_time_; 293 current_retry_time_ = next_retry_time_;
316 next_retry_time_ = base::TimeTicks(); 294 next_retry_time_ = base::TimeTicks();
317 } 295 }
318 } 296 }
319 297
320 void NudgeTracker::SetHintBufferSize(size_t size) { 298 void NudgeTracker::SetHintBufferSize(size_t size) {
321 for (TypeTrackerMap::iterator it = type_trackers_.begin(); 299 for (TypeTrackerMap::iterator it = type_trackers_.begin();
322 it != type_trackers_.end(); ++it) { 300 it != type_trackers_.end(); ++it) {
323 it->second.UpdatePayloadBufferSize(size); 301 it->second->UpdatePayloadBufferSize(size);
324 } 302 }
325 } 303 }
326 304
327 void NudgeTracker::SetNextRetryTime(base::TimeTicks retry_time) { 305 void NudgeTracker::SetNextRetryTime(base::TimeTicks retry_time) {
328 next_retry_time_ = retry_time; 306 next_retry_time_ = retry_time;
329 } 307 }
330 308
331 } // namespace sessions 309 } // namespace sessions
332 } // namespace syncer 310 } // 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