Expand description
The exploded objects table: ONE Arrow IPC file, one row per object.
§What this replaces, and what it measured
crate::exploded holds oid → [kind][payload…] in redb. It works, and
it is the wrong medium — MEASURED on linux.git, oden 2026-08-13,
11 697 976 objects:
| pack as pushed (verbatim, deflated + delta-encoded) | 6.4 GB |
its objects fully resolved (git verify-pack -v, summed) | 16.8 GB |
objects.exploded on disk | 204 GB |
So the 2026-08-08 eager decision was RIGHT — resolved content is 2.6× the
pack, comfortably inside the 3× it budgeted — and the medium was wrong by
12×. redb is a copy-on-write B-tree: 11.7 million small keys committed in
FLUSH_BYTES batches rewrite interior pages over and over, and 187 of
those 204 GB are page churn rather than anybody’s data.
It cost throughput for the same reason. crate::indexer fans a drained
batch across N workers with gatling_for_each (LAW 3, never rayon) and every
one of them then queued behind redb’s single write transaction — MEASURED:
96.8% of ONE core with 31 idle while the exploder ran.
§The shape
One table, one file, the payload IN the row — which is what this engine
already does everywhere else (crate::reach stores a bitmap as
DataType::Binary, crate::secrets a ciphertext):
oid | object_type | mode | path | payloadAn Arrow IPC stream is [schema message][batch message]… — append-only, no
pages to rewrite, so the file is the payload total plus framing. Each flush
encodes one batch with IpcDataGenerator and appends it with
write_message; nothing earlier in the file is ever touched again.
payload is LargeBinary and not Binary deliberately: Binary offsets are
i32, so one batch would cap at 2 GiB of payload and overflow silently on a
corpus nobody tested. The wider offset costs four bytes a row.
§mode and path — the row IS a file
A git object on its own is content without a name. The two nullable columns carry the name when the caller knows it (a tree walk does; a bare pack resolve does not), which is what lets this table be read as a filesystem rather than as a content-addressed bag. They are nullable and best-effort for a reason that is inherent and not a shortcut: one blob is reachable at many paths in many commits, so a path column can only ever record a path — the one it was first exploded at. Null means “not known here”, never “at the root”.
§Reopening is cheap, and the index is lazy
A batch’s metadata carries its row count and its body length, so
ExplodedArchive::open walks the message framing — seeking over the bodies,
reading kilobytes — and knows how many rows the table holds and where every
batch begins without touching a gigabyte. That is what adopt_journal needs
on startup.
The oid → row index costs one sequential pass and is therefore built on the
first lookup, not on open. A push-heavy process never pays for it; a
process that reads pays once. After that a point read is two preads — the
schema message and the one batch — decoded through StreamDecoder, so it
never scans the batches in front of the one it wants.
§The lookup is ragnar’s static tree — see [OidTree]
That index used to be a Vec<(Vec<u8>, Located)> walked with
binary_search_by: one heap allocation per oid — 11.7 million of them on
linux.git — and a log₂ n chain of dependent loads over scattered Vec
headers. It is now the same stree (znippy-zoomies) this crate already puts
over oids in crate::oid_index, over flat parallel arrays.
nornir-workspace.toml’s performance law names that structure by name; this
is the second place in this crate that obeys it, and it obeys it by reusing
crate::oid_index::key_for_oid rather than deriving a second key.
§Droppable, and it is one rm
Every row is re-derivable from the verbatim pack bytes, so the file can be
deleted without consulting a client:
[crate::git_ops::Absorber::adopt_journal] compares this table’s row count
against the objects table’s and re-queues every pack if it is short. Absent
means fall back and rebuild; it never means wrong. One file, one delete —
which is the property the engine’s own tests assert.
Structs§
- Exploded
Archive - §14’s derived table for one repository.
- Stats
- Counters, all of them applied output.
Enums§
- Explode
Policy - How much of a pack is resolved into the exploded table.
Constants§
- COL_
MODE - COL_OID
- COL_
PATH - COL_
PAYLOAD - COL_
TYPE - FLUSH_
BYTES - Buffered payload bytes that force a flush.
- TOMBSTONE
- A row that retires an oid.
Functions§
- exploded_
schema oid | object_type | mode | path | payload.- kind_
code - The pack type codes, the same mapping
crate::explodeduses, so the two media cannot disagree about what a2means. - kind_of