Skip to main content

chunked_wal/
file_lock.rs

1use std::fs::File;
2use std::fs::OpenOptions;
3use std::io;
4
5use codeq::error_context_ext::ErrorContextExt;
6use fs2::FileExt;
7use log::info;
8
9use crate::Config;
10
11#[derive(Debug)]
12pub struct WalLock {
13    path: String,
14    f: File,
15}
16
17impl WalLock {
18    pub(crate) const LOCK_FILE_NAME: &'static str = "LOCK";
19
20    pub(crate) fn new(config: &Config) -> Result<Self, io::Error> {
21        let path = Self::lock_path(config);
22
23        let f = OpenOptions::new()
24            .read(true)
25            .write(true)
26            .create(true)
27            .truncate(true)
28            .open(&path)
29            .context(|| format!("create lock file '{}'", path))?;
30
31        f.try_lock_exclusive().map_err(|e| {
32            io::Error::new(
33                io::ErrorKind::WouldBlock,
34                format!(
35                    "Directory '{}' is already locked by another process, \
36                    shutdown other process to continue; \
37                    error:({})",
38                    config.dir, e
39                ),
40            )
41        })?;
42
43        info!("Directory lock acquired: {}", path);
44
45        Ok(Self { path, f })
46    }
47
48    pub(crate) fn lock_path(config: &Config) -> String {
49        format!("{}/{}", config.dir, Self::LOCK_FILE_NAME)
50    }
51}
52
53impl Drop for WalLock {
54    fn drop(&mut self) {
55        let _ = fs2::FileExt::unlock(&self.f);
56        info!("Directory lock released: {}", self.path);
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use crate::Config;
63    use crate::WalLock;
64
65    #[test]
66    fn test_lock_file() {
67        let temp_dir = tempfile::tempdir().unwrap();
68        let config = Config::new(temp_dir.path().to_str().unwrap());
69
70        let lf = WalLock::new(&config).unwrap();
71        println!("Directory locked successfully");
72
73        let lf2 = WalLock::new(&config);
74        assert!(lf2.is_err());
75
76        drop(lf);
77        let _lf2 = WalLock::new(&config).unwrap();
78        println!("Directory locked successfully after dropping first lock");
79    }
80}