Module 5 · Dive 5.2
Lock-free readers.
A reader takes hold of the current root and reads it to the end. Whatever the writer does next — commit a new root, ten new roots — the reader’s view is fixed, because its root is immutable. And the writer never waits for a reader, because it only ever appends. Start a reader, then commit a few times and watch the head pull away while the reader stays put.
The head moves; the reader doesn’t
interactiveWhere the locks went
store.design.mdIn a mutable store, a reader and a writer touching the same data must take turns, so one waits — that is what a lock is. Immutability removes the shared mutable thing entirely: the reader’s root and the writer’s new root are different objects, so there is nothing to contend over. Readers scale out freely, a long analytical read can’t stall the write path, and the writer’s only serialization is the tiny head swap from Module 3’s OCC, not a lock over the data. For a durable queue this is the difference between “draining the backlog” and “inspecting the backlog” never fighting each other. The one cost is that a reader pins its version alive — which is exactly what GC must respect, in the last dive.
References & sources
- External
- Multiversion concurrency controlreaders don't block writers
- CubDB.with_snapshota consistent read while writes continue
- Snapshot isolationthe guarantee a pinned reader gets
- Echo records
- store.design.mdlock-free reads beside the write lock
- graft.design.mdreaders, the head, and OCC