feoxdb/core/store/builder.rs
1use std::time::Duration;
2
3use crate::constants::*;
4use crate::core::ttl_sweep::TtlConfig;
5use crate::error::Result;
6
7use super::FeoxStore;
8
9/// Configuration options for FeoxStore.
10///
11/// Use `StoreBuilder` for a more ergonomic way to configure the store.
12pub struct StoreConfig {
13 pub hash_bits: u32,
14 pub memory_only: bool,
15 pub enable_caching: bool,
16 pub device_path: Option<String>,
17 pub file_size: Option<u64>,
18 pub max_memory: Option<usize>,
19 pub enable_ttl: bool,
20 pub ttl_config: Option<TtlConfig>,
21}
22
23/// Builder for creating FeoxStore with custom configuration.
24///
25/// Provides a fluent interface for configuring store parameters.
26///
27/// # Example
28///
29/// ```rust
30/// use feoxdb::FeoxStore;
31///
32/// # fn main() -> feoxdb::Result<()> {
33/// let store = FeoxStore::builder()
34/// .max_memory(1_000_000_000)
35/// .hash_bits(20)
36/// .enable_ttl(true)
37/// .build()?;
38/// # Ok(())
39/// # }
40/// ```
41pub struct StoreBuilder {
42 hash_bits: u32,
43 device_path: Option<String>,
44 file_size: Option<u64>,
45 max_memory: Option<usize>,
46 enable_caching: Option<bool>,
47 enable_ttl: bool,
48 ttl_config: Option<TtlConfig>,
49 allow_ambiguous_legacy_recovery: bool,
50}
51
52impl StoreBuilder {
53 pub fn new() -> Self {
54 Self {
55 hash_bits: DEFAULT_HASH_BITS,
56 device_path: None,
57 file_size: None,
58 max_memory: Some(DEFAULT_MAX_MEMORY),
59 enable_caching: None, // Disable caching for memory-only mode
60 enable_ttl: false,
61 ttl_config: None,
62 allow_ambiguous_legacy_recovery: false,
63 }
64 }
65
66 /// Set the device path for persistent storage.
67 ///
68 /// When set, data will be persisted to disk asynchronously.
69 /// If not set, the store operates in memory-only mode.
70 pub fn device_path(mut self, path: impl Into<String>) -> Self {
71 self.device_path = Some(path.into());
72 self
73 }
74
75 /// Allow recovery past a released v1/v2 deletion marker.
76 ///
77 /// Those formats did not store the deleted extent length, so a continuation
78 /// block can be indistinguishable from a record head. This opt-in preserves
79 /// their historical skip-one behavior for trusted stores or migration.
80 pub fn allow_ambiguous_legacy_recovery(mut self, allow: bool) -> Self {
81 self.allow_ambiguous_legacy_recovery = allow;
82 self
83 }
84
85 /// Set the initial file size for new persistent stores (in bytes).
86 ///
87 /// When creating a new persistent store file, it will be pre-allocated
88 /// to this size for better performance. If not set, defaults to 1GB.
89 /// This option is ignored for existing files.
90 ///
91 /// # Example
92 ///
93 /// ```no_run
94 /// use feoxdb::FeoxStore;
95 ///
96 /// # fn main() -> feoxdb::Result<()> {
97 /// let store = FeoxStore::builder()
98 /// .device_path("/path/to/data.feox")
99 /// .file_size(10 * 1024 * 1024 * 1024) // 10GB
100 /// .build()?;
101 /// # Ok(())
102 /// # }
103 /// ```
104 pub fn file_size(mut self, size: u64) -> Self {
105 self.file_size = Some(size);
106 self
107 }
108
109 /// Set the maximum memory limit (in bytes).
110 ///
111 /// The store will start evicting entries when this limit is approached.
112 /// Default: 1GB
113 pub fn max_memory(mut self, limit: usize) -> Self {
114 self.max_memory = Some(limit);
115 self
116 }
117
118 /// Remove memory limit.
119 ///
120 /// Use with caution as the store can grow unbounded.
121 pub fn no_memory_limit(mut self) -> Self {
122 self.max_memory = None;
123 self
124 }
125
126 /// Set number of hash bits (determines hash table size).
127 ///
128 /// More bits = larger hash table = better performance for large datasets.
129 /// Default: 18 (256K buckets)
130 pub fn hash_bits(mut self, bits: u32) -> Self {
131 self.hash_bits = bits;
132 self
133 }
134
135 /// Enable or disable caching.
136 ///
137 /// When enabled, frequently accessed values are kept in memory
138 /// even after being written to disk. Uses CLOCK eviction algorithm.
139 pub fn enable_caching(mut self, enable: bool) -> Self {
140 self.enable_caching = Some(enable);
141 self
142 }
143
144 /// Enable or disable TTL (Time-To-Live) functionality.
145 ///
146 /// When disabled (default), TTL operations will return errors and no background cleaner runs.
147 /// When enabled, keys can have expiry times and a background cleaner removes expired keys.
148 /// Default: false (disabled for optimal performance)
149 pub fn enable_ttl(mut self, enable: bool) -> Self {
150 self.enable_ttl = enable;
151 if enable {
152 let mut config = self.ttl_config.unwrap_or_default();
153 config.enabled = true;
154 self.ttl_config = Some(config);
155 }
156 self
157 }
158
159 /// Enable or disable TTL sweeper.
160 ///
161 /// When enabled, a background thread periodically removes expired keys.
162 /// Note: This method is deprecated in favor of enable_ttl().
163 pub fn enable_ttl_cleaner(mut self, enable: bool) -> Self {
164 let mut config = self.ttl_config.unwrap_or_default();
165 config.enabled = enable;
166 self.ttl_config = Some(config);
167 self.enable_ttl = enable; // Also enable TTL when cleaner is enabled
168 self
169 }
170
171 /// Configure TTL sweeper with custom parameters.
172 ///
173 /// # Arguments
174 ///
175 /// * `sample_size` - Keys to check per batch
176 /// * `threshold` - Continue if >threshold expired (0.0-1.0)
177 /// * `max_time_ms` - Max milliseconds per cleaning run
178 /// * `interval_ms` - Sleep between runs
179 pub fn ttl_sweeper_config(
180 mut self,
181 sample_size: usize,
182 threshold: f32,
183 max_time_ms: u64,
184 interval_ms: u64,
185 ) -> Self {
186 self.ttl_config = Some(TtlConfig {
187 sample_size,
188 expiry_threshold: threshold,
189 max_iterations: 16,
190 max_time_per_run: Duration::from_millis(max_time_ms),
191 sleep_interval: Duration::from_millis(interval_ms),
192 enabled: true,
193 });
194 self
195 }
196
197 /// Build the FeoxStore
198 pub fn build(self) -> Result<FeoxStore> {
199 let memory_only = self.device_path.is_none();
200 let enable_caching = self.enable_caching.unwrap_or(!memory_only);
201
202 let config = StoreConfig {
203 hash_bits: self.hash_bits,
204 memory_only,
205 enable_caching,
206 device_path: self.device_path,
207 file_size: self.file_size,
208 max_memory: self.max_memory,
209 enable_ttl: self.enable_ttl,
210 ttl_config: self.ttl_config,
211 };
212
213 FeoxStore::with_config_and_legacy_recovery(config, self.allow_ambiguous_legacy_recovery)
214 }
215}
216
217impl Default for StoreBuilder {
218 fn default() -> Self {
219 Self::new()
220 }
221}