cognee_session/
improve_lock.rs1use std::collections::HashSet;
13use std::sync::{Mutex, OnceLock};
14
15static IMPROVING: OnceLock<Mutex<HashSet<String>>> = OnceLock::new();
16
17fn registry() -> &'static Mutex<HashSet<String>> {
18 IMPROVING.get_or_init(|| Mutex::new(HashSet::new()))
19}
20
21pub fn try_acquire_improve_lock(session_id: &str) -> bool {
28 if session_id.is_empty() {
29 return true;
30 }
31 #[allow(clippy::unwrap_used, reason = "lock poison is unrecoverable")]
33 let mut set = registry().lock().unwrap();
34 set.insert(session_id.to_string())
35}
36
37pub fn release_improve_lock(session_id: &str) {
41 if session_id.is_empty() {
42 return;
43 }
44 #[allow(clippy::unwrap_used, reason = "lock poison is unrecoverable")]
46 registry().lock().unwrap().remove(session_id);
47}
48
49pub struct ImproveLockGuard(Option<String>);
58
59impl ImproveLockGuard {
60 pub fn acquire(session_id: &str) -> Option<Self> {
65 if try_acquire_improve_lock(session_id) {
66 Some(Self(Some(session_id.to_string())))
67 } else {
68 None
69 }
70 }
71}
72
73impl Drop for ImproveLockGuard {
74 fn drop(&mut self) {
75 if let Some(ref s) = self.0.take() {
76 release_improve_lock(s);
77 }
78 }
79}
80
81#[cfg(test)]
82#[allow(
83 clippy::unwrap_used,
84 clippy::expect_used,
85 reason = "test code — panics are acceptable failures"
86)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn empty_session_id_always_acquires() {
92 assert!(try_acquire_improve_lock(""));
93 assert!(try_acquire_improve_lock(""));
94 release_improve_lock("");
96 }
97
98 #[test]
99 fn second_acquire_returns_false() {
100 let sid = format!("test-lock-second-{}", uuid::Uuid::new_v4());
101 assert!(try_acquire_improve_lock(&sid), "first acquire must succeed");
102 assert!(
103 !try_acquire_improve_lock(&sid),
104 "second acquire must fail while first is held"
105 );
106 release_improve_lock(&sid);
107 }
108
109 #[test]
110 fn improve_lock_excludes_concurrent() {
111 let sid = format!("test-lock-excl-{}", uuid::Uuid::new_v4());
112
113 assert!(try_acquire_improve_lock(&sid));
115 assert!(!try_acquire_improve_lock(&sid));
117 release_improve_lock(&sid);
119 assert!(try_acquire_improve_lock(&sid));
120 release_improve_lock(&sid);
122 }
123
124 #[test]
125 fn guard_releases_on_drop() {
126 let sid = format!("test-lock-guard-{}", uuid::Uuid::new_v4());
127 {
128 let guard = ImproveLockGuard::acquire(&sid);
129 assert!(guard.is_some(), "guard must be acquired");
130 assert!(!try_acquire_improve_lock(&sid));
132 } assert!(try_acquire_improve_lock(&sid));
135 release_improve_lock(&sid);
136 }
137
138 #[test]
139 fn guard_acquire_fails_when_held() {
140 let sid = format!("test-lock-guard-fail-{}", uuid::Uuid::new_v4());
141 let _g1 = ImproveLockGuard::acquire(&sid).expect("first guard");
142 let g2 = ImproveLockGuard::acquire(&sid);
143 assert!(g2.is_none(), "second guard must not be acquired");
144 }
145
146 #[test]
147 fn empty_session_id_guard_always_acquires() {
148 let g1 = ImproveLockGuard::acquire("");
149 assert!(g1.is_some());
150 let g2 = ImproveLockGuard::acquire("");
152 assert!(g2.is_some());
153 }
154}