driven/state/
atomic_sync.rs1use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum SyncState {
11 Idle,
13 Syncing,
15 Completed,
17 Failed,
19}
20
21#[derive(Debug)]
23pub struct AtomicSync {
24 state: AtomicU64,
26 in_progress: AtomicBool,
28 last_sync: AtomicU64,
30 sync_count: AtomicU64,
32 error_count: AtomicU64,
34}
35
36impl AtomicSync {
37 pub fn new() -> Self {
39 Self {
40 state: AtomicU64::new(SyncState::Idle as u64),
41 in_progress: AtomicBool::new(false),
42 last_sync: AtomicU64::new(0),
43 sync_count: AtomicU64::new(0),
44 error_count: AtomicU64::new(0),
45 }
46 }
47
48 pub fn state(&self) -> SyncState {
50 match self.state.load(Ordering::SeqCst) {
51 0 => SyncState::Idle,
52 1 => SyncState::Syncing,
53 2 => SyncState::Completed,
54 _ => SyncState::Failed,
55 }
56 }
57
58 pub fn try_start(&self) -> bool {
60 if self
61 .in_progress
62 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
63 .is_ok()
64 {
65 {
66 self.state
67 .store(SyncState::Syncing as u64, Ordering::SeqCst);
68 true
69 }
70 } else {
71 false
72 }
73 }
74
75 pub fn complete(&self) {
77 self.state
78 .store(SyncState::Completed as u64, Ordering::SeqCst);
79 self.in_progress.store(false, Ordering::SeqCst);
80 self.last_sync.store(
81 std::time::SystemTime::now()
82 .duration_since(std::time::UNIX_EPOCH)
83 .unwrap_or_default()
84 .as_secs(),
85 Ordering::SeqCst,
86 );
87 self.sync_count.fetch_add(1, Ordering::SeqCst);
88 }
89
90 pub fn fail(&self) {
92 self.state.store(SyncState::Failed as u64, Ordering::SeqCst);
93 self.in_progress.store(false, Ordering::SeqCst);
94 self.error_count.fetch_add(1, Ordering::SeqCst);
95 }
96
97 pub fn reset(&self) {
99 self.state.store(SyncState::Idle as u64, Ordering::SeqCst);
100 self.in_progress.store(false, Ordering::SeqCst);
101 }
102
103 pub fn is_syncing(&self) -> bool {
105 self.in_progress.load(Ordering::SeqCst)
106 }
107
108 pub fn last_sync_time(&self) -> u64 {
110 self.last_sync.load(Ordering::SeqCst)
111 }
112
113 pub fn sync_count(&self) -> u64 {
115 self.sync_count.load(Ordering::SeqCst)
116 }
117
118 pub fn error_count(&self) -> u64 {
120 self.error_count.load(Ordering::SeqCst)
121 }
122
123 pub fn time_since_sync(&self) -> Option<u64> {
125 let last = self.last_sync.load(Ordering::SeqCst);
126 if last == 0 {
127 return None;
128 }
129
130 let now = std::time::SystemTime::now()
131 .duration_since(std::time::UNIX_EPOCH)
132 .unwrap_or_default()
133 .as_secs();
134
135 Some(now.saturating_sub(last))
136 }
137}
138
139impl Default for AtomicSync {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145pub struct SyncGuard<'a> {
147 sync: &'a AtomicSync,
148 completed: bool,
149}
150
151impl<'a> SyncGuard<'a> {
152 pub fn new(sync: &'a AtomicSync) -> Option<Self> {
154 if sync.try_start() {
155 Some(Self {
156 sync,
157 completed: false,
158 })
159 } else {
160 None
161 }
162 }
163
164 pub fn complete(mut self) {
166 self.completed = true;
167 self.sync.complete();
168 }
169
170 pub fn fail(mut self) {
172 self.completed = true;
173 self.sync.fail();
174 }
175}
176
177impl<'a> Drop for SyncGuard<'a> {
178 fn drop(&mut self) {
179 if !self.completed {
180 self.sync.fail();
181 }
182 }
183}
184
185pub type AtomicSyncHandle = Arc<AtomicSync>;
187
188pub fn create_sync_handle() -> AtomicSyncHandle {
190 Arc::new(AtomicSync::new())
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn test_sync_lifecycle() {
199 let sync = AtomicSync::new();
200
201 assert_eq!(sync.state(), SyncState::Idle);
202 assert!(!sync.is_syncing());
203
204 assert!(sync.try_start());
205 assert_eq!(sync.state(), SyncState::Syncing);
206 assert!(sync.is_syncing());
207
208 assert!(!sync.try_start());
210
211 sync.complete();
212 assert_eq!(sync.state(), SyncState::Completed);
213 assert!(!sync.is_syncing());
214 assert_eq!(sync.sync_count(), 1);
215 }
216
217 #[test]
218 fn test_sync_guard() {
219 let sync = AtomicSync::new();
220
221 {
222 let guard = SyncGuard::new(&sync).unwrap();
223 assert!(sync.is_syncing());
224 guard.complete();
225 }
226
227 assert_eq!(sync.state(), SyncState::Completed);
228 }
229
230 #[test]
231 fn test_sync_guard_auto_fail() {
232 let sync = AtomicSync::new();
233
234 {
235 let _guard = SyncGuard::new(&sync).unwrap();
236 assert!(sync.is_syncing());
237 }
239
240 assert_eq!(sync.state(), SyncState::Failed);
241 assert_eq!(sync.error_count(), 1);
242 }
243
244 #[test]
245 fn test_thread_safety() {
246 let sync = Arc::new(AtomicSync::new());
247
248 let handles: Vec<_> = (0..10)
249 .map(|_| {
250 let sync = sync.clone();
251 std::thread::spawn(move || {
252 if sync.try_start() {
253 std::thread::sleep(std::time::Duration::from_millis(1));
254 sync.complete();
255 true
256 } else {
257 false
258 }
259 })
260 })
261 .collect();
262
263 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
264 let successes: usize = results.into_iter().filter(|&b| b).count();
265
266 assert!(successes >= 1);
268 }
269}