1use alloc::collections::BTreeMap;
6use alloc::collections::BTreeSet;
7use alloc::string::{String, ToString};
8use alloc::vec::Vec;
9use cynos_core::{Error, Result};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum LockType {
14 Shared,
16 Exclusive,
18}
19
20#[derive(Clone, Debug)]
22pub struct LockRequest {
23 pub tx_id: u64,
25 pub lock_type: LockType,
27}
28
29#[derive(Clone, Debug, Default)]
31struct LockState {
32 shared_holders: BTreeSet<u64>,
34 exclusive_holder: Option<u64>,
36}
37
38impl LockState {
39 fn new() -> Self {
40 Self::default()
41 }
42
43 fn is_free(&self) -> bool {
44 self.shared_holders.is_empty() && self.exclusive_holder.is_none()
45 }
46
47 fn can_grant_shared(&self, tx_id: u64) -> bool {
48 self.exclusive_holder.is_none() || self.exclusive_holder == Some(tx_id)
50 }
51
52 fn can_grant_exclusive(&self, tx_id: u64) -> bool {
53 (self.exclusive_holder.is_none() && self.shared_holders.is_empty())
55 || (self.exclusive_holder.is_none()
56 && self.shared_holders.len() == 1
57 && self.shared_holders.contains(&tx_id))
58 || self.exclusive_holder == Some(tx_id)
59 }
60}
61
62pub struct LockManager {
64 locks: BTreeMap<String, LockState>,
66}
67
68impl LockManager {
69 pub fn new() -> Self {
71 Self {
72 locks: BTreeMap::new(),
73 }
74 }
75
76 pub fn acquire(&mut self, resource: &str, tx_id: u64, lock_type: LockType) -> Result<()> {
78 let state = self.locks.entry(resource.to_string()).or_insert_with(LockState::new);
79
80 match lock_type {
81 LockType::Shared => {
82 if state.can_grant_shared(tx_id) {
83 state.shared_holders.insert(tx_id);
84 Ok(())
85 } else {
86 Err(Error::invalid_operation("Cannot acquire shared lock"))
87 }
88 }
89 LockType::Exclusive => {
90 if state.can_grant_exclusive(tx_id) {
91 state.shared_holders.remove(&tx_id);
93 state.exclusive_holder = Some(tx_id);
94 Ok(())
95 } else {
96 Err(Error::invalid_operation("Cannot acquire exclusive lock"))
97 }
98 }
99 }
100 }
101
102 pub fn release_all(&mut self, tx_id: u64) {
104 for state in self.locks.values_mut() {
105 state.shared_holders.remove(&tx_id);
106 if state.exclusive_holder == Some(tx_id) {
107 state.exclusive_holder = None;
108 }
109 }
110
111 self.locks.retain(|_, state| !state.is_free());
113 }
114
115 pub fn release(&mut self, resource: &str, tx_id: u64) {
117 if let Some(state) = self.locks.get_mut(resource) {
118 state.shared_holders.remove(&tx_id);
119 if state.exclusive_holder == Some(tx_id) {
120 state.exclusive_holder = None;
121 }
122
123 if state.is_free() {
124 self.locks.remove(resource);
125 }
126 }
127 }
128
129 pub fn holds_lock(&self, resource: &str, tx_id: u64) -> bool {
131 if let Some(state) = self.locks.get(resource) {
132 state.shared_holders.contains(&tx_id) || state.exclusive_holder == Some(tx_id)
133 } else {
134 false
135 }
136 }
137
138 pub fn holds_exclusive(&self, resource: &str, tx_id: u64) -> bool {
140 if let Some(state) = self.locks.get(resource) {
141 state.exclusive_holder == Some(tx_id)
142 } else {
143 false
144 }
145 }
146
147 pub fn get_locked_resources(&self, tx_id: u64) -> Vec<&str> {
149 self.locks
150 .iter()
151 .filter(|(_, state)| {
152 state.shared_holders.contains(&tx_id) || state.exclusive_holder == Some(tx_id)
153 })
154 .map(|(name, _)| name.as_str())
155 .collect()
156 }
157}
158
159impl Default for LockManager {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_acquire_shared_lock() {
171 let mut lm = LockManager::new();
172
173 assert!(lm.acquire("table1", 1, LockType::Shared).is_ok());
174 assert!(lm.holds_lock("table1", 1));
175 }
176
177 #[test]
178 fn test_acquire_exclusive_lock() {
179 let mut lm = LockManager::new();
180
181 assert!(lm.acquire("table1", 1, LockType::Exclusive).is_ok());
182 assert!(lm.holds_exclusive("table1", 1));
183 }
184
185 #[test]
186 fn test_multiple_shared_locks() {
187 let mut lm = LockManager::new();
188
189 assert!(lm.acquire("table1", 1, LockType::Shared).is_ok());
190 assert!(lm.acquire("table1", 2, LockType::Shared).is_ok());
191 assert!(lm.holds_lock("table1", 1));
192 assert!(lm.holds_lock("table1", 2));
193 }
194
195 #[test]
196 fn test_exclusive_blocks_shared() {
197 let mut lm = LockManager::new();
198
199 assert!(lm.acquire("table1", 1, LockType::Exclusive).is_ok());
200 assert!(lm.acquire("table1", 2, LockType::Shared).is_err());
201 }
202
203 #[test]
204 fn test_shared_blocks_exclusive() {
205 let mut lm = LockManager::new();
206
207 assert!(lm.acquire("table1", 1, LockType::Shared).is_ok());
208 assert!(lm.acquire("table1", 2, LockType::Exclusive).is_err());
209 }
210
211 #[test]
212 fn test_upgrade_shared_to_exclusive() {
213 let mut lm = LockManager::new();
214
215 assert!(lm.acquire("table1", 1, LockType::Shared).is_ok());
216 assert!(lm.acquire("table1", 1, LockType::Exclusive).is_ok());
217 assert!(lm.holds_exclusive("table1", 1));
218 }
219
220 #[test]
221 fn test_release_lock() {
222 let mut lm = LockManager::new();
223
224 lm.acquire("table1", 1, LockType::Exclusive).unwrap();
225 lm.release("table1", 1);
226
227 assert!(!lm.holds_lock("table1", 1));
228 assert!(lm.acquire("table1", 2, LockType::Exclusive).is_ok());
229 }
230
231 #[test]
232 fn test_release_all() {
233 let mut lm = LockManager::new();
234
235 lm.acquire("table1", 1, LockType::Shared).unwrap();
236 lm.acquire("table2", 1, LockType::Exclusive).unwrap();
237
238 lm.release_all(1);
239
240 assert!(!lm.holds_lock("table1", 1));
241 assert!(!lm.holds_lock("table2", 1));
242 }
243
244 #[test]
245 fn test_get_locked_resources() {
246 let mut lm = LockManager::new();
247
248 lm.acquire("table1", 1, LockType::Shared).unwrap();
249 lm.acquire("table2", 1, LockType::Exclusive).unwrap();
250 lm.acquire("table3", 2, LockType::Shared).unwrap();
251
252 let resources = lm.get_locked_resources(1);
253 assert_eq!(resources.len(), 2);
254 assert!(resources.contains(&"table1"));
255 assert!(resources.contains(&"table2"));
256 }
257}