Home | History | Annotate | Download | only in sessions
      1 // Copyright 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/data_type_tracker.h"
      6 
      7 #include "base/logging.h"
      8 #include "sync/internal_api/public/base/invalidation.h"
      9 #include "sync/notifier/single_object_invalidation_set.h"
     10 #include "sync/sessions/nudge_tracker.h"
     11 
     12 namespace syncer {
     13 namespace sessions {
     14 
     15 DataTypeTracker::DataTypeTracker()
     16   : local_nudge_count_(0),
     17     local_refresh_request_count_(0),
     18     local_payload_overflow_(false),
     19     server_payload_overflow_(false),
     20     payload_buffer_size_(NudgeTracker::kDefaultMaxPayloadsPerType) { }
     21 
     22 DataTypeTracker::~DataTypeTracker() { }
     23 
     24 void DataTypeTracker::RecordLocalChange() {
     25   local_nudge_count_++;
     26 }
     27 
     28 void DataTypeTracker::RecordLocalRefreshRequest() {
     29   local_refresh_request_count_++;
     30 }
     31 
     32 void DataTypeTracker::RecordRemoteInvalidations(
     33     const SingleObjectInvalidationSet& invalidations) {
     34   for (SingleObjectInvalidationSet::const_iterator it =
     35        invalidations.begin(); it != invalidations.end(); ++it) {
     36     if (it->is_unknown_version()) {
     37       server_payload_overflow_ = true;
     38     } else {
     39       pending_payloads_.push_back(it->payload());
     40       if (pending_payloads_.size() > payload_buffer_size_) {
     41         // Drop the oldest payload if we've overflowed.
     42         pending_payloads_.pop_front();
     43         local_payload_overflow_ = true;
     44       }
     45     }
     46   }
     47 }
     48 
     49 void DataTypeTracker::RecordSuccessfulSyncCycle() {
     50   // If we were throttled, then we would have been excluded from this cycle's
     51   // GetUpdates and Commit actions.  Our state remains unchanged.
     52   if (IsThrottled())
     53     return;
     54 
     55   local_nudge_count_ = 0;
     56   local_refresh_request_count_ = 0;
     57   pending_payloads_.clear();
     58   local_payload_overflow_ = false;
     59   server_payload_overflow_ = false;
     60 }
     61 
     62 // This limit will take effect on all future invalidations received.
     63 void DataTypeTracker::UpdatePayloadBufferSize(size_t new_size) {
     64   payload_buffer_size_ = new_size;
     65 }
     66 
     67 bool DataTypeTracker::IsSyncRequired() const {
     68   return !IsThrottled() &&
     69       (local_nudge_count_ > 0 ||
     70        local_refresh_request_count_ > 0 ||
     71        HasPendingInvalidation() ||
     72        local_payload_overflow_ ||
     73        server_payload_overflow_);
     74 }
     75 
     76 bool DataTypeTracker::IsGetUpdatesRequired() const {
     77   return !IsThrottled() &&
     78       (local_refresh_request_count_ > 0 ||
     79        HasPendingInvalidation() ||
     80        local_payload_overflow_ ||
     81        server_payload_overflow_);
     82 }
     83 
     84 bool DataTypeTracker::HasLocalChangePending() const {
     85   return local_nudge_count_ > 0;
     86 }
     87 
     88 bool DataTypeTracker::HasPendingInvalidation() const {
     89   return !pending_payloads_.empty();
     90 }
     91 
     92 std::string DataTypeTracker::GetMostRecentInvalidationPayload() const {
     93   return pending_payloads_.back();
     94 }
     95 
     96 void DataTypeTracker::SetLegacyNotificationHint(
     97     sync_pb::DataTypeProgressMarker* progress) const {
     98   DCHECK(!IsThrottled())
     99       << "We should not make requests if the type is throttled.";
    100 
    101   if (HasPendingInvalidation()) {
    102     // The old-style source info can contain only one hint per type.  We grab
    103     // the most recent, to mimic the old coalescing behaviour.
    104     progress->set_notification_hint(GetMostRecentInvalidationPayload());
    105   } else if (HasLocalChangePending()) {
    106     // The old-style source info sent up an empty string (as opposed to
    107     // nothing at all) when the type was locally nudged, but had not received
    108     // any invalidations.
    109     progress->set_notification_hint("");
    110   }
    111 }
    112 
    113 void DataTypeTracker::FillGetUpdatesTriggersMessage(
    114     sync_pb::GetUpdateTriggers* msg) const {
    115   // Fill the list of payloads, if applicable.  The payloads must be ordered
    116   // oldest to newest, so we insert them in the same order as we've been storing
    117   // them internally.
    118   for (PayloadList::const_iterator payload_it = pending_payloads_.begin();
    119        payload_it != pending_payloads_.end(); ++payload_it) {
    120     msg->add_notification_hint(*payload_it);
    121   }
    122 
    123   msg->set_client_dropped_hints(local_payload_overflow_);
    124   msg->set_local_modification_nudges(local_nudge_count_);
    125   msg->set_datatype_refresh_nudges(local_refresh_request_count_);
    126 
    127   // TODO(rlarocque): Support Tango trickles.  See crbug.com/223437.
    128   // msg->set_server_dropped_hints(server_payload_oveflow_);
    129 }
    130 
    131 bool DataTypeTracker::IsThrottled() const {
    132   return !unthrottle_time_.is_null();
    133 }
    134 
    135 base::TimeDelta DataTypeTracker::GetTimeUntilUnthrottle(
    136     base::TimeTicks now) const {
    137   if (!IsThrottled()) {
    138     NOTREACHED();
    139     return base::TimeDelta::FromSeconds(0);
    140   }
    141   return std::max(base::TimeDelta::FromSeconds(0),
    142                   unthrottle_time_ - now);
    143 }
    144 
    145 void DataTypeTracker::ThrottleType(base::TimeDelta duration,
    146                                       base::TimeTicks now) {
    147   unthrottle_time_ = std::max(unthrottle_time_, now + duration);
    148 }
    149 
    150 void DataTypeTracker::UpdateThrottleState(base::TimeTicks now) {
    151   if (now >= unthrottle_time_) {
    152     unthrottle_time_ = base::TimeTicks();
    153   }
    154 }
    155 
    156 }  // namespace sessions
    157 }  // namespace syncer
    158