[SyncFS] Build indexes from FileTracker entries on disk.
[chromium-blink-merge.git] / sync / sessions / nudge_tracker.cc
blobe4ebc23940059566b1979c8196208c6cb222b422
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.
5 #include "sync/sessions/nudge_tracker.h"
7 #include "base/basictypes.h"
8 #include "sync/protocol/sync.pb.h"
10 namespace syncer {
11 namespace sessions {
13 size_t NudgeTracker::kDefaultMaxPayloadsPerType = 10;
15 NudgeTracker::NudgeTracker()
16 : type_tracker_deleter_(&type_trackers_),
17 invalidations_enabled_(false),
18 invalidations_out_of_sync_(true) {
19 ModelTypeSet protocol_types = ProtocolTypes();
20 // Default initialize all the type trackers.
21 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good();
22 it.Inc()) {
23 type_trackers_.insert(std::make_pair(it.Get(), new DataTypeTracker()));
27 NudgeTracker::~NudgeTracker() { }
29 bool NudgeTracker::IsSyncRequired() const {
30 if (IsRetryRequired())
31 return true;
33 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
34 it != type_trackers_.end(); ++it) {
35 if (it->second->IsSyncRequired()) {
36 return true;
40 return false;
43 bool NudgeTracker::IsGetUpdatesRequired() const {
44 if (invalidations_out_of_sync_)
45 return true;
47 if (IsRetryRequired())
48 return true;
50 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
51 it != type_trackers_.end(); ++it) {
52 if (it->second->IsGetUpdatesRequired()) {
53 return true;
56 return false;
59 bool NudgeTracker::IsRetryRequired() const {
60 if (sync_cycle_start_time_.is_null())
61 return false;
63 if (current_retry_time_.is_null())
64 return false;
66 return current_retry_time_ < sync_cycle_start_time_;
69 void NudgeTracker::RecordSuccessfulSyncCycle() {
70 // If a retry was required, we've just serviced it. Unset the flag.
71 if (IsRetryRequired())
72 current_retry_time_ = base::TimeTicks();
74 // A successful cycle while invalidations are enabled puts us back into sync.
75 invalidations_out_of_sync_ = !invalidations_enabled_;
77 for (TypeTrackerMap::iterator it = type_trackers_.begin();
78 it != type_trackers_.end(); ++it) {
79 it->second->RecordSuccessfulSyncCycle();
83 void NudgeTracker::RecordLocalChange(ModelTypeSet types) {
84 for (ModelTypeSet::Iterator type_it = types.First(); type_it.Good();
85 type_it.Inc()) {
86 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type_it.Get());
87 DCHECK(tracker_it != type_trackers_.end());
88 tracker_it->second->RecordLocalChange();
92 void NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) {
93 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
94 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get());
95 DCHECK(tracker_it != type_trackers_.end());
96 tracker_it->second->RecordLocalRefreshRequest();
100 void NudgeTracker::RecordRemoteInvalidation(
101 syncer::ModelType type,
102 scoped_ptr<InvalidationInterface> invalidation) {
103 // Forward the invalidations to the proper recipient.
104 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type);
105 DCHECK(tracker_it != type_trackers_.end());
106 tracker_it->second->RecordRemoteInvalidation(invalidation.Pass());
109 void NudgeTracker::OnInvalidationsEnabled() {
110 invalidations_enabled_ = true;
113 void NudgeTracker::OnInvalidationsDisabled() {
114 invalidations_enabled_ = false;
115 invalidations_out_of_sync_ = true;
118 void NudgeTracker::SetTypesThrottledUntil(
119 ModelTypeSet types,
120 base::TimeDelta length,
121 base::TimeTicks now) {
122 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
123 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get());
124 tracker_it->second->ThrottleType(length, now);
128 void NudgeTracker::UpdateTypeThrottlingState(base::TimeTicks now) {
129 for (TypeTrackerMap::iterator it = type_trackers_.begin();
130 it != type_trackers_.end(); ++it) {
131 it->second->UpdateThrottleState(now);
135 bool NudgeTracker::IsAnyTypeThrottled() const {
136 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
137 it != type_trackers_.end(); ++it) {
138 if (it->second->IsThrottled()) {
139 return true;
142 return false;
145 bool NudgeTracker::IsTypeThrottled(ModelType type) const {
146 DCHECK(type_trackers_.find(type) != type_trackers_.end());
147 return type_trackers_.find(type)->second->IsThrottled();
150 base::TimeDelta NudgeTracker::GetTimeUntilNextUnthrottle(
151 base::TimeTicks now) const {
152 DCHECK(IsAnyTypeThrottled()) << "This function requires a pending unthrottle";
154 // Return min of GetTimeUntilUnthrottle() values for all IsThrottled() types.
155 base::TimeDelta time_until_next_unthrottle = base::TimeDelta::Max();
156 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
157 it != type_trackers_.end(); ++it) {
158 if (it->second->IsThrottled()) {
159 time_until_next_unthrottle = std::min(
160 time_until_next_unthrottle, it->second->GetTimeUntilUnthrottle(now));
163 DCHECK(!time_until_next_unthrottle.is_max());
165 return time_until_next_unthrottle;
168 ModelTypeSet NudgeTracker::GetThrottledTypes() const {
169 ModelTypeSet result;
170 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
171 it != type_trackers_.end(); ++it) {
172 if (it->second->IsThrottled()) {
173 result.Put(it->first);
176 return result;
179 ModelTypeSet NudgeTracker::GetNudgedTypes() const {
180 ModelTypeSet result;
181 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
182 it != type_trackers_.end(); ++it) {
183 if (it->second->HasLocalChangePending()) {
184 result.Put(it->first);
187 return result;
190 ModelTypeSet NudgeTracker::GetNotifiedTypes() const {
191 ModelTypeSet result;
192 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
193 it != type_trackers_.end(); ++it) {
194 if (it->second->HasPendingInvalidation()) {
195 result.Put(it->first);
198 return result;
201 ModelTypeSet NudgeTracker::GetRefreshRequestedTypes() const {
202 ModelTypeSet result;
203 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
204 it != type_trackers_.end(); ++it) {
205 if (it->second->HasRefreshRequestPending()) {
206 result.Put(it->first);
209 return result;
212 void NudgeTracker::SetLegacyNotificationHint(
213 ModelType type,
214 sync_pb::DataTypeProgressMarker* progress) const {
215 DCHECK(type_trackers_.find(type) != type_trackers_.end());
216 type_trackers_.find(type)->second->SetLegacyNotificationHint(progress);
219 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::GetLegacySource()
220 const {
221 // There's an order to these sources: NOTIFICATION, DATATYPE_REFRESH, LOCAL,
222 // RETRY. The server makes optimization decisions based on this field, so
223 // it's important to get this right. Setting it wrong could lead to missed
224 // updates.
226 // This complexity is part of the reason why we're deprecating 'source' in
227 // favor of 'origin'.
228 bool has_invalidation_pending = false;
229 bool has_refresh_request_pending = false;
230 bool has_commit_pending = false;
231 bool has_retry = IsRetryRequired();
233 for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
234 it != type_trackers_.end(); ++it) {
235 const DataTypeTracker& tracker = *it->second;
236 if (!tracker.IsThrottled() && tracker.HasPendingInvalidation()) {
237 has_invalidation_pending = true;
239 if (!tracker.IsThrottled() && tracker.HasRefreshRequestPending()) {
240 has_refresh_request_pending = true;
242 if (!tracker.IsThrottled() && tracker.HasLocalChangePending()) {
243 has_commit_pending = true;
247 if (has_invalidation_pending) {
248 return sync_pb::GetUpdatesCallerInfo::NOTIFICATION;
249 } else if (has_refresh_request_pending) {
250 return sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH;
251 } else if (has_commit_pending) {
252 return sync_pb::GetUpdatesCallerInfo::LOCAL;
253 } else if (has_retry) {
254 return sync_pb::GetUpdatesCallerInfo::RETRY;
255 } else {
256 return sync_pb::GetUpdatesCallerInfo::UNKNOWN;
260 void NudgeTracker::FillProtoMessage(
261 ModelType type,
262 sync_pb::GetUpdateTriggers* msg) const {
263 DCHECK(type_trackers_.find(type) != type_trackers_.end());
265 // Fill what we can from the global data.
266 msg->set_invalidations_out_of_sync(invalidations_out_of_sync_);
268 // Delegate the type-specific work to the DataTypeTracker class.
269 type_trackers_.find(type)->second->FillGetUpdatesTriggersMessage(msg);
272 void NudgeTracker::SetSyncCycleStartTime(base::TimeTicks now) {
273 sync_cycle_start_time_ = now;
275 // If current_retry_time_ is still set, that means we have an old retry time
276 // left over from a previous cycle. For example, maybe we tried to perform
277 // this retry, hit a network connection error, and now we're in exponential
278 // backoff. In that case, we want this sync cycle to include the GU retry
279 // flag so we leave this variable set regardless of whether or not there is an
280 // overwrite pending.
281 if (!current_retry_time_.is_null()) {
282 return;
285 // If do not have a current_retry_time_, but we do have a next_retry_time_ and
286 // it is ready to go, then we set it as the current_retry_time_. It will stay
287 // there until a GU retry has succeeded.
288 if (!next_retry_time_.is_null() &&
289 next_retry_time_ < sync_cycle_start_time_) {
290 current_retry_time_ = next_retry_time_;
291 next_retry_time_ = base::TimeTicks();
295 void NudgeTracker::SetHintBufferSize(size_t size) {
296 for (TypeTrackerMap::iterator it = type_trackers_.begin();
297 it != type_trackers_.end(); ++it) {
298 it->second->UpdatePayloadBufferSize(size);
302 void NudgeTracker::SetNextRetryTime(base::TimeTicks retry_time) {
303 next_retry_time_ = retry_time;
306 } // namespace sessions
307 } // namespace syncer