pub fn redb_cache_bytes() -> Result<usize>Expand description
The page-cache ceiling for one repository’s redb database, in bytes.
§Why this exists at all
redb::Database::create(path) is Builder::new().create(path), and
Builder::new ends with set_cache_size(1024 * 1024 * 1024) — redb-2.6.3
db.rs:1140. One GiB, per database, by default, split 90 % read /
10 % write by set_cache_size (db.rs:1184), so the stock ceiling is 1 GiB
per repository and a long-lived server holding N repositories has N times
that.
§“Two databases per repository” was stale, and it cost a wrong diagnosis
This paragraph said “a store opens two of them, so the stock ceiling is
2 GiB per repository” until 2026-08-31. A store opens one.
GitStore::open_with_arms
constructs exactly one ObjectReadStack
— objects.tail — and tests/fd_per_store.rs counts exactly one
objects.tail descriptor per store and asserts the total is three. The
second database was the exploded table’s, and it stopped being a redb when
§14 moved that tier to append-only Arrow IPC
(crate::exploded_arrow); the sentence outlived it.
It is recorded rather than quietly deleted because a stale doc is a second
truth and this one was believed: gunnar/.nornir/stinky.md S-079 doubled
this figure to 128 MiB per store on the strength of it, and built an
explanation of a live appliance’s 10 G on top. See S-082 for the
measurement that refuted it.
It is a ceiling and not a reservation, so a small repository never noticed.
MEASURED 2026-08-10 (t14s, h2h-linear-sha1-2048c-1024f-16k, a 1 078 472 704-byte
objects.exploded): a single clone parked 594 MB resident and kept it for
the life of the process, because the pages a full-file traversal touched all
fit under the ceiling and nothing evicted them.
§How the default was chosen
A B-tree read cache earns its keep on the interior nodes, which every
lookup re-touches, and earns nothing on a single sequential pass over the
leaves, which is what a refold is. The interior levels of a 4 KiB-page
B-tree over that 1.078 GB table are ~7 MB; 64 MiB holds all of them nine
times over and leaves 6.4 MiB of write cache, which is more than one absorb
batch dirties. Measured against the 1 GiB default on the clone path it costs
nothing and returns most of the resident set — see the sweep in
agentAA-report.md.
§This is the one environment read that is not an arm
Every other variable in this module selects an implementation and therefore
changes what the store promises, which is why
GitStore::open deliberately reads none of
them. This one selects nothing: it is a memory ceiling, every arm behaves
identically under any value of it, and the bytes on disk are the same either
way. So it is read on the open path — an operator who has to cap a
server’s footprint cannot be told to use a different constructor.
An unparseable or zero value is an error, for the same reason a misspelled arm is: a silent fallback would let an operator believe a measurement came from a ceiling that was never applied.