Skip to content

Commit 8b7a529

Browse files
docs
1 parent d909a97 commit 8b7a529

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

crates/icp/src/fs/lock.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,40 @@
1-
use crate::prelude::*;
1+
//! File locking abstractions to make directory locks easy and safe.
2+
//!
3+
//! Directory structures are typically represented by a struct containing the directory path,
4+
//! which then has methods for getting files or directories within it. This struct should implement
5+
//! `PathsAccess`, and then instead of passing it around directly, it should be stored in a
6+
//! [`DirectoryStructureLock`]. This ensures that paths cannot be accessed without holding the appropriate
7+
//! lock.
8+
//!
9+
//! Temporary locks can be acquired using the `with_read` and `with_write` methods, which take
10+
//! async closures. For locks that should be stored in a structure, `into_read` and `into_write` can be used
11+
//! to convert the lock into an owned guard.
12+
13+
use crate::{fs, prelude::*};
214
use snafu::{ResultExt, Snafu};
315
use std::{fs::File, io, ops::Deref};
416
use tokio::{sync::RwLock, task::spawn_blocking};
517

18+
/// Directory lock ensuring safe concurrency around filesystem operations.
619
pub struct DirectoryStructureLock<T: PathsAccess> {
720
paths_access: T,
821
lock_file: RwLock<File>,
922
lock_path: PathBuf,
1023
}
1124

25+
/// A directory structure, typically with methods to access specific paths within it.
26+
///
27+
/// One file within it is selected as the file for advisory locks.
1228
pub trait PathsAccess: Send + Sync + 'static {
29+
/// Path to the canonical file for locking the directory structure. Usually `$dir/.lock`.
1330
fn lock_file(&self) -> PathBuf;
1431
}
1532

1633
impl<T: PathsAccess> DirectoryStructureLock<T> {
34+
/// Creates a new lock, implicitly calling [`fs::create_dir_all`] on the parent.
1735
pub fn open_or_create(paths_access: T) -> Result<Self, LockError> {
1836
let lock_path = paths_access.lock_file();
19-
crate::fs::create_dir_all(lock_path.parent().unwrap())?;
37+
fs::create_dir_all(lock_path.parent().unwrap())?;
2038
let lock_file =
2139
File::create(&lock_path).context(OpenLockFileFailedSnafu { path: &lock_path })?;
2240
Ok(Self {
@@ -26,7 +44,8 @@ impl<T: PathsAccess> DirectoryStructureLock<T> {
2644
})
2745
}
2846

29-
pub async fn read(self) -> Result<DirectoryStructureGuardOwned<T>, LockError> {
47+
/// Converts the lock structure into an owned read-lock.
48+
pub async fn into_read(self) -> Result<DirectoryStructureGuardOwned<T>, LockError> {
3049
spawn_blocking(move || {
3150
let lock_file = self.lock_file.into_inner();
3251
lock_file.lock_shared().context(LockFailedSnafu {
@@ -41,7 +60,8 @@ impl<T: PathsAccess> DirectoryStructureLock<T> {
4160
.unwrap()
4261
}
4362

44-
pub async fn write(self) -> Result<DirectoryStructureGuardOwned<T>, LockError> {
63+
/// Converts the lock structure into an owned write-lock.
64+
pub async fn into_write(self) -> Result<DirectoryStructureGuardOwned<T>, LockError> {
4565
spawn_blocking(move || {
4666
let lock_file = self.lock_file.into_inner();
4767
lock_file.lock().context(LockFailedSnafu {
@@ -55,6 +75,8 @@ impl<T: PathsAccess> DirectoryStructureLock<T> {
5575
.await
5676
.unwrap()
5777
}
78+
79+
/// Accesses the directory structure under a read lock.
5880
pub async fn with_read<R>(&self, f: impl AsyncFnOnce(&T) -> R) -> Result<R, LockError> {
5981
let guard = self.lock_file.read().await;
6082
let lock_file = guard.try_clone().context(HandleCloneFailedSnafu {
@@ -73,6 +95,7 @@ impl<T: PathsAccess> DirectoryStructureLock<T> {
7395
Ok(ret)
7496
}
7597

98+
/// Accesses the directory structure under a write lock.
7699
pub async fn with_write<R>(&self, f: impl AsyncFnOnce(&T) -> R) -> Result<R, LockError> {
77100
let guard = self.lock_file.write().await;
78101
let lock_file = guard.try_clone().context(HandleCloneFailedSnafu {
@@ -107,6 +130,7 @@ pub enum LockError {
107130
HandleCloneFailed { source: io::Error, path: PathBuf },
108131
}
109132

133+
/// File lock guard. Do not use as a temporary in an expression - if you are making a temporary lock, use `with_*`.
110134
pub struct DirectoryStructureGuardOwned<T> {
111135
paths_access: T,
112136
guard: File,

0 commit comments

Comments
 (0)