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