1 // Copyright 2014 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.
5 #include "components/invalidation/impl/unacked_invalidation_set.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "components/invalidation/public/ack_handle.h"
9 #include "components/invalidation/public/object_id_invalidation_map.h"
13 const char kSourceKey
[] = "source";
14 const char kNameKey
[] = "name";
15 const char kInvalidationListKey
[] = "invalidation-list";
21 const size_t UnackedInvalidationSet::kMaxBufferedInvalidations
= 5;
24 UnackedInvalidationSet::UnackedInvalidationSet(
25 invalidation::ObjectId id
)
29 UnackedInvalidationSet::UnackedInvalidationSet(
30 const UnackedInvalidationSet
& other
)
31 : registered_(other
.registered_
),
32 object_id_(other
.object_id_
),
33 invalidations_(other
.invalidations_
) {
36 UnackedInvalidationSet::~UnackedInvalidationSet() {}
38 const invalidation::ObjectId
& UnackedInvalidationSet::object_id() const {
42 void UnackedInvalidationSet::Add(
43 const Invalidation
& invalidation
) {
44 SingleObjectInvalidationSet set
;
45 set
.Insert(invalidation
);
48 Truncate(kMaxBufferedInvalidations
);
51 void UnackedInvalidationSet::AddSet(
52 const SingleObjectInvalidationSet
& invalidations
) {
53 invalidations_
.insert(invalidations
.begin(), invalidations
.end());
55 Truncate(kMaxBufferedInvalidations
);
58 void UnackedInvalidationSet::ExportInvalidations(
59 base::WeakPtr
<AckHandler
> ack_handler
,
60 scoped_refptr
<base::SingleThreadTaskRunner
> ack_handler_task_runner
,
61 ObjectIdInvalidationMap
* out
) const {
62 for (SingleObjectInvalidationSet::const_iterator it
= invalidations_
.begin();
63 it
!= invalidations_
.end(); ++it
) {
64 // Copy the invalidation and set the copy's ack_handler.
65 Invalidation
inv(*it
);
66 inv
.SetAckHandler(ack_handler
, ack_handler_task_runner
);
71 void UnackedInvalidationSet::Clear() {
72 invalidations_
.clear();
75 void UnackedInvalidationSet::SetHandlerIsRegistered() {
79 void UnackedInvalidationSet::SetHandlerIsUnregistered() {
81 Truncate(kMaxBufferedInvalidations
);
84 // Removes the matching ack handle from the list.
85 void UnackedInvalidationSet::Acknowledge(const AckHandle
& handle
) {
86 bool handle_found
= false;
87 for (SingleObjectInvalidationSet::const_iterator it
= invalidations_
.begin();
88 it
!= invalidations_
.end(); ++it
) {
89 if (it
->ack_handle().Equals(handle
)) {
90 invalidations_
.erase(*it
);
95 DLOG_IF(WARNING
, !handle_found
)
96 << "Unrecognized to ack for object " << ObjectIdToString(object_id_
);
97 (void)handle_found
; // Silence unused variable warning in release builds.
100 // Erase the invalidation with matching ack handle from the list. Also creates
101 // an 'UnknownVersion' invalidation with the same ack handle and places it at
102 // the beginning of the list. If an unknown version invalidation currently
103 // exists, it is replaced.
104 void UnackedInvalidationSet::Drop(const AckHandle
& handle
) {
105 SingleObjectInvalidationSet::const_iterator it
;
106 for (it
= invalidations_
.begin(); it
!= invalidations_
.end(); ++it
) {
107 if (it
->ack_handle().Equals(handle
)) {
111 if (it
== invalidations_
.end()) {
112 DLOG(WARNING
) << "Unrecognized drop request for object "
113 << ObjectIdToString(object_id_
);
117 Invalidation unknown_version
= Invalidation::InitFromDroppedInvalidation(*it
);
118 invalidations_
.erase(*it
);
120 // If an unknown version is in the list, we remove it so we can replace it.
121 if (!invalidations_
.empty() && invalidations_
.begin()->is_unknown_version()) {
122 invalidations_
.erase(*invalidations_
.begin());
125 invalidations_
.insert(unknown_version
);
128 scoped_ptr
<base::DictionaryValue
> UnackedInvalidationSet::ToValue() const {
129 scoped_ptr
<base::DictionaryValue
> value(new base::DictionaryValue
);
130 value
->SetString(kSourceKey
, base::IntToString(object_id_
.source()));
131 value
->SetString(kNameKey
, object_id_
.name());
133 scoped_ptr
<base::ListValue
> list_value(new base::ListValue
);
134 for (InvalidationsSet::const_iterator it
= invalidations_
.begin();
135 it
!= invalidations_
.end(); ++it
) {
136 list_value
->Append(it
->ToValue().release());
138 value
->Set(kInvalidationListKey
, list_value
.release());
143 bool UnackedInvalidationSet::ResetFromValue(
144 const base::DictionaryValue
& value
) {
145 std::string source_str
;
146 if (!value
.GetString(kSourceKey
, &source_str
)) {
147 DLOG(WARNING
) << "Unable to deserialize source";
151 if (!base::StringToInt(source_str
, &source
)) {
152 DLOG(WARNING
) << "Invalid source: " << source_str
;
156 if (!value
.GetString(kNameKey
, &name
)) {
157 DLOG(WARNING
) << "Unable to deserialize name";
160 object_id_
= invalidation::ObjectId(source
, name
);
161 const base::ListValue
* invalidation_list
= NULL
;
162 if (!value
.GetList(kInvalidationListKey
, &invalidation_list
)
163 || !ResetListFromValue(*invalidation_list
)) {
164 // Earlier versions of this class did not set this field, so we don't treat
165 // parsing errors here as a fatal failure.
166 DLOG(WARNING
) << "Unable to deserialize invalidation list.";
171 bool UnackedInvalidationSet::ResetListFromValue(
172 const base::ListValue
& list
) {
173 for (size_t i
= 0; i
< list
.GetSize(); ++i
) {
174 const base::DictionaryValue
* dict
;
175 if (!list
.GetDictionary(i
, &dict
)) {
176 DLOG(WARNING
) << "Failed to get invalidation dictionary at index " << i
;
179 scoped_ptr
<Invalidation
> invalidation
= Invalidation::InitFromValue(*dict
);
181 DLOG(WARNING
) << "Failed to parse invalidation at index " << i
;
184 invalidations_
.insert(*invalidation
.get());
189 void UnackedInvalidationSet::Truncate(size_t max_size
) {
190 DCHECK_GT(max_size
, 0U);
192 if (invalidations_
.size() <= max_size
) {
196 while (invalidations_
.size() > max_size
) {
197 invalidations_
.erase(*invalidations_
.begin());
200 // We dropped some invalidations. We remember the fact that an unknown
201 // amount of information has been lost by ensuring this list begins with
202 // an UnknownVersion invalidation. We remove the oldest remaining
203 // invalidation to make room for it.
204 invalidation::ObjectId id
= invalidations_
.begin()->object_id();
205 invalidations_
.erase(*invalidations_
.begin());
207 Invalidation unknown_version
= Invalidation::InitUnknownVersion(id
);
208 invalidations_
.insert(unknown_version
);
211 } // namespace syncer