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 or
PackLock::try_acquire for a fail-fast probe.
Note: PackLock::acquire is deprecated since v1.2.4; prefer
PackLock::acquire_async or PackLock::try_acquire. The sync
blocking variant will be removed in v1.3.0.
Implementations§
Source§impl PackLock
impl PackLock
Sourcepub fn open(pack_path: &Path) -> Result<Self, PackLockError>
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.
Sourcepub async fn acquire_async(self) -> Result<PackLockHold, PackLockError>
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
PackLockError::Busyon same-thread re-entry.PackLockError::Ioon any OS-level lock failure.
Sourcepub async fn acquire_cancellable(
self,
cancel: &CancellationToken,
) -> Result<PackLockHold, PackLockErrorOrCancelled>
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
PackLockErrorOrCancelled::Cancelled— the token fired before a guard was returned.PackLockErrorOrCancelled::LockwrappingPackLockError::Busyon same-thread re-entry, orPackLockError::Ioon any OS-level lock failure.
Sourcepub fn acquire(&mut self) -> Result<RwLockWriteGuard<'_, File>, PackLockError>
👎Deprecated since 1.2.4: use acquire_async for async contexts or try_acquire for non-blocking; sync acquire will be removed in v1.3.0
pub fn acquire(&mut self) -> Result<RwLockWriteGuard<'_, File>, PackLockError>
use acquire_async for async contexts or try_acquire for non-blocking; sync acquire will be removed in v1.3.0
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.
§Deprecation
Implementation strategy: restored as the original direct
blocking fd_lock::write() call (single-line body, no
behaviour change vs v1.2.3) — simpler and safer than a
busy-wait shim, since fd-lock already parks the calling OS
thread on the kernel flock and a busy-wait would burn CPU
without engaging the kernel waiter queue.
Sourcepub fn try_acquire(
&mut self,
) -> Result<RwLockWriteGuard<'_, File>, PackLockError>
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
PackLockError::Busywhen a concurrent holder owns the lock.PackLockError::Ioon any other OS-level lock failure.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for PackLock
impl RefUnwindSafe for PackLock
impl Send for PackLock
impl Sync for PackLock
impl Unpin for PackLock
impl UnsafeUnpin for PackLock
impl UnwindSafe for PackLock
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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