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