Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / sync / sessions / data_type_tracker.cc
blob8103c003db710c440f1afca37abbc4e1c22ef9e2
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.
5 #include "sync/sessions/data_type_tracker.h"
7 #include "base/logging.h"
8 #include "sync/internal_api/public/base/invalidation_interface.h"
9 #include "sync/sessions/nudge_tracker.h"
11 namespace syncer {
12 namespace sessions {
14 DataTypeTracker::DataTypeTracker()
15 : local_nudge_count_(0),
16 local_refresh_request_count_(0),
17 payload_buffer_size_(NudgeTracker::kDefaultMaxPayloadsPerType),
18 initial_sync_required_(false),
19 sync_required_to_resolve_conflict_(false) {
22 DataTypeTracker::~DataTypeTracker() { }
24 base::TimeDelta DataTypeTracker::RecordLocalChange() {
25 local_nudge_count_++;
26 return nudge_delay_;
29 void DataTypeTracker::RecordLocalRefreshRequest() {
30 local_refresh_request_count_++;
33 void DataTypeTracker::RecordRemoteInvalidation(
34 scoped_ptr<InvalidationInterface> incoming) {
35 DCHECK(incoming);
37 // Merge the incoming invalidation into our list of pending invalidations.
39 // We won't use STL algorithms here because our concept of equality doesn't
40 // quite fit the expectations of set_intersection. In particular, two
41 // invalidations can be equal according to the SingleObjectInvalidationSet's
42 // rules (ie. have equal versions), but still have different AckHandle values
43 // and need to be acknowledged separately.
45 // The invalidations service can only track one outsanding invalidation per
46 // type and version, so the acknowledgement here should be redundant. We'll
47 // acknowledge them anyway since it should do no harm, and makes this code a
48 // bit easier to test.
50 // Overlaps should be extremely rare for most invalidations. They can happen
51 // for unknown version invalidations, though.
53 ScopedVector<InvalidationInterface>::iterator it =
54 pending_invalidations_.begin();
56 // Find the lower bound.
57 while (it != pending_invalidations_.end() &&
58 InvalidationInterface::LessThanByVersion(**it, *incoming)) {
59 it++;
62 if (it != pending_invalidations_.end() &&
63 !InvalidationInterface::LessThanByVersion(*incoming, **it) &&
64 !InvalidationInterface::LessThanByVersion(**it, *incoming)) {
65 // Incoming overlaps with existing. Either both are unknown versions
66 // (likely) or these two have the same version number (very unlikely).
67 // Acknowledge and overwrite existing.
69 // Insert before the existing and get iterator to inserted.
70 ScopedVector<InvalidationInterface>::iterator it2 =
71 pending_invalidations_.insert(it, incoming.release());
73 // Increment that iterator to the old one, then acknowledge and remove it.
74 ++it2;
75 (*it2)->Acknowledge();
76 pending_invalidations_.erase(it2);
77 } else {
78 // The incoming has a version not in the pending_invalidations_ list.
79 // Add it to the list at the proper position.
80 pending_invalidations_.insert(it, incoming.release());
83 // The incoming invalidation may have caused us to exceed our buffer size.
84 // Trim some items from our list, if necessary.
85 while (pending_invalidations_.size() > payload_buffer_size_) {
86 last_dropped_invalidation_.reset(pending_invalidations_.front());
87 last_dropped_invalidation_->Drop();
88 pending_invalidations_.weak_erase(pending_invalidations_.begin());
92 void DataTypeTracker::RecordInitialSyncRequired() {
93 initial_sync_required_ = true;
96 void DataTypeTracker::RecordCommitConflict() {
97 sync_required_to_resolve_conflict_ = true;
100 void DataTypeTracker::RecordSuccessfulSyncCycle() {
101 // If we were throttled, then we would have been excluded from this cycle's
102 // GetUpdates and Commit actions. Our state remains unchanged.
103 if (IsThrottled())
104 return;
106 local_nudge_count_ = 0;
107 local_refresh_request_count_ = 0;
109 // TODO(rlarocque): If we want this to be correct even if we should happen to
110 // crash before writing all our state, we should wait until the results of
111 // this sync cycle have been written to disk before updating the invalidations
112 // state. See crbug.com/324996.
113 for (ScopedVector<InvalidationInterface>::const_iterator it =
114 pending_invalidations_.begin();
115 it != pending_invalidations_.end();
116 ++it) {
117 (*it)->Acknowledge();
119 pending_invalidations_.clear();
121 if (last_dropped_invalidation_) {
122 last_dropped_invalidation_->Acknowledge();
123 last_dropped_invalidation_.reset();
126 initial_sync_required_ = false;
127 sync_required_to_resolve_conflict_ = false;
130 // This limit will take effect on all future invalidations received.
131 void DataTypeTracker::UpdatePayloadBufferSize(size_t new_size) {
132 payload_buffer_size_ = new_size;
135 bool DataTypeTracker::IsSyncRequired() const {
136 return !IsThrottled() && (HasLocalChangePending() || IsGetUpdatesRequired());
139 bool DataTypeTracker::IsGetUpdatesRequired() const {
140 return !IsThrottled() &&
141 (HasRefreshRequestPending() || HasPendingInvalidation() ||
142 IsInitialSyncRequired() || IsSyncRequiredToResolveConflict());
145 bool DataTypeTracker::HasLocalChangePending() const {
146 return local_nudge_count_ > 0;
149 bool DataTypeTracker::HasRefreshRequestPending() const {
150 return local_refresh_request_count_ > 0;
153 bool DataTypeTracker::HasPendingInvalidation() const {
154 return !pending_invalidations_.empty() || last_dropped_invalidation_;
157 bool DataTypeTracker::IsInitialSyncRequired() const {
158 return initial_sync_required_;
161 bool DataTypeTracker::IsSyncRequiredToResolveConflict() const {
162 return sync_required_to_resolve_conflict_;
165 void DataTypeTracker::SetLegacyNotificationHint(
166 sync_pb::DataTypeProgressMarker* progress) const {
167 DCHECK(!IsThrottled())
168 << "We should not make requests if the type is throttled.";
170 if (!pending_invalidations_.empty() &&
171 !pending_invalidations_.back()->IsUnknownVersion()) {
172 // The old-style source info can contain only one hint per type. We grab
173 // the most recent, to mimic the old coalescing behaviour.
174 progress->set_notification_hint(
175 pending_invalidations_.back()->GetPayload());
176 } else if (HasLocalChangePending()) {
177 // The old-style source info sent up an empty string (as opposed to
178 // nothing at all) when the type was locally nudged, but had not received
179 // any invalidations.
180 progress->set_notification_hint(std::string());
184 void DataTypeTracker::FillGetUpdatesTriggersMessage(
185 sync_pb::GetUpdateTriggers* msg) const {
186 // Fill the list of payloads, if applicable. The payloads must be ordered
187 // oldest to newest, so we insert them in the same order as we've been storing
188 // them internally.
189 for (ScopedVector<InvalidationInterface>::const_iterator it =
190 pending_invalidations_.begin();
191 it != pending_invalidations_.end();
192 ++it) {
193 if (!(*it)->IsUnknownVersion()) {
194 msg->add_notification_hint((*it)->GetPayload());
198 msg->set_server_dropped_hints(
199 !pending_invalidations_.empty() &&
200 (*pending_invalidations_.begin())->IsUnknownVersion());
201 msg->set_client_dropped_hints(last_dropped_invalidation_);
202 msg->set_local_modification_nudges(local_nudge_count_);
203 msg->set_datatype_refresh_nudges(local_refresh_request_count_);
204 msg->set_initial_sync_in_progress(initial_sync_required_);
205 msg->set_sync_for_resolve_conflict_in_progress(
206 sync_required_to_resolve_conflict_);
209 bool DataTypeTracker::IsThrottled() const {
210 return !unthrottle_time_.is_null();
213 base::TimeDelta DataTypeTracker::GetTimeUntilUnthrottle(
214 base::TimeTicks now) const {
215 if (!IsThrottled()) {
216 NOTREACHED();
217 return base::TimeDelta::FromSeconds(0);
219 return std::max(base::TimeDelta::FromSeconds(0),
220 unthrottle_time_ - now);
223 void DataTypeTracker::ThrottleType(base::TimeDelta duration,
224 base::TimeTicks now) {
225 unthrottle_time_ = std::max(unthrottle_time_, now + duration);
228 void DataTypeTracker::UpdateThrottleState(base::TimeTicks now) {
229 if (now >= unthrottle_time_) {
230 unthrottle_time_ = base::TimeTicks();
234 void DataTypeTracker::UpdateLocalNudgeDelay(base::TimeDelta delay) {
235 nudge_delay_ = delay;
238 } // namespace sessions
239 } // namespace syncer