barrel_timeline (barrel_docdb v1.1.1)
View SourceTimeline: branch a database, work on the branch, merge back.
A branch is an instant fork: both RocksDB stores (docs and attachments) are checkpointed into the branch's directory (hard links, O(1) in data size, copy-on-write at the file level), and the branch opens as a normal database whose storage keys keep the parent's name (keyspace indirection, see barrel_keyspace). The fork instant is minted inside the parent's writer, so the checkpoint is exactly "everything up to fork_hlc".
The two stores are checkpointed back to back, not atomically: attachment writes do not serialize through the writer, so an in-flight attachment may straddle the fork. Attachments are LWW state with origin guards and sync out of band, the same tolerance replication has.
v1 lineage is linear: branching a branch is rejected, which keeps barrel_keyspace:resolve/1 single-level.
Summary
Functions
Fork a database. Opts: - at => now (default): the branch starts at the fork instant. - data_dir => Dir: base directory for the branch (defaults to the parent's base, i.e. the branch lives next to its parent). Every other option is merged over the inherited parent config for the branch's FIRST open (channels are always inherited: the copied feed rows are keyspace-scoped and a mismatched config would orphan them). Reopening the branch later follows the normal create_db contract: config is runtime-only and must be supplied again.
The OPEN branches of a database, from the registry (a parent tracks nothing; on-disk-but-closed branches are not listed).
Ship the branch's edits to its parent: one-shot replication over the local transports starting at the fork instant (exclusive), then the attachment phase from the same boundary. Conflicts resolve on the parent through its configured machinery (deterministic LWW, conflict_merger when set); redelivery is a no-op, and a merge checkpoint (a local doc on the branch) makes repeated merges incremental. A PITR rewind is NOT merged: restored versions sit at or before the fork and the parent's vectors already contain them.
Types
-type att_info() :: #{name := binary(), content_type := binary(), length := non_neg_integer(), digest := binary(), chunked => boolean(), chunk_size => pos_integer(), chunk_count => pos_integer()}.
-type change() :: map().
-type db_name() :: binary().
-type docid() :: binary().
-type revid() :: binary().
-type seq() :: barrel_hlc:timestamp().
-type seq_string() :: binary().
-type view_name() :: binary().
Functions
Fork a database. Opts: - at => now (default): the branch starts at the fork instant. - data_dir => Dir: base directory for the branch (defaults to the parent's base, i.e. the branch lives next to its parent). Every other option is merged over the inherited parent config for the branch's FIRST open (channels are always inherited: the copied feed rows are keyspace-scoped and a mismatched config would orphan them). Reopening the branch later follows the normal create_db contract: config is runtime-only and must be supplied again.
The OPEN branches of a database, from the registry (a parent tracks nothing; on-disk-but-closed branches are not listed).
Ship the branch's edits to its parent: one-shot replication over the local transports starting at the fork instant (exclusive), then the attachment phase from the same boundary. Conflicts resolve on the parent through its configured machinery (deterministic LWW, conflict_merger when set); redelivery is a no-op, and a merge checkpoint (a local doc on the branch) makes repeated merges incremental. A PITR rewind is NOT merged: restored versions sit at or before the fork and the parent's vectors already contain them.
Opts: batch_size (default 100), attachments (default true), att_batch_size. Limitations (documented): the parent's conflict_merger is db-open-time config, there is no per-merge override; the report carries replication stats, not per-doc conflict detail. Merge at least once per retention window: branch retention can forget an expired tombstone, and a forgotten delete never ships.