| Index: sync/notifier/unacked_invalidation_storage.cc
|
| diff --git a/sync/notifier/unacked_invalidation_storage.cc b/sync/notifier/unacked_invalidation_storage.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..33c6cda7384caf9d6a028f784457fe3ead3942a3
|
| --- /dev/null
|
| +++ b/sync/notifier/unacked_invalidation_storage.cc
|
| @@ -0,0 +1,198 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "sync/notifier/unacked_invalidation_storage.h"
|
| +
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "sync/internal_api/public/base/ack_handle.h"
|
| +#include "sync/notifier/object_id_invalidation_map.h"
|
| +#include "sync/notifier/ordered_invalidation_list.h"
|
| +#include "sync/notifier/sync_invalidation_listener.h"
|
| +
|
| +namespace {
|
| +
|
| +const char kSourceKey[] = "source";
|
| +const char kNameKey[] = "name";
|
| +const char kInvalidationListKey[] = "invalidation-list";
|
| +
|
| +const size_t kBufferSize =
|
| + syncer::SyncInvalidationListener::kMaxBufferedInvalidations;
|
| +
|
| +} // namespace
|
| +
|
| +namespace syncer {
|
| +
|
| +// static
|
| +UnackedInvalidationStorage::UnackedInvalidationStorage(
|
| + invalidation::ObjectId id)
|
| + : registered_(false),
|
| + object_id_(id) {}
|
| +
|
| +UnackedInvalidationStorage::~UnackedInvalidationStorage() {}
|
| +
|
| +void UnackedInvalidationStorage::RecordInvalidation(
|
| + const Invalidation& invalidation) {
|
| + OrderedInvalidationList list;
|
| + list.Insert(invalidation);
|
| + RecordInvalidations(list);
|
| +}
|
| +
|
| +void UnackedInvalidationStorage::RecordInvalidations(
|
| + const OrderedInvalidationList& invalidations) {
|
| + invalidations_.insert(invalidations.begin(), invalidations.end());
|
| + Truncate(kBufferSize);
|
| +}
|
| +
|
| +void UnackedInvalidationStorage::UnpackRecordedInvalidations(
|
| + ObjectIdInvalidationMap* out,
|
| + WeakHandle<AckHandler> ack_handler) const {
|
| + for (OrderedInvalidationList::const_iterator it = invalidations_.begin();
|
| + it != invalidations_.end(); ++it) {
|
| + Invalidation inv(*it);
|
| + inv.SetAckHandler(ack_handler);
|
| + out->Insert(inv);
|
| + }
|
| +}
|
| +
|
| +void UnackedInvalidationStorage::Clear() {
|
| + invalidations_.clear();
|
| +}
|
| +
|
| +void UnackedInvalidationStorage::SetIsRegistered() {
|
| + registered_ = true;
|
| +}
|
| +
|
| +void UnackedInvalidationStorage::UnsetIsRegistered() {
|
| + registered_ = false;
|
| + Clear();
|
| +}
|
| +
|
| +// Removes the matching ack handle from the list.
|
| +void UnackedInvalidationStorage::Acknowledge(const AckHandle& handle) {
|
| + bool handle_found = false;
|
| + for (OrderedInvalidationList::const_iterator it = invalidations_.begin();
|
| + it != invalidations_.end(); ++it) {
|
| + if (it->GetAckHandle().Equals(handle)) {
|
| + invalidations_.erase(it);
|
| + handle_found = true;
|
| + break;
|
| + }
|
| + }
|
| + DLOG_IF(WARNING, !handle_found)
|
| + << "Unrecognized to ack for object " << ObjectIdToString(object_id_);
|
| +}
|
| +
|
| +// Erases the invalidation with matching ack handle from the list. Also creates
|
| +// an 'UnknownVersion' invalidation with the same ack handle and places it at
|
| +// the beginning of the list. If an unknown version invalidation currently
|
| +// exists, it is replaced.
|
| +void UnackedInvalidationStorage::Drop(const AckHandle& handle) {
|
| + OrderedInvalidationList::const_iterator it;
|
| + for (it = invalidations_.begin(); it != invalidations_.end(); ++it) {
|
| + if (it->GetAckHandle().Equals(handle)) {
|
| + break;
|
| + }
|
| + }
|
| + if (it == invalidations_.end()) {
|
| + DLOG(WARNING) << "Unrecognized drop request for object "
|
| + << ObjectIdToString(object_id_);
|
| + return;
|
| + }
|
| +
|
| + Invalidation unknown_version = Invalidation::InitFromDroppedInvalidation(*it);
|
| + invalidations_.erase(it);
|
| +
|
| + // If an unknown version is in the list, we remove it so we can replace it.
|
| + if (!invalidations_.empty()
|
| + && invalidations_.begin()->IsUnknownVersion()) {
|
| + invalidations_.erase(invalidations_.begin());
|
| + }
|
| +
|
| + invalidations_.insert(unknown_version);
|
| +}
|
| +
|
| +scoped_ptr<base::DictionaryValue> UnackedInvalidationStorage::ToValue() const {
|
| + scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue);
|
| + value->SetString(kSourceKey, base::IntToString(object_id_.source()));
|
| + value->SetString(kNameKey, object_id_.name());
|
| +
|
| + scoped_ptr<base::ListValue> list_value(new ListValue);
|
| + for (InvalidationsSet::const_iterator it = invalidations_.begin();
|
| + it != invalidations_.end(); ++it) {
|
| + list_value->Append(it->ToValue().release());
|
| + }
|
| + value->Set(kInvalidationListKey, list_value.release());
|
| +
|
| + return value.Pass();
|
| +}
|
| +
|
| +bool UnackedInvalidationStorage::ResetListFromValue(
|
| + const base::ListValue& list) {
|
| + for (size_t i = 0; i < list.GetSize(); ++i) {
|
| + Invalidation invalidation;
|
| + const base::DictionaryValue* dict;
|
| + if (!list.GetDictionary(i, &dict) || !invalidation.ResetFromValue(*dict)) {
|
| + DLOG(WARNING) << "Failed to parse invalidation at index " << i;
|
| + return false;
|
| + }
|
| + invalidations_.insert(invalidation);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool UnackedInvalidationStorage::ResetFromValue(
|
| + const base::DictionaryValue& value) {
|
| + std::string source_str;
|
| + if (!value.GetString(kSourceKey, &source_str)) {
|
| + DLOG(WARNING) << "Unable to deserialize source";
|
| + return false;
|
| + }
|
| + int source = 0;
|
| + if (!base::StringToInt(source_str, &source)) {
|
| + DLOG(WARNING) << "Invalid source: " << source_str;
|
| + return false;
|
| + }
|
| + std::string name;
|
| + if (!value.GetString(kNameKey, &name)) {
|
| + DLOG(WARNING) << "Unable to deserialize name";
|
| + return false;
|
| + }
|
| + object_id_ = invalidation::ObjectId(source, name);
|
| + const base::ListValue* invalidation_list = NULL;
|
| + if (!value.GetList(kInvalidationListKey, &invalidation_list)
|
| + || !ResetListFromValue(*invalidation_list)) {
|
| + // Earlier versions of this class did not set this field, so we don't treat
|
| + // parsing errors here as a fatal failure.
|
| + DLOG(WARNING) << "Unable to deserialize invalidation list.";
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +const invalidation::ObjectId& UnackedInvalidationStorage::GetObjectId() const {
|
| + return object_id_;
|
| +}
|
| +
|
| +void UnackedInvalidationStorage::Truncate(size_t max_size) {
|
| + DCHECK_GT(max_size, 0U);
|
| +
|
| + if (invalidations_.size() <= max_size) {
|
| + return;
|
| + }
|
| +
|
| + while (invalidations_.size() > max_size) {
|
| + invalidations_.erase(invalidations_.begin());
|
| + }
|
| +
|
| + // We dropped some invalidations. We remember the fact that an unknown
|
| + // amount of information has been lost by ensuring this list begins with
|
| + // an UnknownVersion invalidation. We remove the oldest remaining
|
| + // invalidation to make room for it.
|
| + invalidation::ObjectId id = invalidations_.begin()->GetObjectId();
|
| + invalidations_.erase(invalidations_.begin());
|
| +
|
| + Invalidation unknown_version = Invalidation::InitUnknownVersion(id);
|
| + invalidations_.insert(unknown_version);
|
| +}
|
| +
|
| +} // namespace syncer
|
|
|