pub struct OneTableFourColumns { /* private fields */ }Expand description
One Arrow IPC section, one table, the facts one column each.
Arrow is columnar, so this is not row-contiguous: offset is its own
buffer, len is its own buffer, and a full-row fetch still touches five
strides that are megabytes apart. What it saves over FourTables is the
framing of three IPC streams and nothing else — which is exactly what the
measurement found.
The name counts the columns it had when it was named and measured; since
delta_base (PLAN §13) there are five payload columns here and in
FourTables alike, so the two are still separated by section count and
nothing else.
Implementations§
Source§impl OneTableFourColumns
impl OneTableFourColumns
pub fn oid_column(&self) -> &FixedSizeBinaryArray
Sourcepub fn column_is_inside_ipc(&self) -> bool
pub fn column_is_inside_ipc(&self) -> bool
All five arrays are views into the one IPC buffer.
Sourcepub fn ipc_slice(&self) -> &[u8] ⓘ
pub fn ipc_slice(&self) -> &[u8] ⓘ
The bytes this index would be persisted as — the single Arrow IPC
stream every column is a view into, exactly as [to_ipc] framed it.
ObjectIndex::ipc_bytes reports this buffer’s length, which is
enough to compare two layouts’ footprints and not enough to write one
down. examples/tail_write_bench.rs needs the bytes themselves: its
no-tail arm has to rewrite the whole index on every push, and a
measurement of that write is only honest if the bytes going to the file
are the index’s own and not a stand-in of the same size.
A borrowed slice and not a Vec: the buffer is already resident and
aligned, and handing out a copy would put an allocation inside the very
write this exists to measure.
Trait Implementations§
Source§impl ObjectIndex for OneTableFourColumns
impl ObjectIndex for OneTableFourColumns
Source§fn from_persisted(buf: Buffer) -> Result<Self>
fn from_persisted(buf: Buffer) -> Result<Self>
The buffer is decoded in place — decode_ipc_buffer, not decode_ipc,
so a memory-mapped file stays mapped and every column is a view into
it — and the stree is rebuilt over its oid column. The stree is the
one thing this does not read back: its section is a reader-side
structure GitOidIndex::parse_as derives, and building it is O(n) in
the oid count against the O(n log n) sort-and-encode a rebuild from
redb pays, with no B-tree walk in front of it.
fn build(entries: &[IndexEntry]) -> Result<Self>
Source§fn persists() -> bool
fn persists() -> bool
from_persisted. An arm that
answers false is never persisted: the stack then keeps every row in
redb and rebuilds from it, which is the pre-2026-09-04 behaviour, kept
as a correct fallback rather than made an error. Read moreSource§fn persisted_bytes(&self) -> Option<&[u8]>
fn persisted_bytes(&self) -> Option<&[u8]>
None for an arm with no such form.Source§fn oid_at(&self, ordinal: u32) -> Vec<u8> ⓘ
fn oid_at(&self, ordinal: u32) -> Vec<u8> ⓘ
ordinal. Every arm keeps a FixedSizeBinary oid
column, so this is one bounds-checked slice, copied out — owned rather
than borrowed so that a stack holding its projection behind a lock can
answer it too. Positional, like Arrow’s own value(i): an ordinal past
len() (or, on a stack, a tail-tagged one) is a programming error and
panics rather than answering.Source§fn entry_at(&self, ordinal: u32) -> IndexEntry
fn entry_at(&self, ordinal: u32) -> IndexEntry
ordinal, as the entry that would rebuild it.
The fold’s merge reads the projection back through this.Source§fn extent_at(&self, ordinal: u32) -> (u64, u64)
fn extent_at(&self, ordinal: u32) -> (u64, u64)
(offset, len) of the row at ordinal — positional, no oid, no
allocation. The crash-recovery diff scans the whole projection through
this, so it must cost a column read and nothing more.Source§fn oids_raw(&self) -> Vec<u8> ⓘ
fn oids_raw(&self) -> Vec<u8> ⓘ
len() × oid_len bytes.
This IS the ordinal space the derived tables address (__gunnar_reach__
bitmaps, the commit graph’s token), and on a persisted arm it is the oid
column’s own bytes: the thing objects.ordinal used to cache in a file
of its own, with a header and an epoch to validate it, is a contiguous
buffer this index already holds. The default is the positional loop; the
columnar arms hand back their column.Source§fn lookup(&self, oid: &[u8]) -> Option<IndexRow>
fn lookup(&self, oid: &[u8]) -> Option<IndexRow>
None for an absent oid and for an oid of the
wrong width.Source§fn lookup_batch(&self, oids: &[&[u8]]) -> Vec<Option<IndexRow>>
fn lookup_batch(&self, oids: &[&[u8]]) -> Vec<Option<IndexRow>>
have negotiation sends up to
1000 oids at a time, the push connectivity check sends thousands.
Positional — out[i] answers oids[i]. Read moreSource§fn ordinals_batch(&self, oids: &[&[u8]]) -> Vec<Option<u32>>
fn ordinals_batch(&self, oids: &[&[u8]]) -> Vec<Option<u32>>
Source§fn extents_batch(&self, oids: &[&[u8]]) -> Vec<Option<(u64, u64)>>
fn extents_batch(&self, oids: &[&[u8]]) -> Vec<Option<(u64, u64)>>
extents(&[oid]), what the wire path actually asks for
when it is about to copy bytes out of a pack.Source§fn sum_uncompressed(&self) -> u64
fn sum_uncompressed(&self) -> u64
Source§fn count_type(&self, t: ObjType) -> usize
fn count_type(&self, t: ObjType) -> usize
fn name(&self) -> &'static str
fn len(&self) -> usize
Source§fn ipc_bytes(&self) -> usize
fn ipc_bytes(&self) -> usize
Source§fn resident_bytes(&self) -> usize
fn resident_bytes(&self) -> usize
stree oid section — everything the index keeps
alive, excluding the handful of Arc’d schema/metadata allocations.fn is_empty(&self) -> bool
Source§fn entries(&self) -> Vec<IndexEntry>
fn entries(&self) -> Vec<IndexEntry>
len() allocations of oid, which
is the price of handing build a slice; the fold pays it once per fold
and nothing on the read path calls it.