View Source ProcessHub.Service.ProcessRegistry.Row (ProcessHub v0.7.0)

The registry row's ProcessHub-owned bookkeeping, stored under the reserved metadata key :__process_hub__.

A registry row is {child_spec, node_pids, metadata}. child_spec and node_pids are the caller's and the cluster's; metadata is the caller's except for this one reserved key, which is the hub's:

%{
  epoch: pos_integer(),          # per-child counter, never a wall clock
  changed_at: integer(),         # diagnostics only
  changed_by: node(),
  durable: true                  # only for children started durable: true
}

This module is the algebra over that key: who wins a merge, what an authored write stamps. It is pure — reads and writes belong to ProcessHub.Service.ProcessRegistry, which owns the table.

Experimental

The durable flag is part of the experimental declared-children feature and may change in future releases. The epoch and merge ordering apply to every hub.

Summary

Types

t()

The reserved bookkeeping map carried by every row's metadata.

Functions

Returns whether a row belongs to a child declared with durable: true.

Returns a row metadata's bookkeeping, or nil for a row that predates it.

The reserved metadata key. Hub-owned: caller metadata cannot set it.

Returns {metadata, forged?}: the caller's metadata with the bookkeeping this write should carry, and whether the caller tried to author the reserved key.

Returns whether candidate wins a merge against incumbent.

Types

@type t() :: %{
  :epoch => pos_integer(),
  :changed_at => integer(),
  :changed_by => node(),
  optional(:durable) => true
}

The reserved bookkeeping map carried by every row's metadata.

Functions

@spec durable?(map() | nil) :: boolean()

Returns whether a row belongs to a child declared with durable: true.

@spec meta(map() | nil) :: t() | nil

Returns a row metadata's bookkeeping, or nil for a row that predates it.

@spec reserved_key() :: :__process_hub__

The reserved metadata key. Hub-owned: caller metadata cannot set it.

Link to this function

stamp(caller_metadata, previous, opts)

View Source
@spec stamp(map(), t() | nil, keyword()) :: {map(), boolean()}

Returns {metadata, forged?}: the caller's metadata with the bookkeeping this write should carry, and whether the caller tried to author the reserved key.

opts[:adopt] marks a merge — the caller-supplied bookkeeping already won an epoch comparison and is written verbatim, because a merge adopts a value rather than authoring one. Every other write authors: the epoch advances by one and the local node stamps itself. opts[:durable] marks the row's child as declared; once set, the flag survives every subsequent authored write.

forged? reports on shape, not equality. Passing the stored bookkeeping straight back is the norm — every read-modify-write does it, and a concurrent write in between makes the value legitimately stale — so only a value that is not a whole bookkeeping map could have been hand-written. Either way the supplied value is ignored.

Link to this function

wins_merge?(candidate, incumbent)

View Source
@spec wins_merge?(map() | nil, map() | nil) :: boolean()

Returns whether candidate wins a merge against incumbent.

Resolution is by higher epoch, ties broken by the lexicographically lower changed_by node name, so every node that performs the merge reaches the same result in any order and with any number of repetitions.