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 std::list<scoped_ptr<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::LessThan(**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::LessThan(*incoming, **it) && |
| 61 !InvalidationInterface::LessThan(**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 (*it)->Acknowledge(); |
| 66 it->swap(incoming); |
| 67 incoming.reset(); |
| 68 } else { |
| 69 // The incoming has a version not in the pending_invalidations_ list. |
| 70 // Add it to the list at the proper position. |
| 71 pending_invalidations_.insert(it, incoming.Pass()); |
| 72 } |
| 73 |
| 74 // The incoming invalidation may have caused us to exceed our buffer size. |
95 // Trim some items from our list, if necessary. | 75 // Trim some items from our list, if necessary. |
96 while (pending_invalidations_.GetSize() > payload_buffer_size_) { | 76 while (pending_invalidations_.size() > payload_buffer_size_) { |
97 pending_invalidations_.begin()->Drop(&drop_tracker_); | 77 last_dropped_invalidation_.reset(pending_invalidations_.front().release()); |
98 pending_invalidations_.Erase(pending_invalidations_.begin()); | 78 last_dropped_invalidation_->Drop(); |
| 79 pending_invalidations_.pop_front(); |
99 } | 80 } |
100 } | 81 } |
101 | 82 |
102 void DataTypeTracker::RecordSuccessfulSyncCycle() { | 83 void DataTypeTracker::RecordSuccessfulSyncCycle() { |
103 // If we were throttled, then we would have been excluded from this cycle's | 84 // If we were throttled, then we would have been excluded from this cycle's |
104 // GetUpdates and Commit actions. Our state remains unchanged. | 85 // GetUpdates and Commit actions. Our state remains unchanged. |
105 if (IsThrottled()) | 86 if (IsThrottled()) |
106 return; | 87 return; |
107 | 88 |
108 local_nudge_count_ = 0; | 89 local_nudge_count_ = 0; |
109 local_refresh_request_count_ = 0; | 90 local_refresh_request_count_ = 0; |
110 | 91 |
111 // TODO(rlarocque): If we want this to be correct even if we should happen to | 92 // 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 | 93 // 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 | 94 // this sync cycle have been written to disk before updating the invalidations |
114 // state. See crbug.com/324996. | 95 // state. See crbug.com/324996. |
115 for (SingleObjectInvalidationSet::const_iterator it = | 96 for (std::list<scoped_ptr<InvalidationInterface> >::const_iterator it = |
116 pending_invalidations_.begin(); | 97 pending_invalidations_.begin(); |
117 it != pending_invalidations_.end(); ++it) { | 98 it != pending_invalidations_.end(); |
118 it->Acknowledge(); | 99 ++it) { |
| 100 (*it)->Acknowledge(); |
119 } | 101 } |
120 pending_invalidations_.Clear(); | 102 pending_invalidations_.clear(); |
121 | 103 |
122 if (drop_tracker_.IsRecoveringFromDropEvent()) { | 104 if (last_dropped_invalidation_) { |
123 drop_tracker_.RecordRecoveryFromDropEvent(); | 105 last_dropped_invalidation_->Acknowledge(); |
| 106 last_dropped_invalidation_.reset(); |
124 } | 107 } |
125 } | 108 } |
126 | 109 |
127 // This limit will take effect on all future invalidations received. | 110 // This limit will take effect on all future invalidations received. |
128 void DataTypeTracker::UpdatePayloadBufferSize(size_t new_size) { | 111 void DataTypeTracker::UpdatePayloadBufferSize(size_t new_size) { |
129 payload_buffer_size_ = new_size; | 112 payload_buffer_size_ = new_size; |
130 } | 113 } |
131 | 114 |
132 bool DataTypeTracker::IsSyncRequired() const { | 115 bool DataTypeTracker::IsSyncRequired() const { |
133 return !IsThrottled() && (HasLocalChangePending() || IsGetUpdatesRequired()); | 116 return !IsThrottled() && (HasLocalChangePending() || IsGetUpdatesRequired()); |
134 } | 117 } |
135 | 118 |
136 bool DataTypeTracker::IsGetUpdatesRequired() const { | 119 bool DataTypeTracker::IsGetUpdatesRequired() const { |
137 return !IsThrottled() && | 120 return !IsThrottled() && |
138 (HasRefreshRequestPending() || HasPendingInvalidation()); | 121 (HasRefreshRequestPending() || HasPendingInvalidation()); |
139 } | 122 } |
140 | 123 |
141 bool DataTypeTracker::HasLocalChangePending() const { | 124 bool DataTypeTracker::HasLocalChangePending() const { |
142 return local_nudge_count_ > 0; | 125 return local_nudge_count_ > 0; |
143 } | 126 } |
144 | 127 |
145 bool DataTypeTracker::HasRefreshRequestPending() const { | 128 bool DataTypeTracker::HasRefreshRequestPending() const { |
146 return local_refresh_request_count_ > 0; | 129 return local_refresh_request_count_ > 0; |
147 } | 130 } |
148 | 131 |
149 bool DataTypeTracker::HasPendingInvalidation() const { | 132 bool DataTypeTracker::HasPendingInvalidation() const { |
150 return !pending_invalidations_.IsEmpty() | 133 return !pending_invalidations_.empty() || last_dropped_invalidation_; |
151 || drop_tracker_.IsRecoveringFromDropEvent(); | |
152 } | 134 } |
153 | 135 |
154 void DataTypeTracker::SetLegacyNotificationHint( | 136 void DataTypeTracker::SetLegacyNotificationHint( |
155 sync_pb::DataTypeProgressMarker* progress) const { | 137 sync_pb::DataTypeProgressMarker* progress) const { |
156 DCHECK(!IsThrottled()) | 138 DCHECK(!IsThrottled()) |
157 << "We should not make requests if the type is throttled."; | 139 << "We should not make requests if the type is throttled."; |
158 | 140 |
159 if (!pending_invalidations_.IsEmpty() && | 141 if (!pending_invalidations_.empty() && |
160 !pending_invalidations_.back().is_unknown_version()) { | 142 !pending_invalidations_.back()->IsUnknownVersion()) { |
161 // The old-style source info can contain only one hint per type. We grab | 143 // The old-style source info can contain only one hint per type. We grab |
162 // the most recent, to mimic the old coalescing behaviour. | 144 // the most recent, to mimic the old coalescing behaviour. |
163 progress->set_notification_hint(pending_invalidations_.back().payload()); | 145 progress->set_notification_hint( |
| 146 pending_invalidations_.back()->GetPayload()); |
164 } else if (HasLocalChangePending()) { | 147 } else if (HasLocalChangePending()) { |
165 // The old-style source info sent up an empty string (as opposed to | 148 // 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 | 149 // nothing at all) when the type was locally nudged, but had not received |
167 // any invalidations. | 150 // any invalidations. |
168 progress->set_notification_hint(""); | 151 progress->set_notification_hint(std::string()); |
169 } | 152 } |
170 } | 153 } |
171 | 154 |
172 void DataTypeTracker::FillGetUpdatesTriggersMessage( | 155 void DataTypeTracker::FillGetUpdatesTriggersMessage( |
173 sync_pb::GetUpdateTriggers* msg) const { | 156 sync_pb::GetUpdateTriggers* msg) const { |
174 // Fill the list of payloads, if applicable. The payloads must be ordered | 157 // 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 | 158 // oldest to newest, so we insert them in the same order as we've been storing |
176 // them internally. | 159 // them internally. |
177 for (SingleObjectInvalidationSet::const_iterator it = | 160 for (std::list<scoped_ptr<InvalidationInterface> >::const_iterator it = |
178 pending_invalidations_.begin(); | 161 pending_invalidations_.begin(); |
179 it != pending_invalidations_.end(); ++it) { | 162 it != pending_invalidations_.end(); |
180 if (!it->is_unknown_version()) { | 163 ++it) { |
181 msg->add_notification_hint(it->payload()); | 164 if (!(*it)->IsUnknownVersion()) { |
| 165 msg->add_notification_hint((*it)->GetPayload()); |
182 } | 166 } |
183 } | 167 } |
184 | 168 |
185 msg->set_server_dropped_hints( | 169 msg->set_server_dropped_hints( |
186 pending_invalidations_.StartsWithUnknownVersion()); | 170 !pending_invalidations_.empty() && |
187 msg->set_client_dropped_hints(drop_tracker_.IsRecoveringFromDropEvent()); | 171 (*pending_invalidations_.begin())->IsUnknownVersion()); |
| 172 msg->set_client_dropped_hints(last_dropped_invalidation_); |
188 msg->set_local_modification_nudges(local_nudge_count_); | 173 msg->set_local_modification_nudges(local_nudge_count_); |
189 msg->set_datatype_refresh_nudges(local_refresh_request_count_); | 174 msg->set_datatype_refresh_nudges(local_refresh_request_count_); |
190 } | 175 } |
191 | 176 |
192 bool DataTypeTracker::IsThrottled() const { | 177 bool DataTypeTracker::IsThrottled() const { |
193 return !unthrottle_time_.is_null(); | 178 return !unthrottle_time_.is_null(); |
194 } | 179 } |
195 | 180 |
196 base::TimeDelta DataTypeTracker::GetTimeUntilUnthrottle( | 181 base::TimeDelta DataTypeTracker::GetTimeUntilUnthrottle( |
197 base::TimeTicks now) const { | 182 base::TimeTicks now) const { |
(...skipping 11 matching lines...) Expand all Loading... |
209 } | 194 } |
210 | 195 |
211 void DataTypeTracker::UpdateThrottleState(base::TimeTicks now) { | 196 void DataTypeTracker::UpdateThrottleState(base::TimeTicks now) { |
212 if (now >= unthrottle_time_) { | 197 if (now >= unthrottle_time_) { |
213 unthrottle_time_ = base::TimeTicks(); | 198 unthrottle_time_ = base::TimeTicks(); |
214 } | 199 } |
215 } | 200 } |
216 | 201 |
217 } // namespace sessions | 202 } // namespace sessions |
218 } // namespace syncer | 203 } // namespace syncer |
OLD | NEW |