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