Skip to main content

RefManager

Struct RefManager 

Source
pub struct RefManager { /* private fields */ }
Expand description

Manager for references (threads, markers, HEAD).

Implementations§

Source§

impl RefManager

Source§

impl RefManager

Source

pub fn new(heddle_dir: impl AsRef<Path>) -> Self

Source

pub fn with_local_head(self, path: PathBuf) -> Self

Source

pub fn with_reconciler(self, reconciler: Arc<dyn RefReconciler>) -> Self

Inject the oplog-backed reconciler (heddle#330 §2.2). Once set, every logical read funnels through RefManager::reconciled_load and reconciles against the committed oplog tail. Mirrors the with_local_head builder shape.

The class watermarks are seeded to the current generation: this handle trusts the already-published canonical cache as of open and reconciles only commits made after it — the load-bearing long-held handle cell (the daemon’s Arc<Repository>, cid 3328112197) an open-time-only pass cannot reach. (Catching a pre-open crash lag is the job of the optional Repository::open eager pass, deferred here as the spike’s stated optimization, not the guarantee.) Seeding to the current generation also keeps reconciliation from re-deriving long-since-deleted refs from old records in the un-migrated tree, where deletes do not all record yet.

Source

pub fn with_committer(self, committer: Arc<dyn RefCommitter>) -> Self

Inject the oplog-backed committer (heddle#330 §2.2 write chokepoint). Once set, commit_and_publish appends the caller’s ref-carrying records before publishing the ref batch.

Source

pub fn commit_and_publish( &self, records: &[OpRecord], ref_updates: &[RefUpdate], scope: Option<&str>, ) -> Result<()>

The atomic-write entry of THE write chokepoint (heddle#330 §2.2): commit the caller-supplied ref-carrying record batch (phase 4) before publishing the atomic ref batch (phase 5), record-before-publish, the whole batch published as one unit. The bare publish (temp→rename, via update_refs_with_lock) is reachable through this seam, never with a ref published ahead of its record. With no committer it degrades to a plain publish (bootstrap).

Invariant (cid 3329490978 / 3329490984): the oplog record and the ref publish commit together under the refs lock; a record exists iff its publish succeeded, and concurrent publishes to the same ref serialize record-and-publish as a unit. Routed through write_chokepoint, which takes the refs lock FIRST and materializes the committed-but-unpublished tail of every class BEFORE the body runs; the ref expectations are then validated (phase 3) against that reconciled state, BEFORE the record is appended (phase 4), and the publish (phase 5) follows under the same lock — so a failed expectation never leaks a record, and two concurrent callers can never append in one order and publish in another. (For PgRefBackend the single pool.begin()…commit() gives the same atomicity natively.)

Source

pub fn materialize_snapshot_thread_after_commit( &self, thread: &ThreadName, state: StateId, tip: u64, ) -> Result<()>

Atomically publish a just-committed attached snapshot as a reconstructible materialized view. The caller already owns the authoritative state and oplog tip, so replaying the same oplog tail through a fresh reconciler here only adds file/index I/O to every capture. The persisted watermarks deliberately remain at their prior durable floor for fresh-process recovery.

Source

pub fn materialize_snapshot_head_after_commit( &self, state: StateId, tip: u64, ) -> Result<()>

Detached-HEAD counterpart to materialize_snapshot_thread_after_commit.

Source

pub fn init_reconcile_watermark(&self) -> Result<()>

Seed the per-read watermarks from the persisted last-clean point (heddle#354 r5, cid 3329631074), so a fresh handle recovers a prior process’s committed-but-unpublished crash tail.

A RefManager seeds its in-memory watermarks at the current generation (with_reconciler) — so the per-read gate, on a fresh process, would never fold a record committed before this handle opened, and a cross-process crash (phase-4 committed, phase-5 publish never ran) would be silently lost. The fix is NOT an eager open-time fold (that would re-derive long-since-deleted refs from ancient records, since the un-migrated delete paths do not all record yet): it is a persisted watermark. Reads advance and persist it past every materialized record, so on open the seed sits at the last point canonical was known-consistent; the per-read reconcile then folds only (seed, tip] — the genuine crash tail — and never the ancient records below the seed.

When no watermark has been persisted yet (a fresh repo, or a repo from before this version), seed conservatively at the current generation and write the file, so the next process has a real last-clean point.

The two classes seed from SEPARATE files: the local watermark from the per-worktree file, the shared watermark from the shared-dir file (cid 3329711893). A sibling worktree that already advanced the shared watermark publishes it to the shared file, so this checkout seeds at that shared last-clean point and never re-folds a shared create the sibling already processed.

Source

pub fn init(&self) -> Result<()>

Source

pub fn cleanup_stale_temps(&self)

Source

pub fn read_head(&self) -> Result<Head>

Source

pub fn write_head(&self, head: &Head) -> Result<()>

Source

pub fn write_head_cas( &self, expected: RefExpectation<Head>, head: &Head, ) -> Result<()>

Source

pub fn get_thread(&self, name: &ThreadName) -> Result<Option<StateId>>

Source

pub fn set_thread(&self, name: &ThreadName, state: &StateId) -> Result<()>

Source

pub fn set_thread_cas( &self, name: &ThreadName, expected: RefExpectation<StateId>, state: &StateId, ) -> Result<()>

Source

pub fn delete_thread(&self, name: &ThreadName) -> Result<Option<StateId>>

Source

pub fn delete_thread_cas( &self, name: &ThreadName, expected: RefExpectation<StateId>, ) -> Result<()>

Source

pub fn list_threads(&self) -> Result<Vec<ThreadName>>

Source

pub fn list_threads_with_states(&self) -> Result<Vec<(ThreadName, StateId)>>

List thread names and targets through one reconciled list read. The summary index is updated by reconciliation before it is read here, so callers avoid one logical point read per listed thread.

Source

pub fn get_marker(&self, name: &MarkerName) -> Result<Option<StateId>>

Source

pub fn create_marker(&self, name: &MarkerName, state: &StateId) -> Result<()>

Source

pub fn set_marker_cas( &self, name: &MarkerName, expected: RefExpectation<StateId>, state: &StateId, ) -> Result<()>

Source

pub fn delete_marker(&self, name: &MarkerName) -> Result<Option<StateId>>

Source

pub fn delete_marker_cas( &self, name: &MarkerName, expected: RefExpectation<StateId>, ) -> Result<()>

Source

pub fn list_markers(&self) -> Result<Vec<MarkerName>>

Source

pub fn set_undo_recovery(&self, state: &StateId) -> Result<()>

Record the heddle-internal pre-undo recovery pointer (ORIG_HEAD-style: a single rolling ref each undo overwrites). Stored OUTSIDE the user-writable marker namespace so marker create/delete — and their undo inverses — can never collide with it. See UNDO_RECOVERY_HANDLE for the resolution handle.

Source

pub fn clear_undo_recovery(&self) -> Result<()>

Remove the heddle-internal pre-undo recovery pointer, returning the repo to the “no undo has run” state. Routes through the same write_chokepoint as the setter so it cannot bypass reconciliation, and is a no-op when no pointer exists. Used as the inverse of set_undo_recovery when the atomic undo transaction rewinds and the pointer had no prior value to restore (the first-ever undo): the pointer is written with no oplog record of its own, so deleting the canonical file is a complete clear.

Source

pub fn get_undo_recovery(&self) -> Result<Option<StateId>>

Read the heddle-internal pre-undo recovery pointer, if one has been recorded. Returns None when no undo has run in this repo.

Source

pub fn get_remote_thread( &self, remote: &str, thread: &ThreadName, ) -> Result<Option<StateId>>

Source

pub fn set_remote_thread( &self, remote: &str, thread: &ThreadName, state: &StateId, ) -> Result<()>

Source

pub fn delete_remote_thread( &self, remote: &str, thread: &ThreadName, ) -> Result<Option<StateId>>

Source

pub fn list_remotes(&self) -> Result<Vec<String>>

Source

pub fn list_remote_threads(&self, remote: &str) -> Result<Vec<ThreadName>>

Source

pub fn update_refs(&self, updates: &[RefUpdate]) -> Result<()>

Source

pub fn resolve(&self, refspec: &str) -> Result<Option<StateId>>

Source

pub fn pack_refs(&self) -> Result<()>

Source§

impl RefManager

Source

pub fn set_synthetic_frontier( &self, name: &SyntheticFrontierName, state: &StateId, ) -> Result<()>

Persist a synthetic frontier root. Does not construct a [ThreadName].

Source

pub fn get_synthetic_frontier( &self, name: &SyntheticFrontierName, ) -> Result<Option<StateId>>

Fetch a synthetic frontier root by its type-distinct name.

Source

pub fn list_synthetic_frontiers( &self, ) -> Result<Vec<(SyntheticFrontierName, StateId)>>

List every stored synthetic frontier root.

Trait Implementations§

Source§

impl CoreRefBackend for RefManager

Source§

type Error = HeddleError

Source§

fn read_head(&self) -> Result<Head>

Source§

fn write_head(&self, head: &Head) -> Result<()>

Source§

fn write_head_cas( &self, expected: RefExpectation<Head>, head: &Head, ) -> Result<()>

Source§

async fn get_thread(&self, name: &ThreadName) -> Result<Option<StateId>>

Source§

fn set_thread(&self, name: &ThreadName, state: &StateId) -> Result<()>

Source§

fn set_thread_cas( &self, name: &ThreadName, expected: RefExpectation<StateId>, state: &StateId, ) -> Result<()>

Source§

fn delete_thread(&self, name: &ThreadName) -> Result<Option<StateId>>

Source§

fn delete_thread_cas( &self, name: &ThreadName, expected: RefExpectation<StateId>, ) -> Result<()>

Source§

fn list_threads(&self) -> Result<Vec<ThreadName>>

Source§

async fn get_marker(&self, name: &MarkerName) -> Result<Option<StateId>>

Source§

async fn create_marker(&self, name: &MarkerName, state: &StateId) -> Result<()>

Source§

fn set_marker_cas( &self, name: &MarkerName, expected: RefExpectation<StateId>, state: &StateId, ) -> Result<()>

Source§

fn delete_marker(&self, name: &MarkerName) -> Result<Option<StateId>>

Source§

fn delete_marker_cas( &self, name: &MarkerName, expected: RefExpectation<StateId>, ) -> Result<()>

Source§

fn list_markers(&self) -> Result<Vec<MarkerName>>

Source§

fn update_refs(&self, updates: &[RefUpdate]) -> Result<()>

Source§

async fn resolve(&self, refspec: &str) -> Result<Option<StateId>>

Source§

impl RefBackend for RefManager

Source§

fn can_commit_records(&self) -> bool

Whether this backend can durably commit a non-empty operation record batch at the commit_and_publish seam. Read more
Source§

fn get_remote_thread( &self, remote: &str, thread: &ThreadName, ) -> Result<Option<StateId>>

Source§

fn set_remote_thread( &self, remote: &str, thread: &ThreadName, state: &StateId, ) -> Result<()>

Source§

fn delete_remote_thread( &self, remote: &str, thread: &ThreadName, ) -> Result<Option<StateId>>

Source§

fn list_remotes(&self) -> Result<Vec<String>>

Source§

fn list_remote_threads(&self, remote: &str) -> Result<Vec<ThreadName>>

Source§

fn commit_and_publish( &self, records: &[OpRecord], ref_updates: &[RefUpdate], scope: Option<&str>, ) -> Result<()>

The write chokepoint (heddle#330 §2.2 r18): append the caller-supplied ref-carrying record batch (phase 4, typed OpRecords) before publishing the atomic ref batch (phase 5), record-before-publish. The seam is per backend: the file backend (RefManager) earns atomicity by oplog-append-then-publish + per-read reconciliation; the Postgres backend co-commits the record row and ref/head rows in one SQL transaction (native ACID). Read more
Source§

fn inspect_ref_summary_index(&self) -> Result<RefSummaryIndexInspection>

Source§

fn rebuild_ref_summary_index(&self) -> Result<RefSummaryIndexInspection>

Source§

fn pack_refs(&self) -> Result<()>

Source§

fn cleanup_stale_temps(&self)

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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> 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> 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, <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<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