Rindle docs and package mapSkip to main content

Module journal_frame

Module journal_frame 

Source
Expand description

The cross-process journal frame envelope (FrameHeader + FrameKind): the typed header (kind / committed_at / run identity + totals) in front of an opaque change payload wherever journal entries live — the hctree master’s hct_journal payload column and the S3 archival segments (rindle-backup). Pure bytes, no deps. See src/journal_frame.rs, designs-implemented/211-HCTREE-LEADER-CDC-DESIGN.md §4.1, and designs-implemented/212-JOURNAL-S3-SHIPPING-DESIGN.md §2.2. The cross-process journal frame envelope — the typed header in front of every opaque change payload (designs-implemented/211-HCTREE-LEADER-CDC-DESIGN.md §4.1).

Today’s _rindle_change_log carries kind, run_id, run_rows, rows_cum, and committed_at as columns, and the plane reads them as columns: the epoch fence is a run_id point lookup at the cursor, C_grace retention reads committed_at, and the lag-shed fold groups on kind and accounts with the run totals. Under 211 the master’s log is hct_journal(cid, query, snapshot, logptr) — no home for those columns — so they move into this header, encoded in front of the payload bytes handed to sqlite3_hct_journal_leader_commit. The same envelope is what the S3 shipping plane (rindle-backup, designs-implemented/212-JOURNAL-S3-SHIPPING-DESIGN.md §2.2) frames into archival segments, so one decode serves the sender, the shipper, and restore replay.

Deliberately not in the header:

  • cid — assigned by the engine inside leader_commit, so the producer cannot know it at encode time. The container carries it (the journal’s cid column; the segment framing). Keeping it out also means there is exactly one source of truth.
  • chunk_seq — one HCTree cid is still one atomic transaction, but its opaque payload may use the versioned chunk container documented at encode_payload_chunks. Chunk sequence is implicit in container order, so it does not belong in the transaction header.

Wire layout (all integers little-endian):

u8   header format version (1 = legacy, 2 = chunk container — see the constants)
u8   kind (0 = rows, 1 = ddl, 2 = empty; 3 reserved — see [`FrameKind`])
u8   flags (bit 0: run_id present, bit 1: run totals present; others reserved)
i64  committed_at — commit wall clock, unix millis, stamped by the capture path
     (identical across a run, like today's column); 0 = unknown (empty frames)
[flag bit 0]  u8 run_id byte-length, then that many UTF-8 bytes
[flag bit 1]  u64 run_rows, u64 rows_cum — precomputed in the capture path (the
     in-txn `stamp_run_totals` UPDATE is impossible once the payload is fixed at
     `leader_commit` time, 211 §4.1)
…    payload — version-dependent:
       v1: ONE opaque legacy blob (in practice a UTF-8 JSON `RowChange[]` array)
       v2: the versioned ordered-chunk container below (absent for Empty frames)

The version byte is per frame, not per container: repack re-encodes old frames to the current version (212 §2.2’s aging-out policy), and a per-frame stamp is what lets one segment legally carry mixed vintages in between.

Structs§

FrameHeader
The decoded envelope header. See the module docs for the wire layout.
RunTotals
The run accounting pair (run_rows, rows_cum) — today’s stamped columns, moved into the header and precomputed in the capture path (211 §4.1).

Enums§

FrameDecodeError
Decode-side failures. Fail-closed by construction: unknown versions, kinds, or flag bits are errors, never best-effort skips — a frame will be replayed by a binary years younger than the one that wrote it, and that direction must be exact.
FrameEncodeError
Encode-side misuse. Every variant is a producer bug, not a data-reachable state — surfaced as errors (not asserts) because the encoder sits on the commit path.
FrameKind
The entry kind — today’s _rindle_change_log.kind discriminator plus the shapes the journal substrate adds.
PayloadDecodeError
PayloadEncodeError