Skip to main content

PackLock

Struct PackLock 

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

Per-pack file lock wrapper.

Construction via PackLock::open creates (or re-opens) the sidecar <pack_path>/.grex-lock but does not acquire the lock — call PackLock::acquire_async for the async-safe blocking path, PackLock::acquire for the thread-blocking synchronous path, or PackLock::try_acquire for a fail-fast probe.

Implementations§

Source§

impl PackLock

Source

pub fn open(pack_path: &Path) -> Result<Self, PackLockError>

Open (and create if missing) the sidecar <pack_path>/.grex-lock. Does not acquire the lock.

§Errors

Returns PackLockError::Io if the sidecar cannot be opened or its parent directory cannot be created.

Source

pub async fn acquire_async(self) -> Result<PackLockHold, PackLockError>

Async acquire — pairs a process-wide tokio::sync::Mutex keyed by canonical pack path with the sidecar fd-lock. Safe to call from any tokio worker without blocking the runtime. Same-thread re-entry (nested synchronous call chain that re-enters the same pack root, e.g. meta-plugin recursion through a .. child that points back at the parent) returns PackLockError::Busy rather than deadlocking.

The returned PackLockHold drops the fd-lock guard and the async mutex guard in reverse acquire order at end-of-scope.

§Errors
Source

pub async fn acquire_cancellable( self, cancel: &CancellationToken, ) -> Result<PackLockHold, PackLockErrorOrCancelled>

Cancellable async acquire — same semantics as PackLock::acquire_async but races the acquire against a tokio_util::sync::CancellationToken. Used by the embedded MCP server (feat-m7-1) so a notifications/cancelled from the client unblocks tool handlers that are parked on a contended pack lock.

Consumes self to mirror PackLock::acquire_async — the same boxed-fd + transmute lifetime dance is needed to hand the guard back across a spawn_blocking boundary, and reusing the consumes-self contract preserves drop ordering against PackLockHold.

§OS-thread leak window — contract

fd_lock::write() is a synchronous syscall that parks the calling OS thread until the kernel releases the flock. Once the blocking call has been launched on the tokio::task::spawn_blocking pool, the runtime cannot interrupt it — there is no portable way to unpark a thread blocked in flock(2). When the cancellation token fires we resolve the outer select! with PackLockErrorOrCancelled::Cancelled immediately, but the spawned OS thread stays parked until the holder eventually releases. When that happens, the spawned thread acquires the guard, the JoinHandle resolves to Ok((boxed, guard)), and the tuple is dropped on the spot (because the select! arm has already won) — at which point the guard’s Drop releases the kernel flock and a subsequent acquirer can proceed.

In other words: cancellation is observable to the caller instantly, but the underlying OS thread holds the lock briefly past the cancel point, until the syscall returns. Callers that immediately re-attempt acquire on the same path may see transient contention until that thread drains. See .omne/cfg/mcp.md §Cancellation.

§Errors
Source

pub fn acquire(&mut self) -> Result<RwLockWriteGuard<'_, File>, PackLockError>

Thread-blocking acquire (no tokio integration). Waits on the fd-lock synchronously. Suitable for synchronous call sites only — async plugin methods MUST use PackLock::acquire_async to avoid blocking a tokio worker.

Returns a borrowed RwLockWriteGuard; the caller owns both the outer PackLock and the guard in scope. Mirrors the crate::fs::ScopedLock shape.

§Errors

Returns PackLockError::Io if the OS lock call fails.

Source

pub fn try_acquire( &mut self, ) -> Result<RwLockWriteGuard<'_, File>, PackLockError>

Non-blocking probe: return PackLockError::Busy instead of waiting when another holder has the lock. Does not engage the async mutex — purely a fail-fast diagnostics hook.

§Errors
Source

pub fn path(&self) -> &Path

Sidecar path — <pack_path>/.grex-lock.

Trait Implementations§

Source§

impl Debug for PackLock

Source§

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

Formats the value using the given formatter. 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<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> 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> 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<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