Skip to main content

FileLock

pub struct FileLock { /* private fields */ }
Expand description

File locking mechanism with process ID tracking

Provides exclusive access to files by creating lock files that contain the process ID of the lock holder. This prevents race conditions when multiple processes attempt to access the same file concurrently.

§Lock Files

Lock files are named {file}.lock and contain the process ID as text. Example: ./data/my-env/state.json.lock contains “12345”

§Stale Lock Detection

If a process crashes while holding a lock, the lock file remains but the process is dead. This implementation detects stale locks by checking if the process ID in the lock file is still running, then automatically cleans up and retries.

§RAII Pattern

The lock is automatically released when the FileLock is dropped, ensuring cleanup even if an error occurs during file operations.

Implementations§

Source§

impl FileLock

Source

pub fn acquire( file_path: &Path, timeout: Duration, ) -> Result<Self, FileLockError>

Attempt to acquire a lock for the given file path

Creates a lock file at {file_path}.lock containing the current process ID. If the lock file already exists, checks if the holding process is still alive. If the process is dead, removes the stale lock and retries.

§Arguments
  • file_path - Path to the file to lock (the actual file, not the lock file)
  • timeout - Maximum time to wait for lock acquisition
§Returns

Returns FileLock on successful acquisition, which will automatically release the lock when dropped.

§Errors

Returns error if:

  • Another process holds the lock and timeout expires (AcquisitionTimeout)
  • Lock file cannot be created due to permissions (CreateFailed)
  • I/O error occurs during lock operations
§Examples
use std::path::Path;
use std::time::Duration;
use torrust_tracker_deployer_lib::infrastructure::persistence::filesystem::file_lock::FileLock;

let file_path = Path::new("./data/test/state.json");
let timeout = Duration::from_secs(10);

match FileLock::acquire(file_path, timeout) {
    Ok(lock) => {
        // Perform operations on the file
        // Lock automatically released when lock goes out of scope
    }
    Err(e) => eprintln!("Failed to acquire lock: {}", e),
}
Source

pub fn release(self) -> Result<(), FileLockError>

Release the lock by removing the lock file

This is called automatically when the FileLock is dropped, but can also be called explicitly for better error handling.

§Errors

Returns error if the lock file cannot be removed due to I/O issues.

§Examples
use std::path::Path;
use std::time::Duration;
use torrust_tracker_deployer_lib::infrastructure::persistence::filesystem::file_lock::FileLock;

let lock = FileLock::acquire(Path::new("test.json"), Duration::from_secs(5))?;
// ... perform operations ...
lock.release()?; // Explicit release with error handling

Trait Implementations§

Source§

impl Debug for FileLock

Source§

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

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

impl Drop for FileLock

Source§

fn drop(&mut self)

Automatically release the lock when the FileLock is dropped

This ensures cleanup even if an error occurs during file operations. Errors during cleanup are logged but otherwise ignored as this is best-effort cleanup.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. 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> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> IntoResult<T> for T

Source§

type Err = !

Source§

fn into_result(self) -> Result<T, <T as IntoResult<T>>::Err>

Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
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> 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, !>

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