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 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 30 NudgeTracker::~NudgeTracker() { } 31 32 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 42 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 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 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 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 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 115 void NudgeTracker::OnInvalidationsEnabled() { 116 invalidations_enabled_ = true; 117 } 118 119 void NudgeTracker::OnInvalidationsDisabled() { 120 invalidations_enabled_ = false; 121 invalidations_out_of_sync_ = true; 122 } 123 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 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 140 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 150 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 155 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 176 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 187 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 194 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::updates_source() 195 const { 196 return updates_source_; 197 } 198 199 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 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