Expand description
The exploded tier is a CACHE, not a tier — and this is the bound.
Rickard, 2026-08-30, on being shown the lazy-explode design: “does lazy
explode mean it eventually takes the disk anyway?” — and the honest answer
is yes, unless the tier is capped, because a client that browses a whole
history reads every object once and a write-back-on-first-read tier would
then hold exactly what the eager one held. MEASURED on the rig 2026-08-30:
the 8.12 GiB torvalds/linux pack drove the eager tier to 141.7 GiB
into /data, ~17× the pack. “We cannot have one repo take all 300 GB
disk.”
So the tier has a byte budget and evicts. Nothing here is data: every
row is re-derivable from the verbatim pack bytes by
crate::resolve::materialize_at, so an eviction is never a loss and never
an error a client can see — it is a later read paying ~0.5–2 ms to inflate
its own delta chain again.
§Two pools, and the split is the whole design
objects.exploded the EAGER pool — what the indexer writes at push
time. Under the shipped policy that is commits
and tags: what `graph`/`reach`/tag-peel need, so
visibility and pull checks never stall.
NEVER evicted — it is the "commits last" rule,
held by construction rather than by a comparator.
objects.exploded.c1 the LAZY pool — first-read write-backs, appended
objects.exploded.c2 in read order, one file per segment.
… EVICTION IS ONE `unlink` of the oldest segment.Both pools are counted against the budget and both are named on the
dashboard; only the lazy one is evictable. If the eager pool alone exceeds
the budget the lazy pool is evicted to nothing and the eager pool is still
kept — a store that cannot answer reach is broken, and a store that reads
slowly is not.
§Why segments, and why eviction is an unlink
ExplodedArchive is one append-only Arrow IPC stream: [schema][batch]…,
nothing ever rewritten. That is what makes it 1.0× its payload instead of
redb’s 12×, and it is also what makes deleting a row in the middle cost a
whole-file rewrite — up to 17 GB, which the module docs already refuse to
smuggle into gc. Cutting the pool into segment files turns “reclaim the
coldest bytes” into remove_file: O(1), no rewrite, no read amplification,
and a crash during it leaves a pool that is merely shorter.
§The recency argument, stated honestly
Segments are appended in first-read order, so dropping the oldest drops the objects least recently admitted. That is not the same as least recently used — an object read at minute 1 and again at minute 90 sits in an old segment. It is not promoted, and it does not need to be: when its segment is dropped, the next read of it misses, re-inflates its chain, and writes it back into the newest segment. Re-entry-on-miss is what makes this LRU-shaped, at the cost of one chain inflate per hot object per eviction cycle rather than a copy per hit. So it is FIFO over segments with re-entry-on-miss, and the thing an LRU is wanted for — a working set that stays resident under a scan of everything else — holds, because the working set is what keeps re-entering.
§What a full-history read now costs on disk
The plateau, not the climb. A reader that walks every object of a
Linux-sized repository writes back every object it inflates; the pool grows
to the budget and then stops, because each rotation past it drops the oldest
segment. That is the number lane Q reports as its headline, and
the_tier_plateaus_at_its_budget_under_a_full_scan is the test that asserts
it rather than the sentence.
Re-exports§
pub use crate::arms::ENV_EXPLODE_BUDGET as ENV_BUDGET;
Structs§
- Cache
Use - What the tier is holding and what it is allowed to hold — the row a
dashboard prints and
Admin.StorageInfocarries. - Exploded
Cache - The two pools, one door. Everything that used to call an
ExplodedArchivecalls this instead; the eager pool is anExplodedArchiveand behaves exactly as it did. - Suppress
Write Back - The guard
suppress_write_backreturns. See it for what this is for.
Constants§
- BUDGET_
CEILING - BUDGET_
FRACTION_ PERCENT - The default budget, and the arithmetic that makes it safe.
- CACHE_
FLUSH_ BYTES - The lazy pool buffers this much before it writes. Far under
crate::exploded_arrow::FLUSH_BYTESon purpose: that 64 MiB buffer is sized for an indexer draining a pack, and a reader’s write-back holding 64 MiB per store is memory the box did not agree to spend. - CHEAP_
DEPTH - The cheapest thing a cache can do is not cache.
- MAX_
CACHED_ BYTES - MIN_
BUDGET
Functions§
- budget_
from_ env - The budget a store opens with: the environment door if it names one, the filesystem-derived default otherwise.
- default_
budget - The default budget for a store rooted at
dir, from that filesystem’s size. - default_
global_ line - The process-wide line for a store rooted at
dir: the same tenth of the filesystem asdefault_budget, uncapped — the cap is per store, the tenth is per box. Every cache on one filesystem computes the same figure; caches on different filesystems each hold the sum to their own, which over-counts across mounts and is the conservative direction.0(no filesystem figure) turns the global check off rather than inventing one. - human
3.1G,812M,40K— one significant fraction, the same shape the dashboard’s other byte cells use.- parse_
budget 12G,512M,1048576,0,unlimited. An unparseable value is an ERROR and never a silent default — a typo in a quota is a bill that is wrong, and nobody notices until it is.- rebuild_
cost - What it cost to produce an object, as the cache scores it.
- set_
budget_ under - Set the budget of every open store under
root(a prefix match, so an account’s whole tree is one call). Returns how many were changed — applied output, so a control plane that set nothing can say so. - suppress_
write_ back - Declare that reads on this thread are validation, not a reader’s.
- use_all
- Every open store’s explode band, as
(store root, use). What the dashboard tick andAdmin.StorageInforead; ametadatacall per pool and no store lock. Dead entries are swept on the way past. - worth_
caching - Is this object worth a slice of the quota?
- write_
back_ suppressed - Whether
suppress_write_backis in force on this thread.