| OLD | NEW |
| (Empty) | |
| 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/notifier/unacked_invalidation_storage.h" |
| 6 |
| 7 #include "base/strings/string_number_conversions.h" |
| 8 #include "sync/internal_api/public/base/ack_handle.h" |
| 9 #include "sync/notifier/object_id_invalidation_map.h" |
| 10 #include "sync/notifier/ordered_invalidation_list.h" |
| 11 #include "sync/notifier/sync_invalidation_listener.h" |
| 12 |
| 13 namespace { |
| 14 |
| 15 const char kSourceKey[] = "source"; |
| 16 const char kNameKey[] = "name"; |
| 17 const char kInvalidationListKey[] = "invalidation-list"; |
| 18 |
| 19 const size_t kBufferSize = |
| 20 syncer::SyncInvalidationListener::kMaxBufferedInvalidations; |
| 21 |
| 22 } // namespace |
| 23 |
| 24 namespace syncer { |
| 25 |
| 26 // static |
| 27 UnackedInvalidationStorage::UnackedInvalidationStorage( |
| 28 invalidation::ObjectId id) |
| 29 : registered_(false), |
| 30 object_id_(id) {} |
| 31 |
| 32 UnackedInvalidationStorage::~UnackedInvalidationStorage() {} |
| 33 |
| 34 void UnackedInvalidationStorage::RecordInvalidation( |
| 35 const Invalidation& invalidation) { |
| 36 OrderedInvalidationList list; |
| 37 list.Insert(invalidation); |
| 38 RecordInvalidations(list); |
| 39 } |
| 40 |
| 41 void UnackedInvalidationStorage::RecordInvalidations( |
| 42 const OrderedInvalidationList& invalidations) { |
| 43 invalidations_.insert(invalidations.begin(), invalidations.end()); |
| 44 Truncate(kBufferSize); |
| 45 } |
| 46 |
| 47 void UnackedInvalidationStorage::UnpackRecordedInvalidations( |
| 48 ObjectIdInvalidationMap* out, |
| 49 WeakHandle<AckHandler> ack_handler) const { |
| 50 for (OrderedInvalidationList::const_iterator it = invalidations_.begin(); |
| 51 it != invalidations_.end(); ++it) { |
| 52 Invalidation inv(*it); |
| 53 inv.SetAckHandler(ack_handler); |
| 54 out->Insert(inv); |
| 55 } |
| 56 } |
| 57 |
| 58 void UnackedInvalidationStorage::Clear() { |
| 59 invalidations_.clear(); |
| 60 } |
| 61 |
| 62 void UnackedInvalidationStorage::SetIsRegistered() { |
| 63 registered_ = true; |
| 64 } |
| 65 |
| 66 void UnackedInvalidationStorage::UnsetIsRegistered() { |
| 67 registered_ = false; |
| 68 Clear(); |
| 69 } |
| 70 |
| 71 // Removes the matching ack handle from the list. |
| 72 void UnackedInvalidationStorage::Acknowledge(const AckHandle& handle) { |
| 73 bool handle_found = false; |
| 74 for (OrderedInvalidationList::const_iterator it = invalidations_.begin(); |
| 75 it != invalidations_.end(); ++it) { |
| 76 if (it->GetAckHandle().Equals(handle)) { |
| 77 invalidations_.erase(it); |
| 78 handle_found = true; |
| 79 break; |
| 80 } |
| 81 } |
| 82 DLOG_IF(WARNING, !handle_found) |
| 83 << "Unrecognized to ack for object " << ObjectIdToString(object_id_); |
| 84 } |
| 85 |
| 86 // Erases the invalidation with matching ack handle from the list. Also creates |
| 87 // an 'UnknownVersion' invalidation with the same ack handle and places it at |
| 88 // the beginning of the list. If an unknown version invalidation currently |
| 89 // exists, it is replaced. |
| 90 void UnackedInvalidationStorage::Drop(const AckHandle& handle) { |
| 91 OrderedInvalidationList::const_iterator it; |
| 92 for (it = invalidations_.begin(); it != invalidations_.end(); ++it) { |
| 93 if (it->GetAckHandle().Equals(handle)) { |
| 94 break; |
| 95 } |
| 96 } |
| 97 if (it == invalidations_.end()) { |
| 98 DLOG(WARNING) << "Unrecognized drop request for object " |
| 99 << ObjectIdToString(object_id_); |
| 100 return; |
| 101 } |
| 102 |
| 103 Invalidation unknown_version = Invalidation::InitFromDroppedInvalidation(*it); |
| 104 invalidations_.erase(it); |
| 105 |
| 106 // If an unknown version is in the list, we remove it so we can replace it. |
| 107 if (!invalidations_.empty() |
| 108 && invalidations_.begin()->IsUnknownVersion()) { |
| 109 invalidations_.erase(invalidations_.begin()); |
| 110 } |
| 111 |
| 112 invalidations_.insert(unknown_version); |
| 113 } |
| 114 |
| 115 scoped_ptr<base::DictionaryValue> UnackedInvalidationStorage::ToValue() const { |
| 116 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue); |
| 117 value->SetString(kSourceKey, base::IntToString(object_id_.source())); |
| 118 value->SetString(kNameKey, object_id_.name()); |
| 119 |
| 120 scoped_ptr<base::ListValue> list_value(new ListValue); |
| 121 for (InvalidationsSet::const_iterator it = invalidations_.begin(); |
| 122 it != invalidations_.end(); ++it) { |
| 123 list_value->Append(it->ToValue().release()); |
| 124 } |
| 125 value->Set(kInvalidationListKey, list_value.release()); |
| 126 |
| 127 return value.Pass(); |
| 128 } |
| 129 |
| 130 bool UnackedInvalidationStorage::ResetListFromValue( |
| 131 const base::ListValue& list) { |
| 132 for (size_t i = 0; i < list.GetSize(); ++i) { |
| 133 Invalidation invalidation; |
| 134 const base::DictionaryValue* dict; |
| 135 if (!list.GetDictionary(i, &dict) || !invalidation.ResetFromValue(*dict)) { |
| 136 DLOG(WARNING) << "Failed to parse invalidation at index " << i; |
| 137 return false; |
| 138 } |
| 139 invalidations_.insert(invalidation); |
| 140 } |
| 141 return true; |
| 142 } |
| 143 |
| 144 bool UnackedInvalidationStorage::ResetFromValue( |
| 145 const base::DictionaryValue& value) { |
| 146 std::string source_str; |
| 147 if (!value.GetString(kSourceKey, &source_str)) { |
| 148 DLOG(WARNING) << "Unable to deserialize source"; |
| 149 return false; |
| 150 } |
| 151 int source = 0; |
| 152 if (!base::StringToInt(source_str, &source)) { |
| 153 DLOG(WARNING) << "Invalid source: " << source_str; |
| 154 return false; |
| 155 } |
| 156 std::string name; |
| 157 if (!value.GetString(kNameKey, &name)) { |
| 158 DLOG(WARNING) << "Unable to deserialize name"; |
| 159 return false; |
| 160 } |
| 161 object_id_ = invalidation::ObjectId(source, name); |
| 162 const base::ListValue* invalidation_list = NULL; |
| 163 if (!value.GetList(kInvalidationListKey, &invalidation_list) |
| 164 || !ResetListFromValue(*invalidation_list)) { |
| 165 // Earlier versions of this class did not set this field, so we don't treat |
| 166 // parsing errors here as a fatal failure. |
| 167 DLOG(WARNING) << "Unable to deserialize invalidation list."; |
| 168 } |
| 169 return true; |
| 170 } |
| 171 |
| 172 const invalidation::ObjectId& UnackedInvalidationStorage::GetObjectId() const { |
| 173 return object_id_; |
| 174 } |
| 175 |
| 176 void UnackedInvalidationStorage::Truncate(size_t max_size) { |
| 177 DCHECK_GT(max_size, 0U); |
| 178 |
| 179 if (invalidations_.size() <= max_size) { |
| 180 return; |
| 181 } |
| 182 |
| 183 while (invalidations_.size() > max_size) { |
| 184 invalidations_.erase(invalidations_.begin()); |
| 185 } |
| 186 |
| 187 // We dropped some invalidations. We remember the fact that an unknown |
| 188 // amount of information has been lost by ensuring this list begins with |
| 189 // an UnknownVersion invalidation. We remove the oldest remaining |
| 190 // invalidation to make room for it. |
| 191 invalidation::ObjectId id = invalidations_.begin()->GetObjectId(); |
| 192 invalidations_.erase(invalidations_.begin()); |
| 193 |
| 194 Invalidation unknown_version = Invalidation::InitUnknownVersion(id); |
| 195 invalidations_.insert(unknown_version); |
| 196 } |
| 197 |
| 198 } // namespace syncer |
| OLD | NEW |