use arc_swap::ArcSwap;
use dashmap::DashMap;
use simple_fs::SPath;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
#[derive(Debug)]
pub struct FileWriteManager {
locks: ArcSwap<DashMap<String, Arc<Mutex<()>>>>,
used_in_generation: AtomicBool,
}
impl FileWriteManager {
pub fn new() -> Self {
Self {
locks: ArcSwap::from_pointee(DashMap::new()),
used_in_generation: AtomicBool::new(false),
}
}
pub fn lock_for_path(&self, path: &SPath) -> FilePathLockHandle {
self.used_in_generation.store(true, Ordering::Relaxed);
let lock_key = Self::resolve_lock_key(path);
let locks = self.locks.load();
let lock_arc = locks.entry(lock_key).or_insert_with(|| Arc::new(Mutex::new(()))).clone();
FilePathLockHandle { mutex: lock_arc }
}
pub fn swap_if_used(&self) -> bool {
if !self.used_in_generation.load(Ordering::Relaxed) {
return false;
}
self.locks.store(Arc::new(DashMap::new()));
self.used_in_generation.store(false, Ordering::Relaxed);
true
}
fn resolve_lock_key(path: &SPath) -> String {
path.to_string()
}
}
#[derive(Debug)]
pub struct FilePathLockHandle {
mutex: Arc<Mutex<()>>,
}
impl FilePathLockHandle {
pub fn lock(&self) -> MutexGuard<'_, ()> {
self.mutex.lock().unwrap_or_else(|e| e.into_inner())
}
}