 Chromium Code Reviews
 Chromium Code Reviews Issue 14963002:
  sync: Report GetUpdate triggers to the server  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 14963002:
  sync: Report GetUpdate triggers to the server  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| Index: sync/sessions/nudge_tracker.cc | 
| diff --git a/sync/sessions/nudge_tracker.cc b/sync/sessions/nudge_tracker.cc | 
| index 714b67d13f14582e427fdf544c40bc44a067dab8..b5ab158b06d332c4822a6547c208403eb83d75b7 100644 | 
| --- a/sync/sessions/nudge_tracker.cc | 
| +++ b/sync/sessions/nudge_tracker.cc | 
| @@ -3,47 +3,189 @@ | 
| // found in the LICENSE file. | 
| #include "sync/sessions/nudge_tracker.h" | 
| + | 
| +#include "sync/internal_api/public/base/invalidation.h" | 
| +#include "sync/internal_api/public/sessions/sync_source_info.h" | 
| #include "sync/protocol/sync.pb.h" | 
| namespace syncer { | 
| namespace sessions { | 
| -NudgeTracker::NudgeTracker() { } | 
| +size_t NudgeTracker::kMaxPayloadsPerType = 10; | 
| 
tim (not reviewing)
2013/05/06 21:29:04
Might this be worth adding to client command as so
 
rlarocque
2013/05/07 18:45:39
I don't see much benefit in fiddling with this kno
 
tim (not reviewing)
2013/05/07 20:34:13
I agree with your logic, but the reason I ask is b
 
rlarocque
2013/05/07 21:50:57
I still don't think it's necessary, but I added it
 | 
| + | 
| +NudgeTracker::NudgeTracker() | 
| + : updates_source_(sync_pb::GetUpdatesCallerInfo::UNKNOWN), | 
| + invalidations_enabled_(false), | 
| + invalidations_out_of_sync_(true) { } | 
| NudgeTracker::~NudgeTracker() { } | 
| -void NudgeTracker::CoalesceSources(const SyncSourceInfo& source) { | 
| - CoalesceStates(source.types, &source_info_.types); | 
| - source_info_.updates_source = source.updates_source; | 
| +bool NudgeTracker::SyncRequired() { | 
| + if (!local_nudge_counts_.empty()) { | 
| + return true; | 
| + } else if (!refresh_requested_counts_.empty()) { | 
| + return true; | 
| + } else if (!payload_list_map_.empty()) { | 
| + return true; | 
| + } else { | 
| + return false; | 
| + } | 
| } | 
| -bool NudgeTracker::IsEmpty() { | 
| - return source_info_.types.empty(); | 
| +void NudgeTracker::RecordSuccessfulSyncCycle() { | 
| + updates_source_ = sync_pb::GetUpdatesCallerInfo::UNKNOWN; | 
| + local_nudge_counts_.clear(); | 
| + refresh_requested_counts_.clear(); | 
| + payload_list_map_.clear(); | 
| + locally_dropped_payload_types_.Clear(); | 
| + server_dropped_payload_types_.Clear(); | 
| + | 
| + // A successful cycle while invalidations are enabled puts us back into sync. | 
| + invalidations_out_of_sync_ = !invalidations_enabled_; | 
| } | 
| -void NudgeTracker::Reset() { | 
| - source_info_ = SyncSourceInfo(); | 
| +void NudgeTracker::RecordLocalChange(ModelTypeSet types) { | 
| + // Don't overwrite an NOTIFICATION or DATATYPE_REFRESH source. The server | 
| + // makes some assumptions about the source; overriding these sources with | 
| + // LOCAL could lead to incorrect behaviour. This is part of the reason why | 
| + // we're deprecating 'source' in favor of 'origin'. | 
| + if (updates_source_ != sync_pb::GetUpdatesCallerInfo::NOTIFICATION | 
| + && updates_source_ != sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH) { | 
| + updates_source_ = sync_pb::GetUpdatesCallerInfo::LOCAL; | 
| + } | 
| + | 
| + for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) { | 
| + local_nudge_counts_[it.Get()]++; | 
| + } | 
| +} | 
| + | 
| +void NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) { | 
| + // Don't overwrite an NOTIFICATION source. The server makes some assumptions | 
| + // about the source. Overriding this source with LOCAL could lead to | 
| + // incorrect behaviour. This is part of the reason why we're deprecating | 
| + // 'source' in favor of 'origin'. | 
| + if (updates_source_ != sync_pb::GetUpdatesCallerInfo::NOTIFICATION) { | 
| + updates_source_ = sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH; | 
| + } | 
| + | 
| + for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) { | 
| + refresh_requested_counts_[it.Get()]++; | 
| + } | 
| +} | 
| + | 
| +void NudgeTracker::RecordRemoteInvalidation( | 
| + const ModelTypeInvalidationMap& invalidation_map) { | 
| + updates_source_ = sync_pb::GetUpdatesCallerInfo::NOTIFICATION; | 
| + | 
| + for (ModelTypeInvalidationMap::const_iterator i = invalidation_map.begin(); | 
| + i != invalidation_map.end(); ++i) { | 
| + const ModelType type = i->first; | 
| + const std::string& payload = i->second.payload; | 
| + | 
| + payload_list_map_[type].push_back(payload); | 
| + | 
| + // Respect the size limits on locally queued invalidation hints. | 
| + if (payload_list_map_[type].size() > kMaxPayloadsPerType) { | 
| + payload_list_map_[type].pop_front(); | 
| + locally_dropped_payload_types_.Put(type); | 
| + } | 
| + } | 
| +} | 
| + | 
| +void NudgeTracker::InvalidationsEnabled() { | 
| + invalidations_enabled_ = true; | 
| +} | 
| + | 
| +void NudgeTracker::InvalidationsDisabled() { | 
| + invalidations_enabled_ = false; | 
| + invalidations_out_of_sync_ = true; | 
| +} | 
| + | 
| +SyncSourceInfo NudgeTracker::source_info() const { | 
| 
tim (not reviewing)
2013/05/06 21:29:04
This isn't such a trivial method.  GetSourceInfo()
 
rlarocque
2013/05/07 18:45:39
Done.
 | 
| + // The old-style source added an empty hint for all locally nudge types. | 
| + // This will be overwritten with the proper hint for any types that were both | 
| + // locally nudged and invalidated. | 
| + ModelTypeSet nudged_types; | 
| + for (NudgeMap::const_iterator it = local_nudge_counts_.begin(); | 
| + it != local_nudge_counts_.end(); ++it) { | 
| + nudged_types.Put(it->first); | 
| + } | 
| + ModelTypeInvalidationMap invalidation_map = | 
| + ModelTypeSetToInvalidationMap(nudged_types, ""); | 
| 
tim (not reviewing)
2013/05/06 21:29:04
prefer std::string() to "" for efficiency & explic
 
rlarocque
2013/05/07 18:45:39
Done.
 | 
| + | 
| + // The old-style source info can contain only one hint per type. We grab the | 
| + // most recent, to mimic the old coalescing behaviour. | 
| + for (PayloadListMap::const_iterator it = payload_list_map_.begin(); | 
| + it != payload_list_map_.end(); ++it) { | 
| + ModelType type = it->first; | 
| + const PayloadList& list = it->second; | 
| + | 
| + if (!list.empty()) { | 
| + Invalidation invalidation; | 
| + invalidation.payload = list.back(); | 
| + if (invalidation_map.find(type) != invalidation_map.end()) { | 
| + invalidation_map[type] = invalidation; | 
| + } else { | 
| + invalidation_map.insert(std::make_pair(type, invalidation)); | 
| + } | 
| + } | 
| + } | 
| + | 
| + return SyncSourceInfo(updates_source_, invalidation_map); | 
| } | 
| -// TODO(rlarocque): This function often reports incorrect results. However, it | 
| -// is compatible with the "classic" behaviour. We would need to make the nudge | 
| -// tracker stop overwriting its own information (ie. fix crbug.com/231693) | 
| -// before we could even try to report correct results. The main issue is that | 
| -// an notifications and local modifications nudges may overlap with each other | 
| -// in sych a way that we lose track of which types were or were not locally | 
| -// modified. | 
| ModelTypeSet NudgeTracker::GetLocallyModifiedTypes() const { | 
| - ModelTypeSet locally_modified; | 
| + ModelTypeSet nudged_types; | 
| + for (NudgeMap::const_iterator it = local_nudge_counts_.begin(); | 
| + it != local_nudge_counts_.end(); ++it) { | 
| + nudged_types.Put(it->first); | 
| + } | 
| + return nudged_types; | 
| +} | 
| + | 
| +sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::updates_source() | 
| + const { | 
| + return updates_source_; | 
| +} | 
| + | 
| +void NudgeTracker::FillProtoMessage( | 
| + ModelType type, | 
| + sync_pb::GetUpdateTriggers* msg) const { | 
| + // Fill the list of payloads, if applicable. The payloads must be ordered | 
| + // oldest to newest, so we insert them in the same order as we've been storing | 
| + // them internally. | 
| + PayloadListMap::const_iterator type_it = payload_list_map_.find(type); | 
| + if (type_it != payload_list_map_.end()) { | 
| + const PayloadList& payload_list = type_it->second; | 
| + for (PayloadList::const_iterator payload_it = payload_list.begin(); | 
| + payload_it != payload_list.end(); ++payload_it) { | 
| + msg->add_notification_hint(*payload_it); | 
| + } | 
| + } | 
| + | 
| + // TODO(rlarocque): Support Tango trickles. See crbug.com/223437. | 
| + // msg->set_server_dropped_hints(server_dropped_payload_types_.Has(type)); | 
| + | 
| + msg->set_client_dropped_hints(locally_dropped_payload_types_.Has(type)); | 
| + msg->set_invalidations_out_of_sync(invalidations_out_of_sync_); | 
| - if (source_info_.updates_source != sync_pb::GetUpdatesCallerInfo::LOCAL) { | 
| - return locally_modified; | 
| + { | 
| + NudgeMap::const_iterator it = local_nudge_counts_.find(type); | 
| + if (it == local_nudge_counts_.end()) { | 
| + msg->set_local_modification_nudges(0); | 
| + } else { | 
| + msg->set_local_modification_nudges(it->second); | 
| + } | 
| } | 
| - for (ModelTypeInvalidationMap::const_iterator i = source_info_.types.begin(); | 
| - i != source_info().types.end(); ++i) { | 
| - locally_modified.Put(i->first); | 
| + { | 
| + NudgeMap::const_iterator it = refresh_requested_counts_.find(type); | 
| + if (it == refresh_requested_counts_.end()) { | 
| + msg->set_datatype_refresh_nudges(0); | 
| + } else { | 
| + msg->set_datatype_refresh_nudges(it->second); | 
| + } | 
| } | 
| - return locally_modified; | 
| } | 
| } // namespace sessions |