Skip to main content

ValidatedRepository

Struct ValidatedRepository 

Source
pub struct ValidatedRepository<'index, 'repo, R: Repository + ?Sized> { /* private fields */ }
Expand description

Validate and index a stable repository, including streaming-only providers.

Checks repository-format IDs, unique enumeration, links and target kinds, tree modes, names, Git ordering and duplicates, tag links/peeling, and exact reachability from the union of HEAD and refs. Commit parents are followed; gitlinks name external repositories and are not followed. Branches and resolved HEAD must name commits.

This is graph validation, not a replacement for all of Git’s fsck policies: identity semantics, platform-specific filename aliases, and special files such as .gitmodules are outside its scope.

The provider must remain stable after validation. Bodies are never retained or copied in full. Enumeration/IDs/metadata use the index; body reads and refs continue to use the provider.

Implementations§

Source§

impl<R: Repository + ?Sized> ValidatedRepository<'_, '_, R>

Source

pub fn select_revision_fetch<'selected>( &self, roots: &[ObjectId], history: (impl IntoIterator<Item = Result<ObjectId>>, impl IntoIterator<Item = Result<ObjectId>>, impl IntoIterator<Item = Result<ObjectId>>), work: &mut [Option<ValidationMetadata>], selected: &'selected mut [usize], scratch: (&mut [u8], &mut [u8], &mut RevisionState<'_>), options: (SelectionOptions, FetchOptions, RevisionOptions), ) -> Result<&'selected [usize]>

Select revision-limited history with separate caller-owned boundary state. history contains common commits, client boundaries, and resolved exclusion endpoints. This additive path rejects an absolute depth, preserves blob filtering/ascending indices, and shares structural bytes across every pass. Exclusion and candidate passes visit commits only; payload traversal follows trees/tags with the existing validated graph contract. No blob body is read. Existing shallow commits are known, and unshallow transitions seed parents; common haves outside candidate history cannot hide newly requested history. Metadata scans are bounded by object capacity (quadratic worst case), and exclusion count is capped independently. Total preparation CPU accounting is a separate host concern, as with ordinary bounded selection.

Source§

impl<'index, 'repo, R: Repository + ?Sized> ValidatedRepository<'index, 'repo, R>

Source

pub fn new( repository: &'repo R, object_storage: &'index mut [Option<ValidationMetadata>], index_storage: &'index mut [usize], read_scratch: &mut [u8], parse_scratch: &mut [u8], ) -> Result<Self>

Each metadata/index array needs object_count slots; extra slots are untouched. Initialize metadata with [None; N]. Read scratch needs at least one byte for nonempty bodies. Empty repositories need no scratch. Parse scratch must fit the longest commit/tag header line (excluding LF), and twice the longest tree name (excluding NUL). Neither scratch buffer is retained. Their sizes do not limit body sizes.

Insufficient arrays/scratch return BufferTooSmall, absent objects/links ObjectNotFound, invalid refs InvalidReference, invalid names InvalidFileName, and ordering/duplicate names UnsortedFiles. Invalid IDs, kinds, framing, modes, duplicate IDs or unreachable objects return InvalidObject. Backend errors propagate. Discard partial arrays on error.

Hashing is linear in body bytes. Lookup uses binary search. Traversal scans pending metadata without recursion, using O(n^2) metadata probes in the worst case. Directory/file duplicate detection can reread earlier tree entries, trading worst-case quadratic tree reads for bounded memory.

Source

pub fn metadata(&self, index: usize) -> Option<&ValidationMetadata>

Source

pub fn select_objects<'selected>( &self, roots: &[ObjectId], work: &mut [Option<ValidationMetadata>], selected: &'selected mut [usize], read_scratch: &mut [u8], parse_scratch: &mut [u8], graph_read_limit: u64, ) -> Result<&'selected [usize]>

Select the exact reachable union of explicit object IDs without allocation. Each work/index array needs object_count slots. Read/parse budgets have the same requirements as validation; graph bodies are read again, not hashed. The result borrows only selected, in the provider’s enumeration order. Overlapping roots are deduplicated. Gitlinks remain external. A failed selection invalidates the work arrays; every retry resets all traversal state. graph_read_limit caps actual structural reads, including prefetch and rereads for tree duplicate checks; exhaustion returns LimitExceeded. Blob bodies and opaque commit/tag messages are not traversed. Metadata probes are bounded by the object-array capacity (quadratic worst case). Independent requests use independent caller storage. This primitive accepts any present root; HTTP’s advertised-want policy is separate.

Source

pub fn select_missing_objects<'selected>( &self, roots: &[ObjectId], common: impl IntoIterator<Item = Result<ObjectId>>, work: &mut [Option<ValidationMetadata>], selected: &'selected mut [usize], scratch: (&mut [u8], &mut [u8]), graph_read_limit: u64, ) -> Result<&'selected [usize]>

Select the wanted closure minus the complete closure of common roots. Common roots must be present, and are trusted to describe complete client history (shallow clients must be rejected by the protocol layer). Both traversals share one graph-read budget and the same caller-owned arrays. Common-root iteration may fail (for example, a host metadata read); errors propagate. Unknown roots fail; retries reset exclusions and traversal state.

Source

pub fn select_fetch_objects<'selected>( &self, roots: &[ObjectId], common: impl IntoIterator<Item = Result<ObjectId>>, work: &mut [Option<ValidationMetadata>], selected: &'selected mut [usize], scratch: (&mut [u8], &mut [u8]), options: SelectionOptions, ) -> Result<&'selected [usize]>

Select missing objects and optionally include advertised annotated tags whose final peeled targets are being sent. Tag traversal shares the graph-read budget with wanted and common history; retries reset all state.

Source

pub fn select_bounded_fetch<'selected>( &self, roots: &[ObjectId], history: (impl IntoIterator<Item = Result<ObjectId>>, impl IntoIterator<Item = Result<ObjectId>>), work: &mut [Option<ValidationMetadata>], selected: &'selected mut [usize], scratch: (&mut [u8], &mut [u8]), options: (SelectionOptions, FetchOptions), ) -> Result<&'selected [usize]>

Select shallow/filtered history with caller-owned arrays. Client shallow IDs must name present commits. Common traversal stops at those commits; depth requests instead resend their closure without trusting common haves. Relative requests from full clients preserve ordinary common exclusion. Relative depth measures the nearest boundary from wanted history, then extends that absolute cut (Git 2.55). Both passes share the budget. Work metadata retains shallow/unshallow markers until the next selection. All structural reads, including revisits after a shorter merge path, consume one budget. Retries reset depths, exclusions and boundary markers.

history contains common roots followed by the client’s shallow IDs. Each work/index slice needs one slot per repository object. Extra slots remain untouched. The returned indices use provider enumeration order; inspect only the first object_count() work slots for boundary updates. A depth request may resend common objects, while an ordinary request subtracts common history only as far as the client’s declared boundaries.

Empty wants, zero/oversized depth and absent or non-commit shallow IDs return InvalidRequest. Missing wanted/common objects return ObjectNotFound; short arrays or scratch return BufferTooSmall, and exhausted structural-read budgets return LimitExceeded. No result is published on failure; reuse the same arrays for a fresh attempt.

This example selects a depth-one snapshot without its blob. The root commit is a shallow boundary even though it has no parents, matching Git. The source, validation index and per-request work arrays are independent.

use git_zero_core::{
    BlobFilter, FetchOptions, File, Repository, SelectionOptions, Snapshot,
    ValidatedRepository,
};
let files = [File { name: "hello.txt", contents: b"hello\n" }];
let (mut tree, mut commit) = ([0; 128], [0; 512]);
let snapshot = Snapshot::new(&files, &mut tree, &mut commit)?;
let (mut metadata, mut by_id) = ([None; 3], [0; 3]);
let repository = ValidatedRepository::new(
    &snapshot, &mut metadata, &mut by_id, &mut [0; 64], &mut [0; 128],
)?;
let (mut work, mut indices) = ([None; 3], [0; 3]);
let wanted = [repository.head()];
let selected = repository.select_bounded_fetch(
    &wanted, (core::iter::empty(), core::iter::empty()),
    &mut work, &mut indices, (&mut [0; 64], &mut [0; 128]),
    (SelectionOptions { graph_read_limit: 4096, include_tags: false },
     FetchOptions { depth: Some(1), filter: BlobFilter::None, ..FetchOptions::default() }),
)?;
assert_eq!(selected.len(), 2); // Commit and tree, with no blob.
let boundary = work.iter().flatten().find(|object| object.is_shallow()).unwrap();
assert_eq!(boundary.id, repository.head());

Trait Implementations§

Source§

impl<R: Repository + ?Sized> Repository for ValidatedRepository<'_, '_, R>

Source§

fn object_format(&self) -> ObjectFormat

Fixed for the entire repository, including unborn HEAD. Defaults to SHA-1; SHA-256 providers must override this independently of object_id.
Source§

fn head(&self) -> ObjectId

Resolved commit ID, or the all-zero sentinel for an unborn HEAD. Use head_state().id() when absence needs to be distinguished.
Source§

fn head_state(&self) -> Head<'_>

Source§

fn object_count(&self) -> usize

Source§

fn object(&self, index: usize) -> Option<Object<'_>>

Optional borrowed-body fast path. Streaming providers can leave this as None and implement object_info, read_object, and object_id instead.
Source§

fn object_info(&self, index: usize) -> Result<ObjectInfo>

Source§

fn object_id(&self, index: usize) -> Option<ObjectId>

Return an object’s ID. Streaming providers must supply precomputed IDs; ObjectHasher computes them incrementally with caller-owned scratch.
Source§

fn read_object( &self, index: usize, offset: u64, storage: &mut [u8], ) -> Result<usize>

Read at most storage.len() body bytes starting at a byte offset. Short reads are allowed. Return zero only at EOF or for empty storage. Calls must be independent of earlier reads, enabling interleaved readers and retries. Errors may modify storage but must not change the object.
Source§

fn find_index(&self, id: ObjectId) -> Option<usize>

Lookup without requiring a borrowed body. Metadata providers can index it.
Source§

fn head_ref(&self) -> &str

Source§

fn reference_count(&self) -> usize

Source§

fn reference_name(&self, index: usize) -> Option<&str>

Source§

fn reference_id(&self, index: usize) -> Option<ObjectId>

Defaults preserve snapshot commit aliases. Override for independent tips.
Source§

fn reference_symbolic_target(&self, index: usize) -> Option<&str>

Source§

fn reference_peeled(&self, index: usize) -> Option<ObjectId>

Source§

fn find(&self, id: ObjectId) -> Option<Object<'_>>

Auto Trait Implementations§

§

impl<'index, 'repo, R> Freeze for ValidatedRepository<'index, 'repo, R>
where &'repo R: Freeze, R: ?Sized,

§

impl<'index, 'repo, R> RefUnwindSafe for ValidatedRepository<'index, 'repo, R>

§

impl<'index, 'repo, R> Send for ValidatedRepository<'index, 'repo, R>
where &'repo R: Send, R: ?Sized,

§

impl<'index, 'repo, R> Sync for ValidatedRepository<'index, 'repo, R>
where &'repo R: Sync, R: ?Sized,

§

impl<'index, 'repo, R> Unpin for ValidatedRepository<'index, 'repo, R>
where &'repo R: Unpin, R: ?Sized,

§

impl<'index, 'repo, R> UnsafeUnpin for ValidatedRepository<'index, 'repo, R>

§

impl<'index, 'repo, R> UnwindSafe for ValidatedRepository<'index, 'repo, R>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.