| 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 |