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