Home | History | Annotate | Download | only in sessions
      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