Bedrock.SystemKeys.Reader (bedrock v0.7.0)

View Source

The shared readers for the durable \xFF/system mapping families: paged range reads and the family decoders. Recovery's materializer bootstrap and the Distributor both read the same families the same way — one reader, so two consumers cannot disagree about what the bytes mean.

Paging resumes each page immediately after the last returned key and drains the continuation to exhaustion: a truncated boundary map is not a degraded layout, it is a wrong one. Any failure mid-continuation fails the whole read — partial success would BE the silent truncation this exists to preclude — and an empty page claiming more is a broken read contract, surfaced rather than looped on.

Summary

Functions

Decodes materializers/<tag>/<worker_id> entries into the membership map %{tag => %{worker_id => node}} - a shard's members are a set, and absence of a key is absence of a member.

Reads a system family's entries to exhaustion, starting at prefix.

Decodes shard_keys/<end_key> entries into the boundary map %{end_key => {tag, start_key}}, consuming the carried start key verbatim — the same meaning RoutingData.apply_mutation gives the value; two readers of one family must not disagree. Adjacency reconstruction (each shard starts where the previous ends) survives only for legacy term_to_binary snapshots that predate carried start keys; recovery no longer rewrites the family (read-and-heal, bedrock-q67.21.2), so a legacy family stays legacy — encoding-uniform, covered by the any-legacy-falls-back-whole rule — until bedrock-q67.20.7 retires the fallback with an explicit migration.

Types

range_read_fn()

@type range_read_fn() :: (Bedrock.key() ->
                      {:ok, {[{Bedrock.key(), binary()}], more :: boolean()}}
                      | {:error, term()}
                      | {:failure, term(), term()})

Functions

decode_materializer_members(entries)

@spec decode_materializer_members([{Bedrock.key(), binary()}]) ::
  {:ok,
   %{
     required(Bedrock.range_tag()) => %{
       required(Bedrock.Service.Worker.id()) => String.t()
     }
   }}
  | {:error, {:invalid_materializer_entry, Bedrock.key()}}

Decodes materializers/<tag>/<worker_id> entries into the membership map %{tag => %{worker_id => node}} - a shard's members are a set, and absence of a key is absence of a member.

A foreign key, or a member key with an undecodable value, fails the whole decode: reading a family we cannot account for as empty would re-recruit every shard and orphan the live ones.

read_family(range_read_fn, prefix, error_tag)

@spec read_family(range_read_fn(), prefix :: Bedrock.key(), error_tag :: atom()) ::
  {:ok, [{Bedrock.key(), binary()}]} | {:error, {atom(), term()}}

Reads a system family's entries to exhaustion, starting at prefix.

shard_layout_from_entries(entries)

@spec shard_layout_from_entries([{Bedrock.key(), binary()}]) ::
  {:ok, %{required(Bedrock.key()) => {Bedrock.range_tag(), Bedrock.key()}}}
  | {:error, {:invalid_shard_value, Bedrock.key()}}

Decodes shard_keys/<end_key> entries into the boundary map %{end_key => {tag, start_key}}, consuming the carried start key verbatim — the same meaning RoutingData.apply_mutation gives the value; two readers of one family must not disagree. Adjacency reconstruction (each shard starts where the previous ends) survives only for legacy term_to_binary snapshots that predate carried start keys; recovery no longer rewrites the family (read-and-heal, bedrock-q67.21.2), so a legacy family stays legacy — encoding-uniform, covered by the any-legacy-falls-back-whole rule — until bedrock-q67.20.7 retires the fallback with an explicit migration.