• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/basictypes.h"
8 #include "sync/internal_api/public/base/invalidation.h"
9 #include "sync/notifier/invalidation_util.h"
10 #include "sync/notifier/object_id_invalidation_map.h"
11 #include "sync/protocol/sync.pb.h"
12 
13 namespace syncer {
14 namespace sessions {
15 
16 size_t NudgeTracker::kDefaultMaxPayloadsPerType = 10;
17 
NudgeTracker()18 NudgeTracker::NudgeTracker()
19     : updates_source_(sync_pb::GetUpdatesCallerInfo::UNKNOWN),
20       invalidations_enabled_(false),
21       invalidations_out_of_sync_(true) {
22   ModelTypeSet protocol_types = ProtocolTypes();
23   // Default initialize all the type trackers.
24   for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good();
25        it.Inc()) {
26     type_trackers_[it.Get()] = DataTypeTracker();
27   }
28 }
29 
~NudgeTracker()30 NudgeTracker::~NudgeTracker() { }
31 
IsSyncRequired() const32 bool NudgeTracker::IsSyncRequired() const {
33   for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
34        it != type_trackers_.end(); ++it) {
35     if (it->second.IsSyncRequired()) {
36       return true;
37     }
38   }
39   return false;
40 }
41 
IsGetUpdatesRequired() const42 bool NudgeTracker::IsGetUpdatesRequired() const {
43   if (invalidations_out_of_sync_)
44     return true;
45   for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
46        it != type_trackers_.end(); ++it) {
47     if (it->second.IsGetUpdatesRequired()) {
48       return true;
49     }
50   }
51   return false;
52 }
53 
RecordSuccessfulSyncCycle()54 void NudgeTracker::RecordSuccessfulSyncCycle() {
55   updates_source_ = sync_pb::GetUpdatesCallerInfo::UNKNOWN;
56 
57   // A successful cycle while invalidations are enabled puts us back into sync.
58   invalidations_out_of_sync_ = !invalidations_enabled_;
59 
60   for (TypeTrackerMap::iterator it = type_trackers_.begin();
61        it != type_trackers_.end(); ++it) {
62     it->second.RecordSuccessfulSyncCycle();
63   }
64 }
65 
RecordLocalChange(ModelTypeSet types)66 void NudgeTracker::RecordLocalChange(ModelTypeSet types) {
67   // Don't overwrite an NOTIFICATION or DATATYPE_REFRESH source.  The server
68   // makes some assumptions about the source; overriding these sources with
69   // LOCAL could lead to incorrect behaviour.  This is part of the reason why
70   // we're deprecating 'source' in favor of 'origin'.
71   if (updates_source_ != sync_pb::GetUpdatesCallerInfo::NOTIFICATION
72       && updates_source_ != sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH) {
73     updates_source_ = sync_pb::GetUpdatesCallerInfo::LOCAL;
74   }
75 
76   for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
77     DCHECK(type_trackers_.find(it.Get()) != type_trackers_.end());
78     type_trackers_[it.Get()].RecordLocalChange();
79   }
80 }
81 
RecordLocalRefreshRequest(ModelTypeSet types)82 void NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) {
83   // Don't overwrite an NOTIFICATION source.  The server makes some assumptions
84   // about the source.  Overriding this source with LOCAL could lead to
85   // incorrect behaviour.  This is part of the reason why we're deprecating
86   // 'source' in favor of 'origin'.
87   if (updates_source_ != sync_pb::GetUpdatesCallerInfo::NOTIFICATION) {
88     updates_source_ = sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH;
89   }
90 
91   for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
92     DCHECK(type_trackers_.find(it.Get()) != type_trackers_.end());
93     type_trackers_[it.Get()].RecordLocalRefreshRequest();
94   }
95 }
96 
RecordRemoteInvalidation(const ObjectIdInvalidationMap & invalidation_map)97 void NudgeTracker::RecordRemoteInvalidation(
98     const ObjectIdInvalidationMap& invalidation_map) {
99   updates_source_ = sync_pb::GetUpdatesCallerInfo::NOTIFICATION;
100 
101   ObjectIdSet ids = invalidation_map.GetObjectIds();
102   for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
103     ModelType type;
104     if (!ObjectIdToRealModelType(*it, &type)) {
105       NOTREACHED()
106           << "Object ID " << ObjectIdToString(*it)
107           << " does not map to valid model type";
108     }
109     DCHECK(type_trackers_.find(type) != type_trackers_.end());
110     type_trackers_[type].RecordRemoteInvalidations(
111         invalidation_map.ForObject(*it));
112   }
113 }
114 
OnInvalidationsEnabled()115 void NudgeTracker::OnInvalidationsEnabled() {
116   invalidations_enabled_ = true;
117 }
118 
OnInvalidationsDisabled()119 void NudgeTracker::OnInvalidationsDisabled() {
120   invalidations_enabled_ = false;
121   invalidations_out_of_sync_ = true;
122 }
123 
SetTypesThrottledUntil(ModelTypeSet types,base::TimeDelta length,base::TimeTicks now)124 void NudgeTracker::SetTypesThrottledUntil(
125     ModelTypeSet types,
126     base::TimeDelta length,
127     base::TimeTicks now) {
128   for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
129     type_trackers_[it.Get()].ThrottleType(length, now);
130   }
131 }
132 
UpdateTypeThrottlingState(base::TimeTicks now)133 void NudgeTracker::UpdateTypeThrottlingState(base::TimeTicks now) {
134   for (TypeTrackerMap::iterator it = type_trackers_.begin();
135        it != type_trackers_.end(); ++it) {
136     it->second.UpdateThrottleState(now);
137   }
138 }
139 
IsAnyTypeThrottled() const140 bool NudgeTracker::IsAnyTypeThrottled() const {
141   for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
142        it != type_trackers_.end(); ++it) {
143     if (it->second.IsThrottled()) {
144       return true;
145     }
146   }
147   return false;
148 }
149 
IsTypeThrottled(ModelType type) const150 bool NudgeTracker::IsTypeThrottled(ModelType type) const {
151   DCHECK(type_trackers_.find(type) != type_trackers_.end());
152   return type_trackers_.find(type)->second.IsThrottled();
153 }
154 
GetTimeUntilNextUnthrottle(base::TimeTicks now) const155 base::TimeDelta NudgeTracker::GetTimeUntilNextUnthrottle(
156     base::TimeTicks now) const {
157   DCHECK(IsAnyTypeThrottled()) << "This function requires a pending unthrottle";
158   const base::TimeDelta kMaxTimeDelta =
159       base::TimeDelta::FromInternalValue(kint64max);
160 
161   // Return min of GetTimeUntilUnthrottle() values for all IsThrottled() types.
162   base::TimeDelta time_until_next_unthrottle = kMaxTimeDelta;
163   for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
164        it != type_trackers_.end(); ++it) {
165     if (it->second.IsThrottled()) {
166       time_until_next_unthrottle =
167           std::min(time_until_next_unthrottle,
168                    it->second.GetTimeUntilUnthrottle(now));
169     }
170   }
171   DCHECK(kMaxTimeDelta != time_until_next_unthrottle);
172 
173   return time_until_next_unthrottle;
174 }
175 
GetThrottledTypes() const176 ModelTypeSet NudgeTracker::GetThrottledTypes() const {
177   ModelTypeSet result;
178   for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
179        it != type_trackers_.end(); ++it) {
180     if (it->second.IsThrottled()) {
181       result.Put(it->first);
182     }
183   }
184   return result;
185 }
186 
SetLegacyNotificationHint(ModelType type,sync_pb::DataTypeProgressMarker * progress) const187 void NudgeTracker::SetLegacyNotificationHint(
188     ModelType type,
189     sync_pb::DataTypeProgressMarker* progress) const {
190   DCHECK(type_trackers_.find(type) != type_trackers_.end());
191   type_trackers_.find(type)->second.SetLegacyNotificationHint(progress);
192 }
193 
updates_source() const194 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::updates_source()
195     const {
196   return updates_source_;
197 }
198 
FillProtoMessage(ModelType type,sync_pb::GetUpdateTriggers * msg) const199 void NudgeTracker::FillProtoMessage(
200     ModelType type,
201     sync_pb::GetUpdateTriggers* msg) const {
202   DCHECK(type_trackers_.find(type) != type_trackers_.end());
203 
204   // Fill what we can from the global data.
205   msg->set_invalidations_out_of_sync(invalidations_out_of_sync_);
206 
207   // Delegate the type-specific work to the DataTypeTracker class.
208   type_trackers_.find(type)->second.FillGetUpdatesTriggersMessage(msg);
209 }
210 
SetHintBufferSize(size_t size)211 void NudgeTracker::SetHintBufferSize(size_t size) {
212   for (TypeTrackerMap::iterator it = type_trackers_.begin();
213        it != type_trackers_.end(); ++it) {
214     it->second.UpdatePayloadBufferSize(size);
215   }
216 }
217 
218 }  // namespace sessions
219 }  // namespace syncer
220