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/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