jonnify·persistence /echo-persistence/native-elixir/the-lazy-reader

Module 7 · Dive 7.2

The lazy Reader.

Reads never load a whole volume. A page request faults through the tiers in order — the head cache in ETS, then CubDB on disk, then a segment fetched from Tigris — stopping at the first hit, and the fetched page is cached on the way back so the next read is fast. Read a hot page, a cold one, and a remote one, then flush the cache and watch a hit turn into a fault.

§1

Descend until hit, cache on return

interactive
One read, three tiers. The probe checks ETS, then CubDB, then Tigris, stopping at the first tier that has the page; on a deeper hit, the page is copied up into ETS. Read different pages and watch the path change.
read: — ETS · L1 head cache volatile · fastest CubDB · durable pages local disk · the LSN log Tigris · remote segments object storage · slowest cache-fill
readout · ETS holds the hot page; CubDB holds all durable pages; Tigris holds older ones only. Read P3 (a disk hit) and it gets cached into ETS — read it again and it’s an L1 hit. Flush ETS to make a hot page cold.
§2

Why faulting beats loading

store.design.md

A volume can be far larger than memory, so the Reader treats pages like a working set rather than a file to slurp. The first tier is ETS, an in-process table holding recently-touched pages — a hit here is a memory read and never blocks on the writer (it reads a committed version, not the head being mutated). Miss, and it reads the page from CubDB’s on-disk B-tree; miss there too — the page has aged out locally — and it pulls the segment from Tigris. Either deep hit fills ETS on the return path, so locality pays off: the second read of the same page is an L1 hit. This is the storage ladder from the landing page made concrete for one read — faults travel down, the answer travels up and warms the cache. The writer and reader share the durable tiers but never block each other, which is the whole point of the split.

§3

References & sources