Skip to content

calternal_collab::history::store

History stores (DESIGN §61, #975 Phase 2, slice A).

Y4/N=500 won Phase 1: Canvas disk 31.86 MiB, Restore p95 48.55 ms, cold open 39.32 ms, undo 19.91 ms. We keep GC on, write v1 update batches and v2 checkpoints with zstd level 3, and train bounded per-document dictionaries. Each frame carries a versioned dictionary ID and BLAKE3 hash. Append acknowledges only after fsync. A partial final frame is removed on open; interior corruption is an error. Fold streams a new segment then atomically replaces the old one. The SQLite Index is a rebuildable hint. Full v1 states use stored::encode, the existing room-state encoder; room epochs remain in stored.rs while this log retains authored history.

A store owns a segment lock until drop or evict. Cache size is explicitly limited; idle rooms are evicted on LRU admission. Blocking IO and Yrs work run on Tokio’s blocking pool, never its async workers. The caller’s first update must include the initial document, not only a delta against a seed the history has never seen. One flush may contain multiple authored rows; it still assigns one point per row and never merges away author boundaries.

Source: crates/calternal-collab/src/history/store.rs

pub struct MemoryHistoryStore

Reference store; it uses the same encoding and retention as the disk store so conformance tests compare semantics, including physical byte accounting.

Implements: Default, HistoryStore

pub async fn append_batch(&self, key: &DocKey, rows: &[HistoryRow]) -> Result<Vec<PointId>>

Match the persistent flush semantics, preserving every author boundary.

Source: crates/calternal-collab/src/history/store.rs:50

pub struct SegmentHistoryStore

Persistent history with a bounded decoded-document cache and rebuilt Index. Construct one store per server. An OS lock rejects a second store writer.

Implements: HistoryStore

pub async fn open(root: Root, db: Db, max_cached_documents: usize) -> Result<Self>

Create the rebuildable Index table. It is owned by calternal-collab, not Security state; a mutation rebuilds stale rows after recovery (#975). max_cached_documents limits decoded rooms; LRU admission evicts idle ones.

pub fn evict(&self, key: &DocKey) -> Result<bool>

Release an idle room’s decoded cache and OS lock. Return false while any in-flight read or write holds the room, so two writers cannot overlap.

pub async fn append_batch(&self, key: &DocKey, rows: &[HistoryRow]) -> Result<Vec<PointId>>

Persist one authenticated flush in one fsync, with one point per input row. Slice B can use this instead of repeated single-row append calls (#975).

pub async fn checkpoint(&self, key: &DocKey) -> Result<()>

Persist an idle checkpoint without creating a new point. The hub can call this after its flush timer; it never delays content or input (DESIGN §34).

Source: crates/calternal-collab/src/history/store.rs:56

pub type HistoryRow = (Author, Vec<u8>, i64);

One flush input; identity and time must come from the authenticated hub. The additional batch API preserves the approved append trait (#975).

Source: crates/calternal-collab/src/history/store.rs:44