oxihuman_core/
file_lock_stub.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum LockMode {
12 Shared,
13 Exclusive,
14}
15
16#[derive(Debug, Clone)]
18pub struct LockRecord {
19 pub path: String,
20 pub mode: LockMode,
21 pub owner_id: u64,
22}
23
24impl LockRecord {
25 pub fn new(path: &str, mode: LockMode, owner_id: u64) -> Self {
26 LockRecord {
27 path: path.to_string(),
28 mode,
29 owner_id,
30 }
31 }
32}
33
34pub struct FileLockManager {
36 locks: HashMap<String, LockRecord>,
37}
38
39impl FileLockManager {
40 pub fn new() -> Self {
41 FileLockManager {
42 locks: HashMap::new(),
43 }
44 }
45
46 pub fn acquire(&mut self, path: &str, mode: LockMode, owner_id: u64) -> bool {
48 if let Some(existing) = self.locks.get(path) {
49 if existing.mode == LockMode::Exclusive || mode == LockMode::Exclusive {
51 return false;
52 }
53 }
54 self.locks
55 .insert(path.to_string(), LockRecord::new(path, mode, owner_id));
56 true
57 }
58
59 pub fn release(&mut self, path: &str, owner_id: u64) -> bool {
61 if let Some(rec) = self.locks.get(path) {
62 if rec.owner_id == owner_id {
63 self.locks.remove(path);
64 return true;
65 }
66 }
67 false
68 }
69
70 pub fn is_locked(&self, path: &str) -> bool {
71 self.locks.contains_key(path)
72 }
73
74 pub fn lock_count(&self) -> usize {
75 self.locks.len()
76 }
77
78 pub fn get_lock(&self, path: &str) -> Option<&LockRecord> {
79 self.locks.get(path)
80 }
81}
82
83impl Default for FileLockManager {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89pub fn new_lock_manager() -> FileLockManager {
91 FileLockManager::new()
92}
93
94pub fn try_shared(mgr: &mut FileLockManager, path: &str, owner_id: u64) -> bool {
96 mgr.acquire(path, LockMode::Shared, owner_id)
97}
98
99pub fn try_exclusive(mgr: &mut FileLockManager, path: &str, owner_id: u64) -> bool {
101 mgr.acquire(path, LockMode::Exclusive, owner_id)
102}
103
104pub fn release_all(mgr: &mut FileLockManager, owner_id: u64) {
106 let paths: Vec<String> = mgr
107 .locks
108 .values()
109 .filter(|r| r.owner_id == owner_id)
110 .map(|r| r.path.clone())
111 .collect();
112 for p in paths {
113 mgr.release(&p, owner_id);
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_acquire_exclusive() {
123 let mut m = new_lock_manager();
124 assert!(try_exclusive(&mut m, "/f", 1));
125 assert!(m.is_locked("/f"));
126 }
127
128 #[test]
129 fn test_exclusive_blocks_shared() {
130 let mut m = new_lock_manager();
131 try_exclusive(&mut m, "/f", 1);
132 assert!(!try_shared(&mut m, "/f", 2));
133 }
134
135 #[test]
136 fn test_exclusive_blocks_exclusive() {
137 let mut m = new_lock_manager();
138 try_exclusive(&mut m, "/f", 1);
139 assert!(!try_exclusive(&mut m, "/f", 2));
140 }
141
142 #[test]
143 fn test_release_lock() {
144 let mut m = new_lock_manager();
145 try_exclusive(&mut m, "/f", 1);
146 assert!(m.release("/f", 1));
147 assert!(!m.is_locked("/f"));
148 }
149
150 #[test]
151 fn test_release_wrong_owner_fails() {
152 let mut m = new_lock_manager();
153 try_exclusive(&mut m, "/f", 1);
154 assert!(!m.release("/f", 2));
155 assert!(m.is_locked("/f"));
156 }
157
158 #[test]
159 fn test_lock_count() {
160 let mut m = new_lock_manager();
161 try_exclusive(&mut m, "/a", 1);
162 try_exclusive(&mut m, "/b", 2);
163 assert_eq!(m.lock_count(), 2);
164 }
165
166 #[test]
167 fn test_release_all() {
168 let mut m = new_lock_manager();
169 try_shared(&mut m, "/a", 1);
170 try_shared(&mut m, "/b", 1);
171 release_all(&mut m, 1);
172 assert_eq!(m.lock_count(), 0);
173 }
174
175 #[test]
176 fn test_get_lock() {
177 let mut m = new_lock_manager();
178 try_exclusive(&mut m, "/x", 42);
179 let rec = m.get_lock("/x").expect("should succeed");
180 assert_eq!(rec.owner_id, 42);
181 }
182
183 #[test]
184 fn test_shared_two_owners() {
185 let mut m = new_lock_manager();
186 assert!(try_shared(&mut m, "/f", 1));
188 let _ = try_shared(&mut m, "/f", 2);
190 }
191
192 #[test]
193 fn test_not_locked_initially() {
194 let m = new_lock_manager();
195 assert!(!m.is_locked("/no_such_file"));
196 }
197}