confium_coordinator/coordinator/
checkpoint.rs1use std::sync::Mutex;
4use std::time::{Duration, Instant};
5
6#[derive(Debug, Clone)]
8pub struct CheckpointConfig {
9 pub interval: Duration,
11 pub max_entries_before_checkpoint: usize,
13}
14
15impl Default for CheckpointConfig {
16 fn default() -> Self {
17 Self {
18 interval: Duration::from_secs(300),
19 max_entries_before_checkpoint: 1000,
20 }
21 }
22}
23
24pub struct CheckpointManager {
26 config: CheckpointConfig,
27 last_checkpoint: Mutex<Instant>,
28 entries_since_checkpoint: Mutex<usize>,
29 total_checkpoints: Mutex<u64>,
30}
31
32impl CheckpointManager {
33 pub fn new(config: CheckpointConfig) -> Self {
34 Self {
35 config,
36 last_checkpoint: Mutex::new(Instant::now()),
37 entries_since_checkpoint: Mutex::new(0),
38 total_checkpoints: Mutex::new(0),
39 }
40 }
41
42 pub fn record_entry(&self) {
44 *self.entries_since_checkpoint.lock().unwrap() += 1;
45 }
46
47 pub fn should_checkpoint(&self) -> bool {
49 let elapsed = self.last_checkpoint.lock().unwrap().elapsed();
50 let entries = *self.entries_since_checkpoint.lock().unwrap();
51 elapsed >= self.config.interval || entries >= self.config.max_entries_before_checkpoint
52 }
53
54 pub fn checkpoint_taken(&self) {
56 *self.last_checkpoint.lock().unwrap() = Instant::now();
57 *self.entries_since_checkpoint.lock().unwrap() = 0;
58 *self.total_checkpoints.lock().unwrap() += 1;
59 }
60
61 pub fn total_checkpoints(&self) -> u64 {
63 *self.total_checkpoints.lock().unwrap()
64 }
65
66 pub fn entries_since_checkpoint(&self) -> usize {
68 *self.entries_since_checkpoint.lock().unwrap()
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn default_interval_5min() {
78 let config = CheckpointConfig::default();
79 assert_eq!(config.interval, Duration::from_secs(300));
80 }
81
82 #[test]
83 fn no_checkpoint_needed_initially() {
84 let mgr = CheckpointManager::new(CheckpointConfig::default());
85 assert!(!mgr.should_checkpoint());
86 }
87
88 #[test]
89 fn checkpoint_after_max_entries() {
90 let config = CheckpointConfig {
91 interval: Duration::from_secs(3600),
92 max_entries_before_checkpoint: 5,
93 };
94 let mgr = CheckpointManager::new(config);
95 for _ in 0..5 {
96 mgr.record_entry();
97 }
98 assert!(mgr.should_checkpoint());
99 }
100
101 #[test]
102 fn checkpoint_resets_counter() {
103 let config = CheckpointConfig {
104 interval: Duration::from_secs(3600),
105 max_entries_before_checkpoint: 3,
106 };
107 let mgr = CheckpointManager::new(config);
108 for _ in 0..3 {
109 mgr.record_entry();
110 }
111 assert!(mgr.should_checkpoint());
112 mgr.checkpoint_taken();
113 assert!(!mgr.should_checkpoint());
114 assert_eq!(mgr.entries_since_checkpoint(), 0);
115 }
116
117 #[test]
118 fn total_checkpoints_increments() {
119 let mgr = CheckpointManager::new(CheckpointConfig::default());
120 assert_eq!(mgr.total_checkpoints(), 0);
121 mgr.checkpoint_taken();
122 mgr.checkpoint_taken();
123 assert_eq!(mgr.total_checkpoints(), 2);
124 }
125
126 #[test]
127 fn entries_accumulate() {
128 let mgr = CheckpointManager::new(CheckpointConfig::default());
129 mgr.record_entry();
130 mgr.record_entry();
131 mgr.record_entry();
132 assert_eq!(mgr.entries_since_checkpoint(), 3);
133 }
134}