Bedrock.DataPlane.CommitProxy.RoutingData (bedrock v0.7.0)
View SourceImmutable routing state for the commit proxy.
Encapsulates all information needed to route mutations to logs:
shards- a:gb_treesmap ofend_key => {tag, start_key}for key → tag ceiling search (end_keyis the shard's exclusive upper bound)log_map- Map of index → log_id for golden ratio routinglog_services- Map of log_id → pid or {otp_name, node} for contacting logsmaterializers- Map of tag →%{worker_id => node}(strings, as committed to thematerializers/keyspace family): a shard's MEMBER SET, from whichcovering_entry/2picks the client-facing ref; clients derive the callable ref from that pickreplication_factor- Number of logs per mutation
The value is a plain immutable term: the commit proxy server is its only writer, applying committed metadata one batch at a time in commit-version order, and every finalization task routes from the snapshot the server handed it for its batch. Concurrent batches can never observe - or race - each other's updates, which is what lets these be ordinary data structures with no versions, locks, or shared tables.
Lifecycle
new_empty/0- Creates empty routing data for dynamic populationfrom_snapshot/1- Builds routing data from a plain snapshot at unlock
Shard Updates
insert_shard/4- Adds or updates a shard entrydelete_shard/2- Removes a shard entry
Log wiring (log_map, log_services, replication_factor) is
epoch-constant: seeded once at unlock and never mutated — changing log
topology IS a recovery (bedrock-q67.41).
Summary
Types
The client-facing covering entry for one key: the shard's bounds, its tag, and the raw materializer ref. Log wiring stays proxy-internal.
A materializer ref handed to a client: worker id and node, both strings.
One shard's committed members: worker id to node. A set, because a shard may be served by more than one materializer (bedrock-q67.21.9).
A plain-data description of routing state, safe to send between processes
and nodes. from_snapshot/1 turns it into runnable routing data.
Functions
Applies metadata mutations to update routing data.
The covering entry for one key: a ceiling walk over the shard tree plus the tag's committed materializer ref.
Deletes a shard entry.
Builds routing data from a plain snapshot.
Inserts or updates a shard entry.
A shard tag's committed members, or {:error, :not_found} when the
keyspace names none.
Creates empty routing data.
The client-facing pick among a shard's members: real coverage beats the placeholder (which only parks), and the choice is deterministic so every proxy answers alike and a client's retry lands consistently.
Types
@type covering_entry() :: {start_key :: Bedrock.key(), end_key :: Bedrock.key(), tag :: term(), materializer_ref()}
The client-facing covering entry for one key: the shard's bounds, its tag, and the raw materializer ref. Log wiring stays proxy-internal.
A materializer ref handed to a client: worker id and node, both strings.
@type members() :: %{required(Bedrock.Service.Worker.id()) => String.t()}
One shard's committed members: worker id to node. A set, because a shard may be served by more than one materializer (bedrock-q67.21.9).
@type shard_tree() :: :gb_trees.tree( Bedrock.key(), {tag :: term(), start_key :: Bedrock.key()} )
@type snapshot() :: %{ optional(:materializers) => %{required(Bedrock.range_tag()) => members()}, shard_layout: %{ required(Bedrock.key()) => {tag :: term(), start_key :: Bedrock.key()} }, log_map: %{required(non_neg_integer()) => Bedrock.DataPlane.Log.id()}, log_services: %{ required(Bedrock.DataPlane.Log.id()) => {atom(), node()} | pid() }, replication_factor: pos_integer() }
A plain-data description of routing state, safe to send between processes
and nodes. from_snapshot/1 turns it into runnable routing data.
@type t() :: %Bedrock.DataPlane.CommitProxy.RoutingData{ log_map: %{required(non_neg_integer()) => Bedrock.DataPlane.Log.id()}, log_services: %{ required(Bedrock.DataPlane.Log.id()) => {atom(), node()} | pid() }, materializers: %{required(Bedrock.range_tag()) => members()}, replication_factor: pos_integer(), shards: shard_tree() }
Functions
@spec apply_mutations(t(), [{Bedrock.version(), [term()]}]) :: t()
Applies metadata mutations to update routing data.
Handles shard_key and materializer_key mutations. Any other system key is ignored: log wiring is epoch-constant and rides the unlock seed, and an unrecognized family is forward-compatibility, not an error.
Parameters
routing_data- Current routing dataupdates- List of{version, [mutations]}tuples from resolver
Returns
Updated routing data with applied mutations.
@spec covering_entry(t(), Bedrock.key()) :: {:ok, covering_entry()} | {:error, :not_found}
The covering entry for one key: a ceiling walk over the shard tree plus the tag's committed materializer ref.
Served to clients by the commit proxy (FDB's GetKeyServerLocations
answered from keyInfo) — one entry per ask, O(log n), never a bulk
projection of a map that can number in the thousands. Locations are
unverified hints: a stale entry costs the client a retry, never a
wrong answer. {:error, :not_found} covers both a key beyond every
boundary and a shard whose tag names no materializer — to the client
both are an unroutable key.
Deletes a shard entry.
Called from apply_mutations/2 when processing shard_key clear mutations.
Builds routing data from a plain snapshot.
@spec insert_shard(t(), binary(), term(), Bedrock.key()) :: t()
Inserts or updates a shard entry.
Called from apply_mutations/2 when processing shard_key mutations.
@spec materializer_members(t(), non_neg_integer()) :: {:ok, members()} | {:error, :not_found}
A shard tag's committed members, or {:error, :not_found} when the
keyspace names none.
This answers a worker's rejoin validation (FDB's storage-server rejoin
through the proxy's txnStateStore: absence from the set means
worker_removed) from the same routing view that serves clients — one
authority, two readers asking different questions. The worker asks
MEMBERSHIP, not resolution: with several members per shard, the ref a
client happens to be routed to says nothing about whether any other
member still belongs.
@spec new_empty() :: t()
Creates empty routing data.
Starts with no shards, no logs, and replication factor of 1. Shard and
materializer entries populate incrementally as metadata mutations
arrive; log wiring is epoch-constant and only from_snapshot/1 sets it.
@spec pick_member(members()) :: {:ok, materializer_ref()} | :error
The client-facing pick among a shard's members: real coverage beats the placeholder (which only parks), and the choice is deterministic so every proxy answers alike and a client's retry lands consistently.
THE one pick. The distributor points the placeholder at a shard's members through this same function, so the member recovery unlocks, the member clients are routed to, and the member parked reads drain into cannot disagree. Load- and locality-aware selection is bedrock-q67.46's to add here, once.