distributed_lock_file/
handle.rs1use std::path::PathBuf;
4use std::sync::Arc;
5use tokio::sync::watch;
6use tracing::instrument;
7
8use distributed_lock_core::error::{LockError, LockResult};
9use distributed_lock_core::traits::LockHandle;
10
11use fd_lock::{RwLock, RwLockWriteGuard};
12
13pub struct FileLockHandle {
17 inner: std::mem::ManuallyDrop<LockGuard>,
21 path: PathBuf,
23 #[allow(dead_code)]
25 lost_sender: Arc<watch::Sender<bool>>,
26 lost_receiver: watch::Receiver<bool>,
27}
28
29struct LockGuard {
32 _lock_file: Arc<RwLock<std::fs::File>>,
33 _guard: std::mem::ManuallyDrop<RwLockWriteGuard<'static, std::fs::File>>,
34}
35
36unsafe impl Send for LockGuard {}
37unsafe impl Sync for LockGuard {}
38
39impl LockGuard {
40 fn new(lock_file: RwLock<std::fs::File>) -> LockResult<Self> {
41 let lock_file_arc = Arc::new(lock_file);
43
44 let guard = unsafe {
49 let rwlock_ptr = Arc::as_ptr(&lock_file_arc) as *mut RwLock<std::fs::File>;
51 (*rwlock_ptr).try_write()
53 }
54 .map_err(|_| {
55 LockError::Backend(Box::new(std::io::Error::new(
56 std::io::ErrorKind::WouldBlock,
57 "lock already held",
58 )))
59 })?;
60
61 let guard_box = Box::new(guard);
67 let guard_ptr = Box::into_raw(guard_box);
68 let guard = unsafe { *Box::from_raw(guard_ptr) };
69 let guard = std::mem::ManuallyDrop::new(guard);
70
71 Ok(Self {
72 _lock_file: lock_file_arc,
73 _guard: guard,
74 })
75 }
76}
77
78impl Drop for LockGuard {
79 fn drop(&mut self) {
80 unsafe {
82 std::mem::ManuallyDrop::drop(&mut self._guard);
83 }
84 }
85}
86
87impl FileLockHandle {
88 pub(crate) fn try_new(lock_file: RwLock<std::fs::File>, path: PathBuf) -> LockResult<Self> {
90 let inner = LockGuard::new(lock_file)?;
91 let (sender, receiver) = watch::channel(false);
92 Ok(Self {
93 inner: std::mem::ManuallyDrop::new(inner),
94 path,
95 lost_sender: Arc::new(sender),
96 lost_receiver: receiver,
97 })
98 }
99}
100
101impl LockHandle for FileLockHandle {
102 fn lost_token(&self) -> &watch::Receiver<bool> {
103 &self.lost_receiver
104 }
105
106 #[instrument(skip(self), fields(lock.path = %self.path.display(), backend = "file"))]
107 async fn release(self) -> LockResult<()> {
108 let path = self.path.clone();
111 unsafe {
112 std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(self).inner);
113 }
114
115 let _ = std::fs::remove_file(&path);
117
118 Ok(())
119 }
120}
121
122impl Drop for FileLockHandle {
123 fn drop(&mut self) {
124 unsafe {
126 std::mem::ManuallyDrop::drop(&mut self.inner);
127 }
128
129 let _ = std::fs::remove_file(&self.path);
131 }
132}