CacheLock

Struct CacheLock 

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

A file lock for cache operations

Implementations§

Source§

impl CacheLock

Source

pub async fn acquire(cache_dir: &Path, source_name: &str) -> Result<Self>

Acquires an exclusive lock for a specific source in the cache directory.

This async method creates and acquires an exclusive file lock for the specified source name. The file locking operation uses spawn_blocking internally to avoid blocking the tokio runtime, while still providing blocking file lock semantics.

§Lock File Management

The method performs several setup operations:

  1. Locks directory creation: Creates .locks/ directory if needed
  2. Lock file creation: Creates {source_name}.lock file
  3. Exclusive locking: Acquires exclusive access via OS file locking
  4. Handle retention: Keeps file handle open to maintain lock
§Async and Blocking Behavior

If another process already holds a lock for the same source:

  • Async-friendly: Uses spawn_blocking to avoid blocking the tokio runtime
  • Blocking wait: The spawned task blocks until other lock is released
  • Fair queuing: Locks are typically acquired in FIFO order
  • No timeout: Task will wait indefinitely (use with caution)
  • Interruptible: Can be interrupted by process signals
§Lock File Location

Lock files are created in a dedicated subdirectory:

{cache_dir}/.locks/{source_name}.lock

Examples:

  • ~/.ccpm/cache/.locks/community.lock
  • ~/.ccpm/cache/.locks/work-tools.lock
  • ~/.ccpm/cache/.locks/my-project.lock
§Parameters
  • cache_dir - Root cache directory path
  • source_name - Unique identifier for the source being locked
§Returns

Returns a CacheLock instance that holds the exclusive lock. The lock remains active until the returned instance is dropped.

§Errors

The method can fail for several reasons:

§Directory Creation Errors
  • Permission denied creating .locks/ directory
  • Disk space exhausted
  • Path length exceeds system limits
§File Operation Errors
  • Permission denied creating/opening lock file
  • File system full
  • Invalid characters in source name
§Locking Errors
  • File locking not supported by file system
  • Lock file corrupted or in invalid state
  • System resource limits exceeded
§Platform Considerations
  • Windows: Uses Win32 LockFile API via fs4
  • Unix: Uses POSIX fcntl() locking via fs4
  • NFS/Network: Behavior depends on file system support
  • Docker: Works within containers with proper volume mounts
§Examples

Simple lock acquisition:

use ccpm::cache::lock::CacheLock;
use std::path::PathBuf;

let cache_dir = PathBuf::from("/home/user/.ccpm/cache");

// This will block if another process has the lock
let lock = CacheLock::acquire(&cache_dir, "my-source").await?;

// Perform cache operations safely...
println!("Lock acquired successfully!");

// Lock is released when 'lock' variable is dropped
drop(lock);

Error handling for lock acquisition:

use ccpm::cache::lock::CacheLock;
use std::path::PathBuf;

let cache_dir = PathBuf::from("/tmp/cache");

match CacheLock::acquire(&cache_dir, "problematic-source").await {
    Ok(lock) => {
        println!("Lock acquired, proceeding with operations");
        // Use lock...
    }
    Err(e) => {
        eprintln!("Failed to acquire lock: {}", e);
        eprintln!("Another process may be using this source");
        return Err(e);
    }
}

Trait Implementations§

Source§

impl Drop for CacheLock

Source§

fn drop(&mut self)

Executes the destructor for this 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<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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: 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: 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> 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
Source§

impl<T> ErasedDestructor for T
where T: 'static,