Skip to main content

CommitHistory

Struct CommitHistory 

Source
pub struct CommitHistory<X: Executor = TokioExecutor> { /* private fields */ }
Expand description

Append-only Merkle history of commit hashes for one branch.

Two construction modes:

  1. CommitHistory::open — purely in-memory. Useful for tests and for callers that don’t want any disk side-effects. Lost on drop.
  2. CommitHistory::open_at — on-disk journaled MMR under <mkit_dir>/history/<branch>/. Survives process exit.

Each call to a sync method (append, root, prove) on the journaled flavour drives an async operation on the underlying commonware-storage::journaled::Mmr via the caller-supplied Executor.

Implementations§

Source§

impl CommitHistory<TokioExecutor>

Source

pub fn open() -> Self

Open a fresh empty in-memory history (mem-backed shape).

Lost on drop. Useful for unit tests and for callers that just need a proof bundle without committing any state to disk.

Source§

impl<X: Executor + 'static> CommitHistory<X>

Source

pub fn open_at( executor: Arc<X>, layout: &RepoLayout, branch: &str, ) -> Result<Self, HistoryError>

Open a persisted history under <common dir>/history/<branch>/.

The on-disk layout is commonware-storage’s native journaled MMR shape — see HISTORY_DIR and SPEC-HISTORY-PROOF §4. If the underlying journal does not yet exist, it is created empty (subsequent CommitHistory::append calls populate it).

Crash recovery is delegated to commonware: its Journaled::init detects a half-written trailing leaf, rewinds the journal to the last valid size, and re-derives the in-memory state. See SPEC-HISTORY-PROOF §4.4 for the contract surfaced to mkit callers.

§Errors
Source

pub fn common_dir(&self) -> Option<&Path>

Borrow the common dir this history was opened against. None for the mem-only flavour. Used by crate::refs::update_ref_with_history to take a RepoLock around the ref-write + MMR-append critical section.

Source

pub fn branch(&self) -> Option<&str>

Borrow the branch name this history was opened against. None for the mem-only flavour.

Source

pub fn reopen(&mut self) -> Result<(), HistoryError>

Re-derive this handle’s in-memory state from the current on-disk journal. A no-op for the mem-only flavour.

CommitHistory::open_at may run before the caller has taken any cross-process lock (opening the journal is cheap and the lock is only needed around the ref-write + append critical section — see crate::refs::update_ref_with_history). If another process appended to the same on-disk journal in the window between that open_at and this handle’s own locked critical section, this handle’s leaf count / root would be stale, and appending against stale state risks writing a leaf at a position the on-disk journal has already used. Callers that hold a cross-process lock around their critical section MUST call this once after acquiring it and before appending, so the append is always against what is truly on disk.

§Errors

Same as CommitHistory::open_at: HistoryError::Corrupted if commonware cannot recover the journal, HistoryError::RuntimeBootstrap if the runtime bootstrap fails, HistoryError::Io for filesystem failures.

§Bootstrap cost (issue #640)

This does NOT spawn a second commonware Context bootstrap. CommitHistory::open_at’s bootstrap thread already built a full tokio runtime, metrics task, and buffer pools for this handle; re-running that per call would double the cost of every history-tracked ref write for no benefit, since the bootstrapped Context is reusable — only the MMR’s in-memory view of the on-disk journal needs re-deriving. reopen takes a labelled child of the handle’s own already-live Context and re-runs JournaledMmr::init against it, which is what actually picks up a concurrent writer’s append.

Source

pub fn append(&mut self, commit_hash: &Hash) -> Result<Position, HistoryError>

Append a commit hash. Returns its leaf Position.

Positions are dense: the n-th append returns Position(n). For the journaled flavour, the underlying MMR is sync’d to disk before returning — survives a SIGKILL immediately after.

A thin wrapper over Self::append_no_sync + Self::sync — see those for the split. Callers appending many leaves in one critical section (e.g. rebuild_from_chain’s backfill) should call the two halves directly instead, batching the fsync.

Source

pub fn root(&self) -> Hash

Current MMR root digest. 32-byte BLAKE3 (mkit Hash shape).

Defined for an empty history — commonware returns a deterministic empty-MMR root (see SPEC-HISTORY-PROOF §2.3).

§Panics

Never panics in practice. Internally calls commonware’s root(&hasher, 0), which only returns an error for a non-zero inactive-peak count; mkit always requests 0 inactive peaks (its proofs are self-contained over the full leaf set), so the Result is always Ok.

Source

pub fn len(&self) -> u64

Number of leaves (commits) appended so far.

Source

pub fn is_empty(&self) -> bool

true if no commits have been appended.

Source

pub fn prove(&self, position: Position) -> Result<InclusionProof, HistoryError>

Build an inclusion proof for the commit at position.

Source

pub fn destroy(self) -> Result<(), HistoryError>

Permanently delete this history’s on-disk journal + metadata partitions (issue #648).

Consumes self: there is no valid handle to keep using once the backing storage is gone. A no-op for the mem-only flavour (there is nothing on disk to remove).

This is the primitive crate::refs::delete_ref_with_history uses to fence a branch’s journal on branch -d / branch -m: without it, re-creating a branch with a previously-used name would reopen the dead incarnation’s non-empty journal (same sanitized partition name) and resume appending on top of its old leaves — see SPEC-HISTORY-PROOF and issue #648 for the full write-up of the resulting stale-inclusion-proof bug.

§Errors

HistoryError::Mmr if commonware’s underlying journal/metadata destroy() fails (e.g. an I/O error removing the partition files).

Trait Implementations§

Source§

impl<X: Executor> Debug for CommitHistory<X>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for CommitHistory<TokioExecutor>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more