Skip to main content

do_memory_storage_redb/persistence/
config.rs

1//! Configuration for cache persistence
2
3use std::path::PathBuf;
4use std::time::Duration;
5
6/// Persistence mode
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum PersistenceMode {
9    /// Full snapshots only
10    Full,
11    /// Incremental updates only
12    Incremental,
13    /// Hybrid: full snapshots with incremental updates
14    #[default]
15    Hybrid,
16    /// Disabled
17    Disabled,
18}
19
20/// Persistence strategy
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22pub enum PersistenceStrategy {
23    /// Persist on every change (high durability, lower performance)
24    Immediate,
25    /// Persist at regular intervals
26    #[default]
27    Interval,
28    /// Persist on shutdown only
29    OnShutdown,
30    /// Persist when cache reaches threshold
31    Threshold,
32}
33
34/// Configuration for cache persistence
35#[derive(Debug, Clone)]
36pub struct PersistenceConfig {
37    /// Whether persistence is enabled
38    pub enabled: bool,
39    /// Path to persistence file
40    pub persistence_path: PathBuf,
41    /// Persistence mode
42    pub mode: PersistenceMode,
43    /// Persistence strategy
44    pub strategy: PersistenceStrategy,
45    /// Save interval (for Interval strategy)
46    pub save_interval: Duration,
47    /// Minimum number of entries to trigger save
48    pub min_entries_threshold: usize,
49    /// Maximum number of entries to keep in snapshot
50    pub max_entries: usize,
51    /// Enable compression for persisted data
52    pub compression_enabled: bool,
53    /// Compression level (0-9, higher = more compression)
54    pub compression_level: u32,
55    /// Enable encryption for persisted data
56    pub encryption_enabled: bool,
57    /// Maximum age of snapshot before forcing full save (seconds)
58    pub max_snapshot_age_secs: u64,
59    /// Number of backup snapshots to keep
60    pub backup_count: usize,
61}
62
63impl Default for PersistenceConfig {
64    fn default() -> Self {
65        Self {
66            enabled: true,
67            persistence_path: PathBuf::from("./cache.redb.snapshot"),
68            mode: PersistenceMode::default(),
69            strategy: PersistenceStrategy::default(),
70            save_interval: Duration::from_secs(300), // 5 minutes
71            min_entries_threshold: 100,
72            max_entries: 100_000,
73            compression_enabled: true,
74            compression_level: 6,
75            encryption_enabled: false,
76            max_snapshot_age_secs: 3600, // 1 hour
77            backup_count: 3,
78        }
79    }
80}
81
82impl PersistenceConfig {
83    /// Create a new configuration with custom path
84    pub fn with_path(path: impl Into<PathBuf>) -> Self {
85        Self {
86            persistence_path: path.into(),
87            ..Default::default()
88        }
89    }
90
91    /// Disable persistence
92    pub fn disabled() -> Self {
93        Self {
94            enabled: false,
95            ..Default::default()
96        }
97    }
98
99    /// Enable immediate persistence strategy
100    pub fn with_immediate_strategy(mut self) -> Self {
101        self.strategy = PersistenceStrategy::Immediate;
102        self
103    }
104
105    /// Enable interval-based persistence
106    pub fn with_interval(mut self, interval: Duration) -> Self {
107        self.strategy = PersistenceStrategy::Interval;
108        self.save_interval = interval;
109        self
110    }
111
112    /// Enable shutdown-only persistence
113    pub fn with_shutdown_strategy(mut self) -> Self {
114        self.strategy = PersistenceStrategy::OnShutdown;
115        self
116    }
117
118    /// Set minimum entries threshold
119    pub fn with_min_entries(mut self, threshold: usize) -> Self {
120        self.min_entries_threshold = threshold;
121        self
122    }
123
124    /// Set maximum entries
125    pub fn with_max_entries(mut self, max: usize) -> Self {
126        self.max_entries = max;
127        self
128    }
129
130    /// Enable/disable compression
131    pub fn with_compression(mut self, enabled: bool) -> Self {
132        self.compression_enabled = enabled;
133        self
134    }
135
136    /// Set compression level
137    pub fn with_compression_level(mut self, level: u32) -> Self {
138        self.compression_level = level.clamp(0, 9);
139        self
140    }
141
142    /// Set number of backups to keep
143    pub fn with_backup_count(mut self, count: usize) -> Self {
144        self.backup_count = count;
145        self
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    #[test]
154    fn test_default_config() {
155        let config = PersistenceConfig::default();
156        assert!(config.enabled);
157        assert_eq!(config.mode, PersistenceMode::Hybrid);
158        assert_eq!(config.strategy, PersistenceStrategy::Interval);
159        assert_eq!(config.save_interval, Duration::from_secs(300));
160        assert_eq!(config.min_entries_threshold, 100);
161        assert!(config.compression_enabled);
162        assert_eq!(config.compression_level, 6);
163        assert!(!config.encryption_enabled);
164    }
165
166    #[test]
167    fn test_disabled_config() {
168        let config = PersistenceConfig::disabled();
169        assert!(!config.enabled);
170    }
171
172    #[test]
173    fn test_builder_methods() {
174        let config = PersistenceConfig::default()
175            .with_immediate_strategy()
176            .with_min_entries(50)
177            .with_max_entries(1000)
178            .with_compression(false)
179            .with_compression_level(9)
180            .with_backup_count(5);
181
182        assert_eq!(config.strategy, PersistenceStrategy::Immediate);
183        assert_eq!(config.min_entries_threshold, 50);
184        assert_eq!(config.max_entries, 1000);
185        assert!(!config.compression_enabled);
186        assert_eq!(config.compression_level, 9);
187        assert_eq!(config.backup_count, 5);
188    }
189
190    #[test]
191    fn test_interval_config() {
192        let config = PersistenceConfig::default().with_interval(Duration::from_secs(60));
193
194        assert_eq!(config.strategy, PersistenceStrategy::Interval);
195        assert_eq!(config.save_interval, Duration::from_secs(60));
196    }
197
198    #[test]
199    fn test_shutdown_strategy() {
200        let config = PersistenceConfig::default().with_shutdown_strategy();
201
202        assert_eq!(config.strategy, PersistenceStrategy::OnShutdown);
203    }
204
205    #[test]
206    fn test_compression_level_clamping() {
207        let config = PersistenceConfig::default().with_compression_level(15);
208
209        assert_eq!(config.compression_level, 9);
210
211        let config = PersistenceConfig::default().with_compression_level(5);
212
213        assert_eq!(config.compression_level, 5);
214    }
215}