| // Copyright 2016 The Fuchsia 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 PERIDOT_BIN_CONTEXT_ENGINE_CONTEXT_REPOSITORY_H_ |
| #define PERIDOT_BIN_CONTEXT_ENGINE_CONTEXT_REPOSITORY_H_ |
| |
| #include <map> |
| #include <set> |
| #include <string> |
| |
| #include <fuchsia/modular/cpp/fidl.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <src/lib/fxl/logging.h> |
| #include <src/lib/fxl/macros.h> |
| |
| #include "peridot/bin/context_engine/index.h" |
| |
| namespace modular { |
| |
| class ContextDebug; |
| class ContextDebugImpl; |
| |
| // This class represents a "multiparent hierarchy", which is another way |
| // of saying a directed graph that cannot have any cycles. |
| // TODO(thatguy): Actually enforce the no cycles constraint :). |
| class ContextGraph { |
| public: |
| using Id = std::string; |
| |
| ContextGraph(); |
| virtual ~ContextGraph(); |
| |
| // Adds a graph edge from |from| to |to|. |
| void AddEdge(const Id& from, const Id& to); |
| |
| // Removes the node |id| and removes any incoming or outgoing edges. |
| // TODO(thatguy): Decide what to do about orphaned children. |
| void Remove(const Id& id); |
| |
| std::set<Id> GetParents(const Id& id) const; |
| |
| // Returns all |id|'s children and their children, recursively. |
| std::set<Id> GetChildrenRecursive(const Id& id) const; |
| |
| // Returns all ancestors for |id|, guaranteeing that all node ids appear in |
| // the return value before their children (ie, in order of seniority). |
| std::vector<Id> GetAncestors(const Id& id) const; |
| |
| private: |
| // From node to its parents. |
| std::map<Id, std::set<Id>> parents_; |
| // From parent to its immediate children. |
| std::map<Id, std::set<Id>> children_; |
| }; |
| |
| // Stores a graph of fuchsia::modular::ContextValue structs (values). Supports |
| // fetching lists of values based on a) the value's type and b) |
| // fuchsia::modular::ContextMetadata fields. |
| // |
| // The graph structure is used to represent value namespaces or scope, although |
| // the exact meaning or what concepts are represented is up to the client. When |
| // a value is queried against and returned, its metadata is "flattened" with |
| // its ancestors' metadata. For example, if an ENTITY value is a child of a |
| // MODULE value, the ENTITY value will inherit the MODULE value's metadata (ie, |
| // the |mod| field of the fuchsia::modular::ContextMetadata struct). |
| class ContextRepository { |
| struct ValueInternal; |
| struct Subscription; |
| struct InProgressUpdate; |
| |
| public: |
| using Id = ContextIndex::Id; |
| using IdAndVersionSet = std::set<std::pair<Id, uint32_t>>; |
| |
| ContextRepository(); |
| ~ContextRepository(); |
| |
| bool Contains(const Id& id) const; |
| Id Add(fuchsia::modular::ContextValue value); |
| Id Add(const Id& parent_id, fuchsia::modular::ContextValue value); |
| void Update(const Id& id, fuchsia::modular::ContextValue value); |
| void Remove(const Id& id); |
| |
| // Returns a copy of the fuchsia::modular::ContextValue for |id|. Returns a |
| // null |fuchsia::modular::ContextValuePtr| if |id| is not valid. |
| fuchsia::modular::ContextValuePtr Get(const Id& id) const; |
| |
| // Returns a copy of the fuchsia::modular::ContextValue for |id|, with |
| // metadata merged from ancestors. Returns a null |
| // |fuchsia::modular::ContextValuePtr| if |id| is not valid. |
| fuchsia::modular::ContextValuePtr GetMerged(const Id& id) const; |
| |
| std::set<Id> Select(const fuchsia::modular::ContextSelector& selector); |
| |
| // Returns the current requested values for the given query as a context |
| // update. |
| fuchsia::modular::ContextUpdate Query( |
| const fuchsia::modular::ContextQuery& query); |
| |
| // Does not take ownership of |listener|. |listener| must remain valid until |
| // RemoveSubscription() is called with the returned Id. |
| Id AddSubscription(fuchsia::modular::ContextQuery query, |
| fuchsia::modular::ContextListener* listener, |
| fuchsia::modular::SubscriptionDebugInfo debug_info); |
| void RemoveSubscription(Id id); |
| |
| // Like AddSubscription above, but takes ownership of the FIDL service proxy |
| // object, |listener|. The subscription is automatically removed when |
| // |listener| experiences a connection error. |
| void AddSubscription(fuchsia::modular::ContextQuery query, |
| fuchsia::modular::ContextListenerPtr listener, |
| fuchsia::modular::SubscriptionDebugInfo debug_info); |
| |
| ContextDebugImpl* debug(); |
| void AddDebugBinding( |
| fidl::InterfaceRequest<fuchsia::modular::ContextDebug> request); |
| |
| private: |
| Id AddInternal(const Id& parent_id, fuchsia::modular::ContextValue value); |
| void RecomputeMergedMetadata(ValueInternal* value); |
| void ReindexAndNotify(InProgressUpdate update); |
| void QueryAndMaybeNotify(Subscription* subscription, bool force); |
| std::pair<fuchsia::modular::ContextUpdate, IdAndVersionSet> QueryInternal( |
| const fuchsia::modular::ContextQuery& query); |
| |
| // Keyed by internal id. |
| std::map<Id, ValueInternal> values_; |
| ContextGraph graph_; |
| |
| // A map of Id (int) to Subscription. |
| std::map<Id, Subscription> subscriptions_; |
| |
| ContextIndex index_; |
| |
| friend class ContextDebugImpl; |
| std::unique_ptr<ContextDebugImpl> debug_; |
| fidl::BindingSet<fuchsia::modular::ContextDebug> debug_bindings_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(ContextRepository); |
| }; |
| |
| struct ContextRepository::ValueInternal { |
| // The contents of |value.meta| merged with metadata from all |
| // of this value's ancestors. |
| Id id; |
| fuchsia::modular::ContextMetadata merged_metadata; |
| fuchsia::modular::ContextValue value; |
| uint32_t version; // Incremented on change. |
| }; |
| |
| struct ContextRepository::Subscription { |
| fuchsia::modular::ContextQuery query; |
| fuchsia::modular::ContextListener* |
| listener; // Optionally owned by |listener_storage|. |
| fuchsia::modular::ContextListenerPtr listener_storage; |
| fuchsia::modular::SubscriptionDebugInfo debug_info; |
| // The set of value id and version we sent the last time we notified |
| // |listener|. Used to calculate if a new update is different. |
| IdAndVersionSet last_update; |
| }; |
| |
| // Holds interim values necessary for processing an update to at least one |
| // context value. |
| struct ContextRepository::InProgressUpdate { |
| // These values are having their values added or updated. |
| std::vector<ValueInternal*> updated_values; |
| // These values are being removed. |
| std::vector<ValueInternal> removed_values; |
| }; |
| |
| } // namespace modular |
| |
| #endif // PERIDOT_BIN_CONTEXT_ENGINE_CONTEXT_REPOSITORY_H_ |