blob: 3ddb73b2e2cc3ba5f58590bac142072f00dc7f55 [file] [log] [blame]
// 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.
#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 {
using Id = std::string;
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;
// 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;
using Id = ContextIndex::Id;
using IdAndVersionSet = std::set<std::pair<Id, uint32_t>>;
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);
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_;
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;
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