View Source Vectoree.TreeServer (Vectoree v0.0.2)

A module for running a GenServer process, which acts as a central hosting point of a "tree" (key-value map). The server can host a local part of a (typically static) tree, which forms the base for other subtrees, which are mounted as concurrent processes of type TreeSource and TreeProcessor on the central server. Concurrent processes of type TreeProcessor and TreeSink can be registered on the central server to receive updates on subtrees via casts.

A TreeServer can be started in the usual way, i.e. via the TreeServer.start_link/1 function or as part of a supervision tree. The server itself spawns a group of DynamicSupervisor processes for the supervision of sources, processors and sinks.

There can be only one TreeServer process being alive on a single ERTS node.

Summary

Functions

Accepts a map and returns a tailored map including only the keys :mount and :listen, depending on what is required.

Returns a specification to start this module under a supervisor.

Mounts the calling process as a source at the given path.

Broadcasts a notification about a changed tree at the given path.

Queries the TreeServer at the given path and returns the aggregated tree of path-payload pairs. The aggregated tree is assembled by passing the query on to all sources and processors, which are mounted on the server.

Queries the TreeServer at the given path and applies a custom function on each replied chunk and by using given accumulator (if required).

Registers the calling process as a sink (listener) at the given path.

Starts a new server process linked to the current process. See GenServer.start_link for detailed documentation.

Starts a processor via the given TreeServer denoted by the given module. Paths must be given at which the processor' internal tree is mounted on the base tree and at which the processor shall listen for updates.

Starts a sink via the given TreeServer denoted by the given module. A path must be given at which the sink shall listen for updates.

Starts a source via the given TreeServer denoted by the given module. A path must be given at which the sources' internal tree is mounted on the base tree.

Stops a processor via the given TreeServer denoted by its PID.

Stops a sink via the given TreeServer denoted by its PID.

Stops a source via the given TreeServer denoted by its PID.

Types

@type path() :: %Vectoree.TreePath{segments: term()}

Functions

@spec args2info(%{mount: path(), listen: path()}) :: %{mount: path(), listen: path()}
@spec args2info(%{mount: path()}) :: %{mount: path()}
@spec args2info(%{listen: path()}) :: %{listen: path()}
@spec args2info((... -> any())) :: %{mount: path(), listen: path()}

Accepts a map and returns a tailored map including only the keys :mount and :listen, depending on what is required.

Examples

iex> Vectoree.TreeServer.args2info(%{mount: ~p"a.b.c", foo: :bar, listen: ~p"a.b"})
%{mount: ~p"a.b.c", listen: ~p"a.b"}

iex> Vectoree.TreeServer.args2info(%{mount: ~p"a.b.c", foo: :bar})
%{mount: ~p"a.b.c"}

iex> Vectoree.TreeServer.args2info(%{foo: :bar, listen: ~p"a.b"})
%{listen: ~p"a.b"}

iex> Vectoree.TreeServer.args2info(fn -> %{foo: :bar, listen: ~p"a.b"} end)
%{listen: ~p"a.b"}

Returns a specification to start this module under a supervisor.

See Supervisor.

@spec mount_source(path()) :: {:ok, pid()} | {:error, {:already_registered, pid()}}

Mounts the calling process as a source at the given path.

@spec notify(path(), map()) :: :ok

Broadcasts a notification about a changed tree at the given path.

notify/2 computes an enumeration of all registered listeners for which the notification is relevant and then uses notify/3 to broadcast the notification to each particular process.

Link to this function

notify(server, path, tree)

View Source
@spec notify(GenServer.server(), path(), map()) :: :ok
Link to this function

query(server, path, opts \\ [])

View Source
@spec query(GenServer.server(), path(), [{:chunk_size, integer()}]) :: map()

Queries the TreeServer at the given path and returns the aggregated tree of path-payload pairs. The aggregated tree is assembled by passing the query on to all sources and processors, which are mounted on the server.

The opts keyword list may contain a :chunk_size item with an integer, which is used for chunking the replies coming from all sources and processors. This can be useful in case of large trees (millions of entries).

Examples

Vectoree.TreeServer.query(server_pid, ~p"a.b")
#=> %{...}

Vectoree.TreeServer.query(server_pid, ~p"a", chunk_size: 1000)
#=> %{...}
Link to this function

query_apply(server, path, acc, fun, opts \\ [])

View Source
@spec query_apply(GenServer.server(), path(), any(), (... -> any()), [
  {:chunk_size, integer()}
]) ::
  any()

Queries the TreeServer at the given path and applies a custom function on each replied chunk and by using given accumulator (if required).

The function arguments are

  • the control atom of the chunk, one of
    • :cont indicating more replies to come
    • :ok indicating the last chunk
  • the chunk (a map)
  • the accumulator

Examples

fun = fn _ctrl, chunk, acc -> Map.merge(acc, chunk) end
Vectoree.TreeServer.query_apply(server_pid, ~p"a", %{}, fun, chunk_size: 1000)
#=> %{...}
@spec register_sink(path()) :: {:ok, pid()} | {:error, {:already_registered, pid()}}

Registers the calling process as a sink (listener) at the given path.

@spec start_link([{:tree, map()}]) :: GenServer.on_start()

Starts a new server process linked to the current process. See GenServer.start_link for detailed documentation.

The opts keyword list may contain a :tree item with a value of type map, which is used as the base tree for the server.

Examples

Vectoree.TreeServer.start_link(tree: %{~p"a.b" => :payload})
{:ok, pid}
Link to this function

start_processor(server, module, mount_path, listen_path)

View Source
@spec start_processor(GenServer.server(), module(), path(), path()) ::
  GenServer.on_start()

Starts a processor via the given TreeServer denoted by the given module. Paths must be given at which the processor' internal tree is mounted on the base tree and at which the processor shall listen for updates.

Examples

Vectoree.TreeServer.start_processor(server_pid, CustomSource, ~p"a.b.p0", ~p"a.b.c.d")
{:ok, pid}
Link to this function

start_sink(server, module, listen_path)

View Source
@spec start_sink(GenServer.server(), module(), path()) :: GenServer.on_start()

Starts a sink via the given TreeServer denoted by the given module. A path must be given at which the sink shall listen for updates.

Examples

Vectoree.TreeServer.start_sink(server_pid, CustomSource, ~p"a.b.p0", ~p"a.b.c.d")
{:ok, pid}
Link to this function

start_source(server, module, mount_path)

View Source
@spec start_source(GenServer.server(), module(), path()) :: GenServer.on_start()

Starts a source via the given TreeServer denoted by the given module. A path must be given at which the sources' internal tree is mounted on the base tree.

Examples

Vectoree.TreeServer.start_source(server_pid, CustomSource, ~p"a.b.s0")
{:ok, pid}
Link to this function

stop_processor(server, pid)

View Source
@spec stop_processor(GenServer.server(), pid()) :: :ok | {:error, :not_found}

Stops a processor via the given TreeServer denoted by its PID.

Examples

Vectoree.TreeServer.stop_processor(server_pid, source_pid)
:ok
@spec stop_sink(GenServer.server(), pid()) :: :ok | {:error, :not_found}

Stops a sink via the given TreeServer denoted by its PID.

Examples

Vectoree.TreeServer.stop_processor(server_pid, source_pid)
:ok
Link to this function

stop_source(server, pid)

View Source
@spec stop_source(GenServer.server(), pid()) :: :ok | {:error, :not_found}

Stops a source via the given TreeServer denoted by its PID.

Examples

Vectoree.TreeServer.stop_source(server_pid, source_pid)
:ok