Skip to main content

ObjectIndex

Trait ObjectIndex 

Source
pub trait ObjectIndex: Send + Sync {
Show 20 methods // Required methods fn build(entries: &[IndexEntry]) -> Result<Self> where Self: Sized; fn lookup(&self, oid: &[u8]) -> Option<IndexRow>; fn lookup_batch(&self, oids: &[&[u8]]) -> Vec<Option<IndexRow>>; fn ordinals_batch(&self, oids: &[&[u8]]) -> Vec<Option<u32>>; fn extents_batch(&self, oids: &[&[u8]]) -> Vec<Option<(u64, u64)>>; fn sum_uncompressed(&self) -> u64; fn count_type(&self, t: ObjType) -> usize; fn name(&self) -> &'static str; fn len(&self) -> usize; fn ipc_bytes(&self) -> usize; fn resident_bytes(&self) -> usize; fn oid_at(&self, ordinal: u32) -> Vec<u8> ⓘ; fn entry_at(&self, ordinal: u32) -> IndexEntry; fn extent_at(&self, ordinal: u32) -> (u64, u64); // Provided methods fn is_empty(&self) -> bool { ... } fn persists() -> bool where Self: Sized { ... } fn persisted_bytes(&self) -> Option<&[u8]> { ... } fn from_persisted(buf: Buffer) -> Result<Self> where Self: Sized { ... } fn oids_raw(&self) -> Vec<u8> ⓘ { ... } fn entries(&self) -> Vec<IndexEntry> { ... }
}
Expand description

A git object index over Apache Arrow IPC.

build is where Self: Sized, so it stays out of the vtable and Box<dyn ObjectIndex> still works — which is how the bench drives both arms through one loop.

Required Methods§

Source

fn build(entries: &[IndexEntry]) -> Result<Self>
where Self: Sized,

Source

fn lookup(&self, oid: &[u8]) -> Option<IndexRow>

Resolve one oid. None for an absent oid and for an oid of the wrong width.

Source

fn lookup_batch(&self, oids: &[&[u8]]) -> Vec<Option<IndexRow>>

The batch path, and the one that matters: have negotiation sends up to 1000 oids at a time, the push connectivity check sends thousands. Positional — out[i] answers oids[i].

This is the full-row access pattern: all five facts of each object.

Source

fn ordinals_batch(&self, oids: &[&[u8]]) -> Vec<Option<u32>>

oid → ordinal and stop. No payload column is touched at all.

Identical in every implementation, because every implementation shares the same stree. It is here as the floor: whatever this costs is what no payload layout can remove, and lookup_batch minus this is the only part any of these layouts can change. Without it a three-way tie is unreadable — it could mean the layouts are equivalent, or it could mean the harness never read a payload byte.

Source

fn extents_batch(&self, oids: &[&[u8]]) -> Vec<Option<(u64, u64)>>

The partial-row access pattern: byte extent only, two of the five facts. This is 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

Full column scan: total uncompressed bytes over every object. The quota gate. Reads one 8-byte fact per row and nothing else.

Source

fn count_type(&self, t: ObjType) -> usize

Full column scan with a predicate: how many objects of this type. Reads one byte per row and nothing else — the most column-shaped query there is, and the one a row-packed layout should lose worst.

Source

fn name(&self) -> &'static str

Source

fn len(&self) -> usize

Source

fn ipc_bytes(&self) -> usize

Total bytes of Arrow IPC this index holds resident. Four sections or one, this counts the same payload, so it is comparable across arms.

Source

fn resident_bytes(&self) -> usize

IPC bytes plus the stree oid section — everything the index keeps alive, excluding the handful of Arc’d schema/metadata allocations.

Source

fn oid_at(&self, ordinal: u32) -> Vec<u8> ⓘ

The raw oid at 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

Every fact of the row at 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)

(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.

Provided Methods§

Source

fn is_empty(&self) -> bool

Source

fn persists() -> bool
where Self: Sized,

Whether this arm has a single-buffer form the stack can write down and read back with 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.

A Sized fn and not an associated const: a const would make the trait not dyn-compatible, and the layout benches hold &dyn ObjectIndex.

Source

fn persisted_bytes(&self) -> Option<&[u8]>

The bytes this index is persisted as — one self-contained Arrow IPC stream holding one record batch, or None for an arm with no such form.

Source

fn from_persisted(buf: Buffer) -> Result<Self>
where Self: Sized,

Reconstruct this index from a buffer persisted_bytes produced — typically a memory-mapped objects.index, so every array is a view into the page cache rather than a copy of it. Refuses a buffer this arm did not write (a different arm’s layout, a different format stamp).

Source

fn oids_raw(&self) -> Vec<u8> ⓘ

Every oid, back to back, in ordinal order — 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 entries(&self) -> Vec<IndexEntry>

All rows, in ordinal (= oid) order. 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.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§