| OLD | NEW |
| 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 : updates_source_(sync_pb::GetUpdatesCallerInfo::UNKNOWN), | 19 : invalidations_enabled_(false), |
| 20 invalidations_enabled_(false), | |
| 21 invalidations_out_of_sync_(true) { | 20 invalidations_out_of_sync_(true) { |
| 22 ModelTypeSet protocol_types = ProtocolTypes(); | 21 ModelTypeSet protocol_types = ProtocolTypes(); |
| 23 // Default initialize all the type trackers. | 22 // Default initialize all the type trackers. |
| 24 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good(); | 23 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good(); |
| 25 it.Inc()) { | 24 it.Inc()) { |
| 26 invalidation::ObjectId id; | 25 invalidation::ObjectId id; |
| 27 if (!RealModelTypeToObjectId(it.Get(), &id)) { | 26 if (!RealModelTypeToObjectId(it.Get(), &id)) { |
| 28 NOTREACHED(); | 27 NOTREACHED(); |
| 29 } else { | 28 } else { |
| 30 type_trackers_.insert(std::make_pair(it.Get(), DataTypeTracker(id))); | 29 type_trackers_.insert(std::make_pair(it.Get(), DataTypeTracker(id))); |
| 31 } | 30 } |
| 32 } | 31 } |
| 33 } | 32 } |
| 34 | 33 |
| 35 NudgeTracker::~NudgeTracker() { } | 34 NudgeTracker::~NudgeTracker() { } |
| 36 | 35 |
| 37 bool NudgeTracker::IsSyncRequired() const { | 36 bool NudgeTracker::IsSyncRequired() const { |
| 37 if (IsRetryRequired()) |
| 38 return true; |
| 39 |
| 38 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); | 40 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); |
| 39 it != type_trackers_.end(); ++it) { | 41 it != type_trackers_.end(); ++it) { |
| 40 if (it->second.IsSyncRequired()) { | 42 if (it->second.IsSyncRequired()) { |
| 41 return true; | 43 return true; |
| 42 } | 44 } |
| 43 } | 45 } |
| 46 |
| 44 return false; | 47 return false; |
| 45 } | 48 } |
| 46 | 49 |
| 47 bool NudgeTracker::IsGetUpdatesRequired() const { | 50 bool NudgeTracker::IsGetUpdatesRequired() const { |
| 48 if (invalidations_out_of_sync_) | 51 if (invalidations_out_of_sync_) |
| 49 return true; | 52 return true; |
| 50 | 53 |
| 51 if (IsRetryRequired()) | 54 if (IsRetryRequired()) |
| 52 return true; | 55 return true; |
| 53 | 56 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 64 if (sync_cycle_start_time_.is_null()) | 67 if (sync_cycle_start_time_.is_null()) |
| 65 return false; | 68 return false; |
| 66 | 69 |
| 67 if (current_retry_time_.is_null()) | 70 if (current_retry_time_.is_null()) |
| 68 return false; | 71 return false; |
| 69 | 72 |
| 70 return current_retry_time_ < sync_cycle_start_time_; | 73 return current_retry_time_ < sync_cycle_start_time_; |
| 71 } | 74 } |
| 72 | 75 |
| 73 void NudgeTracker::RecordSuccessfulSyncCycle() { | 76 void NudgeTracker::RecordSuccessfulSyncCycle() { |
| 74 updates_source_ = sync_pb::GetUpdatesCallerInfo::UNKNOWN; | |
| 75 | |
| 76 // If a retry was required, we've just serviced it. Unset the flag. | 77 // If a retry was required, we've just serviced it. Unset the flag. |
| 77 if (IsRetryRequired()) | 78 if (IsRetryRequired()) |
| 78 current_retry_time_ = base::TimeTicks(); | 79 current_retry_time_ = base::TimeTicks(); |
| 79 | 80 |
| 80 // A successful cycle while invalidations are enabled puts us back into sync. | 81 // A successful cycle while invalidations are enabled puts us back into sync. |
| 81 invalidations_out_of_sync_ = !invalidations_enabled_; | 82 invalidations_out_of_sync_ = !invalidations_enabled_; |
| 82 | 83 |
| 83 for (TypeTrackerMap::iterator it = type_trackers_.begin(); | 84 for (TypeTrackerMap::iterator it = type_trackers_.begin(); |
| 84 it != type_trackers_.end(); ++it) { | 85 it != type_trackers_.end(); ++it) { |
| 85 it->second.RecordSuccessfulSyncCycle(); | 86 it->second.RecordSuccessfulSyncCycle(); |
| 86 } | 87 } |
| 87 } | 88 } |
| 88 | 89 |
| 89 void NudgeTracker::RecordLocalChange(ModelTypeSet types) { | 90 void NudgeTracker::RecordLocalChange(ModelTypeSet types) { |
| 90 // Don't overwrite an NOTIFICATION or DATATYPE_REFRESH source. The server | |
| 91 // makes some assumptions about the source; overriding these sources with | |
| 92 // LOCAL could lead to incorrect behaviour. This is part of the reason why | |
| 93 // we're deprecating 'source' in favor of 'origin'. | |
| 94 if (updates_source_ != sync_pb::GetUpdatesCallerInfo::NOTIFICATION | |
| 95 && updates_source_ != sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH) { | |
| 96 updates_source_ = sync_pb::GetUpdatesCallerInfo::LOCAL; | |
| 97 } | |
| 98 | |
| 99 for (ModelTypeSet::Iterator type_it = types.First(); type_it.Good(); | 91 for (ModelTypeSet::Iterator type_it = types.First(); type_it.Good(); |
| 100 type_it.Inc()) { | 92 type_it.Inc()) { |
| 101 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type_it.Get()); | 93 TypeTrackerMap::iterator tracker_it = type_trackers_.find(type_it.Get()); |
| 102 DCHECK(tracker_it != type_trackers_.end()); | 94 DCHECK(tracker_it != type_trackers_.end()); |
| 103 tracker_it->second.RecordLocalChange(); | 95 tracker_it->second.RecordLocalChange(); |
| 104 } | 96 } |
| 105 } | 97 } |
| 106 | 98 |
| 107 void NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) { | 99 void NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) { |
| 108 // Don't overwrite an NOTIFICATION source. The server makes some assumptions | |
| 109 // about the source. Overriding this source with LOCAL could lead to | |
| 110 // incorrect behaviour. This is part of the reason why we're deprecating | |
| 111 // 'source' in favor of 'origin'. | |
| 112 if (updates_source_ != sync_pb::GetUpdatesCallerInfo::NOTIFICATION) { | |
| 113 updates_source_ = sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH; | |
| 114 } | |
| 115 | |
| 116 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) { | 100 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) { |
| 117 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get()); | 101 TypeTrackerMap::iterator tracker_it = type_trackers_.find(it.Get()); |
| 118 DCHECK(tracker_it != type_trackers_.end()); | 102 DCHECK(tracker_it != type_trackers_.end()); |
| 119 tracker_it->second.RecordLocalRefreshRequest(); | 103 tracker_it->second.RecordLocalRefreshRequest(); |
| 120 } | 104 } |
| 121 } | 105 } |
| 122 | 106 |
| 123 void NudgeTracker::RecordRemoteInvalidation( | 107 void NudgeTracker::RecordRemoteInvalidation( |
| 124 const ObjectIdInvalidationMap& invalidation_map) { | 108 const ObjectIdInvalidationMap& invalidation_map) { |
| 125 updates_source_ = sync_pb::GetUpdatesCallerInfo::NOTIFICATION; | |
| 126 | |
| 127 // Be very careful here. The invalidations acknowledgement system requires a | 109 // Be very careful here. The invalidations acknowledgement system requires a |
| 128 // sort of manual memory management. We'll leak a small amount of memory if | 110 // sort of manual memory management. We'll leak a small amount of memory if |
| 129 // we fail to acknowledge or drop any of these incoming invalidations. | 111 // we fail to acknowledge or drop any of these incoming invalidations. |
| 130 | 112 |
| 131 ObjectIdSet id_set = invalidation_map.GetObjectIds(); | 113 ObjectIdSet id_set = invalidation_map.GetObjectIds(); |
| 132 for (ObjectIdSet::iterator it = id_set.begin(); it != id_set.end(); ++it) { | 114 for (ObjectIdSet::iterator it = id_set.begin(); it != id_set.end(); ++it) { |
| 133 ModelType type; | 115 ModelType type; |
| 134 | 116 |
| 135 // This should never happen. If it does, we'll start to leak memory. | 117 // This should never happen. If it does, we'll start to leak memory. |
| 136 if (!ObjectIdToRealModelType(*it, &type)) { | 118 if (!ObjectIdToRealModelType(*it, &type)) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 return result; | 203 return result; |
| 222 } | 204 } |
| 223 | 205 |
| 224 void NudgeTracker::SetLegacyNotificationHint( | 206 void NudgeTracker::SetLegacyNotificationHint( |
| 225 ModelType type, | 207 ModelType type, |
| 226 sync_pb::DataTypeProgressMarker* progress) const { | 208 sync_pb::DataTypeProgressMarker* progress) const { |
| 227 DCHECK(type_trackers_.find(type) != type_trackers_.end()); | 209 DCHECK(type_trackers_.find(type) != type_trackers_.end()); |
| 228 type_trackers_.find(type)->second.SetLegacyNotificationHint(progress); | 210 type_trackers_.find(type)->second.SetLegacyNotificationHint(progress); |
| 229 } | 211 } |
| 230 | 212 |
| 231 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::updates_source() | 213 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::GetLegacySource() |
| 232 const { | 214 const { |
| 233 return updates_source_; | 215 // There's an order to these sources: NOTIFICATION, DATATYPE_REFRESH, LOCAL, |
| 216 // RETRY. The server makes optimization decisions based on this field, so |
| 217 // it's important to get this right. Setting it wrong could lead to missed |
| 218 // updates. |
| 219 // |
| 220 // This complexity is part of the reason why we're deprecating 'source' in |
| 221 // favor of 'origin'. |
| 222 bool has_invalidation_pending = false; |
| 223 bool has_refresh_request_pending = false; |
| 224 bool has_commit_pending = false; |
| 225 bool has_retry = IsRetryRequired(); |
| 226 |
| 227 for (TypeTrackerMap::const_iterator it = type_trackers_.begin(); |
| 228 it != type_trackers_.end(); ++it) { |
| 229 const DataTypeTracker& tracker = it->second; |
| 230 if (!tracker.IsThrottled() && tracker.HasPendingInvalidation()) { |
| 231 has_invalidation_pending = true; |
| 232 } |
| 233 if (!tracker.IsThrottled() && tracker.HasRefreshRequestPending()) { |
| 234 has_refresh_request_pending = true; |
| 235 } |
| 236 if (!tracker.IsThrottled() && tracker.HasLocalChangePending()) { |
| 237 has_commit_pending = true; |
| 238 } |
| 239 } |
| 240 |
| 241 if (has_invalidation_pending) { |
| 242 return sync_pb::GetUpdatesCallerInfo::NOTIFICATION; |
| 243 } else if (has_refresh_request_pending) { |
| 244 return sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH; |
| 245 } else if (has_commit_pending) { |
| 246 return sync_pb::GetUpdatesCallerInfo::LOCAL; |
| 247 } else if (has_retry) { |
| 248 return sync_pb::GetUpdatesCallerInfo::RETRY; |
| 249 } else { |
| 250 return sync_pb::GetUpdatesCallerInfo::UNKNOWN; |
| 251 } |
| 234 } | 252 } |
| 235 | 253 |
| 236 void NudgeTracker::FillProtoMessage( | 254 void NudgeTracker::FillProtoMessage( |
| 237 ModelType type, | 255 ModelType type, |
| 238 sync_pb::GetUpdateTriggers* msg) const { | 256 sync_pb::GetUpdateTriggers* msg) const { |
| 239 DCHECK(type_trackers_.find(type) != type_trackers_.end()); | 257 DCHECK(type_trackers_.find(type) != type_trackers_.end()); |
| 240 | 258 |
| 241 // Fill what we can from the global data. | 259 // Fill what we can from the global data. |
| 242 msg->set_invalidations_out_of_sync(invalidations_out_of_sync_); | 260 msg->set_invalidations_out_of_sync(invalidations_out_of_sync_); |
| 243 | 261 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 274 it->second.UpdatePayloadBufferSize(size); | 292 it->second.UpdatePayloadBufferSize(size); |
| 275 } | 293 } |
| 276 } | 294 } |
| 277 | 295 |
| 278 void NudgeTracker::SetNextRetryTime(base::TimeTicks retry_time) { | 296 void NudgeTracker::SetNextRetryTime(base::TimeTicks retry_time) { |
| 279 next_retry_time_ = retry_time; | 297 next_retry_time_ = retry_time; |
| 280 } | 298 } |
| 281 | 299 |
| 282 } // namespace sessions | 300 } // namespace sessions |
| 283 } // namespace syncer | 301 } // namespace syncer |
| OLD | NEW |