1.8 KiB
CRDT Snapshot Compaction
Problem
The huskies project CRDT has grown to 55K ops / 276MB in pipeline.db.
Every container restart replays all operations in a tight synchronous loop
on the tokio runtime (crdt_state/state/init.rs:68-78), taking 27+ minutes
and freezing the runtime so the HTTP server never becomes ready.
Op bloat
55K ops across only 4,154 sequence numbers (~13 ops per seq on average).
Many zeroed-out MergeJobCrdt entries appear to be tombstones never cleaned
up. Some individual ops are up to 523KB. Average op size is 4.6KB.
Proposed Fix
1. Snapshot (checkpoint)
After replaying all ops, serialize the materialized CRDT state to a
checkpoint blob (e.g. a crdt_snapshot table or a separate file). On next
startup, load the snapshot and only replay ops with rowid > snapshot_rowid.
At snapshot time, back up the database file so corruption is recoverable.
2. Op pruning / compaction
Delete ops that are superseded by the snapshot. Tombstoned/deleted items with all-zero fields contribute nothing to materialized state and can be dropped from the log once snapshotted.
3. Immediate fix: spawn_blocking
Move the replay loop to tokio::task::spawn_blocking so the HTTP server and
liveness ticks are not starved during replay. This does not reduce replay
time but prevents the runtime freeze.
Acceptance Criteria
- Startup loads a snapshot when available and only replays ops newer than the snapshot sequence
- A snapshot is written after full CRDT replay completes (or periodically in background)
- DB backup is created at each snapshot time
- Startup time for 55K ops drops from 27+ minutes to under 30 seconds
- Dead/zeroed CRDT ops are pruned during compaction
- CRDT sync protocol continues to work correctly across nodes after compaction
- The replay loop runs in spawn_blocking so it does not freeze the tokio runtime