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