The Dyn layer on disk, under one root dir (<data dir>/dyn by default,
Rho.Config.data_dir/0):
gens/<n>/src/**/*.ex the generation's full source set, as the agent
wrote it (logical `Dyn.*` names)
gens/<n>/ebin/*.beam the compiled, selftested binaries
(versioned `Dyn.G<n>.*` names)
gens/<n>/manifest.json a `Rho.Dyn.Generation`
gens/<n>/diff.patch unified diff against the parent's sources
current the active generation's number (0, or no
file: no Dyn layer)
staging/src/**/*.ex where edits go before a proposal
boot.json launch markers: `boot_attempts` (launches since
the last one that reached stable) and `stable`
log.jsonl crash, revert and safe-mode reports
seed the generation the seed (the default sources
the host ships, `Rho.Dyn.Seed`) was last installed as
seed.json what that install was built from: each seed
file's sha256 as shipped (`files`), and the
digest of a newer seed that was rejected
(`rejected`), so it isn't retried every launchEverything that decides what runs (current, manifests, boot.json) is
written to a temp file and renamed over the old one, so a crash mid-write
leaves the old file.
Rho.Dyn, Rho.Dyn.Keeper, Rho.Dyn.Compiler and Rho.Dyn.Seed read
and write it; hosts read Dyn state through Rho.Dyn instead. Every
function takes the root dir first.
Summary
Types
boot.json: launches since the last stable one, whether the last reached
stable, and the delivered Core update (mob_deliver manifest id) the last
counted launch ran, nil for the build's own code.
Functions
Reserves the next generation number by creating its directory.
Appends a report (a JSON-encodable map) to the log; the file keeps the last 200.
Generation n's stored binaries (the module name comes from each binary).
The launch markers (boot_markers/0); a fresh, stable record when there are none.
The active generation's number; 0 when there is none (or the pointer is unreadable).
The default root dir: dyn under Rho.Config.data_dir/0.
Generation n's compile dependencies (Rho.Dyn.Reuse), or nil
if it has none recorded (built before they were, or unreadable): then
nothing of it is reused.
Generation n's unified diff against its parent; "" when there is none.
Generation n's manifest; generation 0 is Rho.Dyn.Generation.empty/0.
Every generation with a readable manifest, newest first, then generation 0.
The last limit reports, oldest first (string keys, as stored).
Writes generation n's compiled binaries.
Writes the launch markers (boot_markers/0).
Points current at generation n (0: no Dyn layer).
Writes generation n's compile dependencies (see deps/2).
Writes generation n's diff against its parent.
Writes generation gen.n's manifest.
Records that the seed was installed as generation n.
Writes the seed's record (seed.json, see seed_files/1).
Writes generation n's sources (%{relative_path => source}).
Replaces the staging copy with sources (normally the current generation's).
The generation the seed was installed as, or nil before it was.
The seed's record (seed.json): files, each seed file's sha256 as it
shipped in the install's seed (nil when an older app installed it and
didn't record them), and rejected, the digest of a seed whose install
failed its check, compile or selftests.
Generation n's sources as %{relative_path => source}.
Generation n's source dir (compile diagnostics point into it).
Creates a staging source only when rel does not already exist.
Removes one staged source; :ok when it was already absent.
Writes (creates or replaces) one staged source; rel must pass valid_rel/1.
One staged source; rel must pass valid_rel/1.
The staged sources as %{relative_path => source}.
Has staging been set up (it is created from the current generation once)?
Reads generation n, applies fun, writes the result back.
Source paths are relative, .ex, made of [A-Za-z0-9_] segments.
Types
@type boot_markers() :: %{ boot_attempts: non_neg_integer(), stable: boolean(), core: String.t() | nil }
boot.json: launches since the last stable one, whether the last reached
stable, and the delivered Core update (mob_deliver manifest id) the last
counted launch ran, nil for the build's own code.
Functions
@spec allocate(Path.t()) :: pos_integer()
Reserves the next generation number by creating its directory.
Appends a report (a JSON-encodable map) to the log; the file keeps the last 200.
@spec beams(Path.t(), pos_integer()) :: [{module(), binary()}]
Generation n's stored binaries (the module name comes from each binary).
@spec boot_markers(Path.t()) :: boot_markers()
The launch markers (boot_markers/0); a fresh, stable record when there are none.
@spec current(Path.t()) :: non_neg_integer()
The active generation's number; 0 when there is none (or the pointer is unreadable).
@spec default_root() :: Path.t()
The default root dir: dyn under Rho.Config.data_dir/0.
@spec deps(Path.t(), non_neg_integer()) :: map() | nil
Generation n's compile dependencies (Rho.Dyn.Reuse), or nil
if it has none recorded (built before they were, or unreadable): then
nothing of it is reused.
@spec diff(Path.t(), non_neg_integer()) :: String.t()
Generation n's unified diff against its parent; "" when there is none.
@spec generation(Path.t(), non_neg_integer()) :: {:ok, Rho.Dyn.Generation.t()} | {:error, :not_found}
Generation n's manifest; generation 0 is Rho.Dyn.Generation.empty/0.
@spec generations(Path.t()) :: [Rho.Dyn.Generation.t()]
Every generation with a readable manifest, newest first, then generation 0.
@spec log(Path.t(), pos_integer()) :: [map()]
The last limit reports, oldest first (string keys, as stored).
@spec put_beams(Path.t(), pos_integer(), [{module(), binary()}]) :: :ok
Writes generation n's compiled binaries.
@spec put_boot_markers(Path.t(), %{ :boot_attempts => non_neg_integer(), :stable => boolean(), optional(:core) => String.t() | nil }) :: :ok | {:error, term()}
Writes the launch markers (boot_markers/0).
@spec put_current(Path.t(), non_neg_integer()) :: :ok | {:error, term()}
Points current at generation n (0: no Dyn layer).
@spec put_deps(Path.t(), pos_integer(), map()) :: :ok
Writes generation n's compile dependencies (see deps/2).
@spec put_diff(Path.t(), pos_integer(), String.t()) :: :ok
Writes generation n's diff against its parent.
@spec put_generation(Path.t(), Rho.Dyn.Generation.t()) :: :ok | {:error, term()}
Writes generation gen.n's manifest.
@spec put_seed(Path.t(), pos_integer()) :: :ok | {:error, term()}
Records that the seed was installed as generation n.
@spec put_seed_files( Path.t(), %{required(String.t()) => String.t()} | nil, String.t() | nil ) :: :ok | {:error, term()}
Writes the seed's record (seed.json, see seed_files/1).
@spec put_sources(Path.t(), pos_integer(), %{required(String.t()) => String.t()}) :: :ok
Writes generation n's sources (%{relative_path => source}).
Replaces the staging copy with sources (normally the current generation's).
@spec seed(Path.t()) :: pos_integer() | nil
The generation the seed was installed as, or nil before it was.
@spec seed_files(Path.t()) :: %{ files: %{required(String.t()) => String.t()} | nil, rejected: String.t() | nil }
The seed's record (seed.json): files, each seed file's sha256 as it
shipped in the install's seed (nil when an older app installed it and
didn't record them), and rejected, the digest of a seed whose install
failed its check, compile or selftests.
@spec sources(Path.t(), non_neg_integer()) :: %{required(String.t()) => String.t()}
Generation n's sources as %{relative_path => source}.
@spec src_dir(Path.t(), pos_integer()) :: Path.t()
Generation n's source dir (compile diagnostics point into it).
@spec stage_create(Path.t(), String.t(), String.t()) :: :ok | {:error, :bad_path | :exists | File.posix()}
Creates a staging source only when rel does not already exist.
Removes one staged source; :ok when it was already absent.
Writes (creates or replaces) one staged source; rel must pass valid_rel/1.
One staged source; rel must pass valid_rel/1.
The staged sources as %{relative_path => source}.
Has staging been set up (it is created from the current generation once)?
@spec update_generation(Path.t(), pos_integer(), (Rho.Dyn.Generation.t() -> Rho.Dyn.Generation.t())) :: {:ok, Rho.Dyn.Generation.t()} | {:error, term()}
Reads generation n, applies fun, writes the result back.
Source paths are relative, .ex, made of [A-Za-z0-9_] segments.