Commit 8eae0d61 authored by Tanja Gornak's avatar Tanja Gornak Committed by Commit Bot

[Tango->FCM] Refactoring. New InvalidatorRegistrar.

This CL creates new InvalidatorRegistrar.
New InvalidatorRegistrar depends on ObjectId as little as possible.

New InvalidatorRegistrar will be used on follow-up CL.
https://chromium-review.googlesource.com/c/chromium/src/+/1194032/5


Bug: 878446, 801985
Change-Id: I9f34d78a1eeb8d28a42ed0e90ee8701fba83192e
Reviewed-on: https://chromium-review.googlesource.com/1193887
Commit-Queue: Tatiana Gornak <melandory@chromium.org>
Reviewed-by: default avatarPavel Yatsuk <pavely@chromium.org>
Cr-Commit-Position: refs/heads/master@{#587728}
parent 1405fd6a
......@@ -23,6 +23,8 @@ static_library("impl") {
"invalidation_switches.h",
"invalidator.cc",
"invalidator.h",
"invalidator_registrar.cc",
"invalidator_registrar.h",
"invalidator_storage.cc",
"invalidator_storage.h",
"mock_ack_handler.cc",
......@@ -168,6 +170,7 @@ source_set("unit_tests") {
"gcm_invalidation_bridge_unittest.cc",
"gcm_network_channel_unittest.cc",
"invalidation_notifier_unittest.cc",
"invalidator_registrar_unittest.cc",
"invalidator_storage_unittest.cc",
"non_blocking_invalidator_unittest.cc",
"object_id_invalidation_map_unittest.cc",
......
// Copyright 2018 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 "components/invalidation/impl/invalidator_registrar.h"
#include <cstddef>
#include <iterator>
#include <utility>
#include "base/logging.h"
#include "components/invalidation/public/object_id_invalidation_map.h"
#include "components/invalidation/public/topic_invalidation_map.h"
namespace syncer {
InvalidatorRegistrar::InvalidatorRegistrar()
: state_(DEFAULT_INVALIDATION_ERROR) {}
InvalidatorRegistrar::~InvalidatorRegistrar() {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(handler_to_topics_map_.empty());
}
void InvalidatorRegistrar::RegisterHandler(InvalidationHandler* handler) {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(handler);
CHECK(!handlers_.HasObserver(handler));
handlers_.AddObserver(handler);
}
bool InvalidatorRegistrar::UpdateRegisteredTopics(InvalidationHandler* handler,
const TopicSet& topics) {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(handler);
CHECK(handlers_.HasObserver(handler));
for (const auto& handler_and_topics : handler_to_topics_map_) {
if (handler_and_topics.first == handler) {
continue;
}
std::vector<Topic> intersection;
std::set_intersection(handler_and_topics.second.begin(),
handler_and_topics.second.end(), topics.begin(),
topics.end(),
std::inserter(intersection, intersection.end()));
if (!intersection.empty()) {
DVLOG(1) << "Duplicate registration: trying to register "
<< *intersection.begin() << " for " << handler
<< " when it's already registered for "
<< handler_and_topics.first;
return false;
}
}
if (topics.empty()) {
handler_to_topics_map_.erase(handler);
} else {
handler_to_topics_map_[handler] = topics;
}
return true;
}
void InvalidatorRegistrar::UnregisterHandler(InvalidationHandler* handler) {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(handler);
CHECK(handlers_.HasObserver(handler));
handlers_.RemoveObserver(handler);
handler_to_topics_map_.erase(handler);
}
TopicSet InvalidatorRegistrar::GetRegisteredTopics(
InvalidationHandler* handler) const {
DCHECK(thread_checker_.CalledOnValidThread());
HandlerTopicsMap::const_iterator lookup =
handler_to_topics_map_.find(handler);
return lookup != handler_to_topics_map_.end() ? lookup->second : TopicSet();
}
TopicSet InvalidatorRegistrar::GetAllRegisteredIds() const {
DCHECK(thread_checker_.CalledOnValidThread());
TopicSet registered_ids;
for (HandlerTopicsMap::const_iterator it = handler_to_topics_map_.begin();
it != handler_to_topics_map_.end(); ++it) {
registered_ids.insert(it->second.begin(), it->second.end());
}
return registered_ids;
}
void InvalidatorRegistrar::DispatchInvalidationsToHandlers(
const TopicInvalidationMap& invalidation_map) {
DCHECK(thread_checker_.CalledOnValidThread());
// If we have no handlers, there's nothing to do.
if (!handlers_.might_have_observers()) {
return;
}
for (const auto& handler_and_topics : handler_to_topics_map_) {
TopicInvalidationMap to_emit =
invalidation_map.GetSubsetWithTopics(handler_and_topics.second);
ObjectIdInvalidationMap object_ids_to_emit;
std::vector<syncer::Invalidation> invalidations;
to_emit.GetAllInvalidations(&invalidations);
for (const auto& invalidation : invalidations) {
object_ids_to_emit.Insert(invalidation);
}
if (!to_emit.Empty()) {
handler_and_topics.first->OnIncomingInvalidation(object_ids_to_emit);
}
}
}
void InvalidatorRegistrar::UpdateInvalidatorState(InvalidatorState state) {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "New invalidator state: " << InvalidatorStateToString(state_)
<< " -> " << InvalidatorStateToString(state);
state_ = state;
for (auto& observer : handlers_)
observer.OnInvalidatorStateChange(state);
}
InvalidatorState InvalidatorRegistrar::GetInvalidatorState() const {
DCHECK(thread_checker_.CalledOnValidThread());
return state_;
}
std::map<std::string, TopicSet>
InvalidatorRegistrar::GetSanitizedHandlersIdsMap() {
DCHECK(thread_checker_.CalledOnValidThread());
std::map<std::string, TopicSet> clean_handlers_to_topics;
for (const auto& handler_and_topics : handler_to_topics_map_)
clean_handlers_to_topics[handler_and_topics.first->GetOwnerName()] =
TopicSet(handler_and_topics.second);
return clean_handlers_to_topics;
}
bool InvalidatorRegistrar::IsHandlerRegisteredForTest(
const InvalidationHandler* handler) const {
DCHECK(thread_checker_.CalledOnValidThread());
return handlers_.HasObserver(handler);
}
void InvalidatorRegistrar::DetachFromThreadForTest() {
DCHECK(thread_checker_.CalledOnValidThread());
thread_checker_.DetachFromThread();
}
} // namespace syncer
// Copyright 2018 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.
#ifndef COMPONENTS_INVALIDATION_IMPL_INVALIDATOR_REGISTRAR_H_
#define COMPONENTS_INVALIDATION_IMPL_INVALIDATOR_REGISTRAR_H_
#include <map>
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
#include "components/invalidation/public/invalidation_export.h"
#include "components/invalidation/public/invalidation_handler.h"
#include "components/invalidation/public/invalidation_util.h"
namespace syncer {
class TopicInvalidationMap;
// A helper class for implementations of the Invalidator interface. It helps
// keep track of registered handlers and which object ID registrations are
// associated with which handlers, so implementors can just reuse the logic
// here to dispatch invalidations and other interesting notifications.
class INVALIDATION_EXPORT InvalidatorRegistrar {
public:
InvalidatorRegistrar();
// It is an error to have registered handlers on destruction.
~InvalidatorRegistrar();
// Starts sending notifications to |handler|. |handler| must not be NULL,
// and it must already be registered.
void RegisterHandler(InvalidationHandler* handler);
// Updates the set of topics associated with |handler|. |handler| must
// not be NULL, and must already be registered. A topic must be registered
// for at most one handler. If topic is already registered function returns
// false.
bool UpdateRegisteredTopics(InvalidationHandler* handler,
const TopicSet& topics) WARN_UNUSED_RESULT;
// Stops sending notifications to |handler|. |handler| must not be NULL, and
// it must already be registered. Note that this doesn't unregister the IDs
// associated with |handler|.
void UnregisterHandler(InvalidationHandler* handler);
TopicSet GetRegisteredTopics(InvalidationHandler* handler) const;
// Returns the set of all IDs that are registered to some handler (even
// handlers that have been unregistered).
TopicSet GetAllRegisteredIds() const;
// Sorts incoming invalidations into a bucket for each handler and then
// dispatches the batched invalidations to the corresponding handler.
// Invalidations for IDs with no corresponding handler are dropped, as are
// invalidations for handlers that are not added.
void DispatchInvalidationsToHandlers(
const TopicInvalidationMap& invalidation_map);
// Updates the invalidator state to the given one and then notifies
// all handlers. Note that the order is important; handlers that
// call GetInvalidatorState() when notified will see the new state.
void UpdateInvalidatorState(InvalidatorState state);
// Returns the current invalidator state. When called from within
// InvalidationHandler::OnInvalidatorStateChange(), this returns the
// updated state.
InvalidatorState GetInvalidatorState() const;
// Gets a new map for the name of invalidator handlers and their
// objects id. This is used by the InvalidatorLogger to be able
// to display every registered handlers and its objectsIds.
std::map<std::string, TopicSet> GetSanitizedHandlersIdsMap();
bool IsHandlerRegisteredForTest(const InvalidationHandler* handler) const;
// Needed for death tests.
void DetachFromThreadForTest();
private:
typedef std::map<InvalidationHandler*, TopicSet> HandlerTopicsMap;
base::ThreadChecker thread_checker_;
base::ObserverList<InvalidationHandler, true>::Unchecked handlers_;
HandlerTopicsMap handler_to_topics_map_;
InvalidatorState state_;
DISALLOW_COPY_AND_ASSIGN(InvalidatorRegistrar);
};
} // namespace syncer
#endif // COMPONENTS_INVALIDATION_IMPL_INVALIDATOR_REGISTRAR_H_
// Copyright 2018 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 "components/invalidation/impl/invalidator_registrar.h"
#include <memory>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/invalidation/impl/fake_invalidation_handler.h"
#include "components/invalidation/impl/invalidator_test_template.h"
#include "components/invalidation/public/topic_invalidation_map.h"
#include "google/cacheinvalidation/types.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
namespace {
// We test DeprecatedInvalidatorRegistrar by wrapping it in an Invalidator and
// running the usual Invalidator tests.
// Thin Invalidator wrapper around DeprecatedInvalidatorRegistrar.
class RegistrarInvalidator : public Invalidator {
public:
RegistrarInvalidator() {}
~RegistrarInvalidator() override {}
InvalidatorRegistrar* GetRegistrar() { return &registrar_; }
// Invalidator implementation.
void RegisterHandler(InvalidationHandler* handler) override {
registrar_.RegisterHandler(handler);
}
bool UpdateRegisteredIds(InvalidationHandler* handler,
const ObjectIdSet& ids) override {
TopicSet topics;
for (const auto& id : ids)
topics.insert(id.name());
return registrar_.UpdateRegisteredTopics(handler, topics);
}
void UnregisterHandler(InvalidationHandler* handler) override {
registrar_.UnregisterHandler(handler);
}
InvalidatorState GetInvalidatorState() const override {
return registrar_.GetInvalidatorState();
}
void UpdateCredentials(const std::string& email,
const std::string& token) override {
// Do nothing.
}
void RequestDetailedStatus(
base::Callback<void(const base::DictionaryValue&)> call) const override {
// Do nothing.
}
private:
InvalidatorRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(RegistrarInvalidator);
};
class RegistrarInvalidatorTestDelegate {
public:
RegistrarInvalidatorTestDelegate() {}
~RegistrarInvalidatorTestDelegate() { DestroyInvalidator(); }
void CreateInvalidator(const std::string& invalidator_client_id,
const std::string& initial_state,
const base::WeakPtr<InvalidationStateTracker>&
invalidation_state_tracker) {
DCHECK(!invalidator_);
invalidator_.reset(new RegistrarInvalidator());
}
RegistrarInvalidator* GetInvalidator() { return invalidator_.get(); }
void DestroyInvalidator() { invalidator_.reset(); }
void WaitForInvalidator() {
// Do nothing.
}
void TriggerOnInvalidatorStateChange(InvalidatorState state) {
invalidator_->GetRegistrar()->UpdateInvalidatorState(state);
}
void TriggerOnIncomingInvalidation(
const ObjectIdInvalidationMap& invalidation_map) {
TopicInvalidationMap topics_map;
std::vector<syncer::Invalidation> invalidations;
invalidation_map.GetAllInvalidations(&invalidations);
for (const auto& invalidation : invalidations) {
topics_map.Insert(invalidation);
}
invalidator_->GetRegistrar()->DispatchInvalidationsToHandlers(topics_map);
}
private:
std::unique_ptr<RegistrarInvalidator> invalidator_;
};
INSTANTIATE_TYPED_TEST_CASE_P(RegistrarInvalidatorTest,
InvalidatorTest,
RegistrarInvalidatorTestDelegate);
} // namespace
} // namespace syncer
......@@ -26,6 +26,8 @@ static_library("public") {
"object_id_invalidation_map.h",
"single_object_invalidation_set.cc",
"single_object_invalidation_set.h",
"topic_invalidation_map.cc",
"topic_invalidation_map.h",
]
public_deps = [
"//google_apis",
......
......@@ -51,6 +51,9 @@ typedef std::set<invalidation::ObjectId, ObjectIdLessThan> ObjectIdSet;
typedef std::map<invalidation::ObjectId, int, ObjectIdLessThan>
ObjectIdCountMap;
using Topic = std::string;
using TopicSet = std::unordered_set<std::string>;
// Caller owns the returned DictionaryValue.
std::unique_ptr<base::DictionaryValue> ObjectIdToValue(
const invalidation::ObjectId& object_id);
......
// Copyright 2018 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 "components/invalidation/public/topic_invalidation_map.h"
#include <stddef.h>
#include "base/json/json_string_value_serializer.h"
namespace syncer {
TopicInvalidationMap::TopicInvalidationMap() {}
TopicInvalidationMap::TopicInvalidationMap(const TopicInvalidationMap& other) =
default;
TopicInvalidationMap::~TopicInvalidationMap() {}
TopicSet TopicInvalidationMap::GetTopics() const {
TopicSet ret;
for (const auto& topic_and_invalidation_set : map_)
ret.insert(topic_and_invalidation_set.first);
return ret;
}
bool TopicInvalidationMap::Empty() const {
return map_.empty();
}
void TopicInvalidationMap::Insert(const Invalidation& invalidation) {
map_[invalidation.object_id().name()].Insert(invalidation);
}
TopicInvalidationMap TopicInvalidationMap::GetSubsetWithTopics(
const TopicSet& topics) const {
TopicToListMap new_map;
for (const auto& topic : topics) {
TopicToListMap::const_iterator lookup = map_.find(topic);
if (lookup != map_.end()) {
new_map[topic] = lookup->second;
}
}
return TopicInvalidationMap(new_map);
}
const SingleObjectInvalidationSet& TopicInvalidationMap::ForTopic(
Topic topic) const {
TopicToListMap::const_iterator lookup = map_.find(topic);
DCHECK(lookup != map_.end());
DCHECK(!lookup->second.IsEmpty());
return lookup->second;
}
void TopicInvalidationMap::GetAllInvalidations(
std::vector<syncer::Invalidation>* out) const {
for (TopicToListMap::const_iterator it = map_.begin(); it != map_.end();
++it) {
out->insert(out->begin(), it->second.begin(), it->second.end());
}
}
void TopicInvalidationMap::AcknowledgeAll() const {
for (TopicToListMap::const_iterator it1 = map_.begin(); it1 != map_.end();
++it1) {
for (SingleObjectInvalidationSet::const_iterator it2 = it1->second.begin();
it2 != it1->second.end(); ++it2) {
it2->Acknowledge();
}
}
}
bool TopicInvalidationMap::operator==(const TopicInvalidationMap& other) const {
return map_ == other.map_;
}
std::unique_ptr<base::ListValue> TopicInvalidationMap::ToValue() const {
std::unique_ptr<base::ListValue> value(new base::ListValue());
for (TopicToListMap::const_iterator it1 = map_.begin(); it1 != map_.end();
++it1) {
for (SingleObjectInvalidationSet::const_iterator it2 = it1->second.begin();
it2 != it1->second.end(); ++it2) {
value->Append(it2->ToValue());
}
}
return value;
}
bool TopicInvalidationMap::ResetFromValue(const base::ListValue& value) {
map_.clear();
for (size_t i = 0; i < value.GetSize(); ++i) {
const base::DictionaryValue* dict;
if (!value.GetDictionary(i, &dict)) {
return false;
}
std::unique_ptr<Invalidation> invalidation =
Invalidation::InitFromValue(*dict);
if (!invalidation) {
return false;
}
Insert(*invalidation);
}
return true;
}
std::string TopicInvalidationMap::ToString() const {
std::string output;
JSONStringValueSerializer serializer(&output);
serializer.set_pretty_print(true);
serializer.Serialize(*ToValue());
return output;
}
TopicInvalidationMap::TopicInvalidationMap(const TopicToListMap& map)
: map_(map) {}
} // namespace syncer
// Copyright 2014 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.
#ifndef COMPONENTS_INVALIDATION_PUBLIC_TOPIC_INVALIDATION_MAP_H_
#define COMPONENTS_INVALIDATION_PUBLIC_TOPIC_INVALIDATION_MAP_H_
#include <map>
#include <memory>
#include <vector>
#include "components/invalidation/public/invalidation.h"
#include "components/invalidation/public/invalidation_export.h"
#include "components/invalidation/public/invalidation_util.h"
#include "components/invalidation/public/single_object_invalidation_set.h"
namespace syncer {
// A set of notifications with some helper methods to organize them by object ID
// and version number.
class INVALIDATION_EXPORT TopicInvalidationMap {
public:
TopicInvalidationMap();
TopicInvalidationMap(const TopicInvalidationMap& other);
~TopicInvalidationMap();
// Returns set of Topics for which at least one invalidation is present.
TopicSet GetTopics() const;
// Returns true if this map contains no invalidations.
bool Empty() const;
// Returns true if both maps contain the same set of invalidations.
bool operator==(const TopicInvalidationMap& other) const;
// Inserts a new invalidation into this map.
void Insert(const Invalidation& invalidation);
// Returns a new map containing the subset of invaliations from this map
// whose IDs were in the specified |ids| set.
TopicInvalidationMap GetSubsetWithTopics(const TopicSet& ids) const;
// Returns the subset of invalidations with IDs matching |id|.
const SingleObjectInvalidationSet& ForTopic(Topic id) const;
// Returns the contents of this map in a single vector.
void GetAllInvalidations(std::vector<syncer::Invalidation>* out) const;
// Call Acknowledge() on all contained Invalidations.
void AcknowledgeAll() const;
// Serialize this map to a value.
std::unique_ptr<base::ListValue> ToValue() const;
// Deserialize the value into a map and use it to re-initialize this object.
bool ResetFromValue(const base::ListValue& value);
// Prints the contentes of this map as a human-readable string.
std::string ToString() const;
private:
typedef std::map<Topic, SingleObjectInvalidationSet> TopicToListMap;
TopicInvalidationMap(const TopicToListMap& map);
TopicToListMap map_;
};
} // namespace syncer
#endif // COMPONENTS_INVALIDATION_PUBLIC_TOPIC_INVALIDATION_MAP_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment