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}
50
51impl StoreBuilder {
52    pub fn new() -> Self {
53        Self {
54            hash_bits: DEFAULT_HASH_BITS,
55            device_path: None,
56            file_size: None,
57            max_memory: Some(DEFAULT_MAX_MEMORY),
58            enable_caching: None, // Disable caching for memory-only mode
59            enable_ttl: false,
60            ttl_config: None,
61        }
62    }
63
64    /// Set the device path for persistent storage.
65    ///
66    /// When set, data will be persisted to disk asynchronously.
67    /// If not set, the store operates in memory-only mode.
68    pub fn device_path(mut self, path: impl Into<String>) -> Self {
69        self.device_path = Some(path.into());
70        self
71    }
72
73    /// Set the initial file size for new persistent stores (in bytes).
74    ///
75    /// When creating a new persistent store file, it will be pre-allocated
76    /// to this size for better performance. If not set, defaults to 1GB.
77    /// This option is ignored for existing files.
78    ///
79    /// # Example
80    ///
81    /// ```no_run
82    /// use feoxdb::FeoxStore;
83    ///
84    /// # fn main() -> feoxdb::Result<()> {
85    /// let store = FeoxStore::builder()
86    ///     .device_path("/path/to/data.feox")
87    ///     .file_size(10 * 1024 * 1024 * 1024)  // 10GB
88    ///     .build()?;
89    /// # Ok(())
90    /// # }
91    /// ```
92    pub fn file_size(mut self, size: u64) -> Self {
93        self.file_size = Some(size);
94        self
95    }
96
97    /// Set the maximum memory limit (in bytes).
98    ///
99    /// The store will start evicting entries when this limit is approached.
100    /// Default: 1GB
101    pub fn max_memory(mut self, limit: usize) -> Self {
102        self.max_memory = Some(limit);
103        self
104    }
105
106    /// Remove memory limit.
107    ///
108    /// Use with caution as the store can grow unbounded.
109    pub fn no_memory_limit(mut self) -> Self {
110        self.max_memory = None;
111        self
112    }
113
114    /// Set number of hash bits (determines hash table size).
115    ///
116    /// More bits = larger hash table = better performance for large datasets.
117    /// Default: 18 (256K buckets)
118    pub fn hash_bits(mut self, bits: u32) -> Self {
119        self.hash_bits = bits;
120        self
121    }
122
123    /// Enable or disable caching.
124    ///
125    /// When enabled, frequently accessed values are kept in memory
126    /// even after being written to disk. Uses CLOCK eviction algorithm.
127    pub fn enable_caching(mut self, enable: bool) -> Self {
128        self.enable_caching = Some(enable);
129        self
130    }
131
132    /// Enable or disable TTL (Time-To-Live) functionality.
133    ///
134    /// When disabled (default), TTL operations will return errors and no background cleaner runs.
135    /// When enabled, keys can have expiry times and a background cleaner removes expired keys.
136    /// Default: false (disabled for optimal performance)
137    pub fn enable_ttl(mut self, enable: bool) -> Self {
138        self.enable_ttl = enable;
139        if enable {
140            let mut config = self.ttl_config.unwrap_or_default();
141            config.enabled = true;
142            self.ttl_config = Some(config);
143        }
144        self
145    }
146
147    /// Enable or disable TTL sweeper.
148    ///
149    /// When enabled, a background thread periodically removes expired keys.
150    /// Note: This method is deprecated in favor of enable_ttl().
151    pub fn enable_ttl_cleaner(mut self, enable: bool) -> Self {
152        let mut config = self.ttl_config.unwrap_or_default();
153        config.enabled = enable;
154        self.ttl_config = Some(config);
155        self.enable_ttl = enable; // Also enable TTL when cleaner is enabled
156        self
157    }
158
159    /// Configure TTL sweeper with custom parameters.
160    ///
161    /// # Arguments
162    ///
163    /// * `sample_size` - Keys to check per batch
164    /// * `threshold` - Continue if >threshold expired (0.0-1.0)
165    /// * `max_time_ms` - Max milliseconds per cleaning run
166    /// * `interval_ms` - Sleep between runs
167    pub fn ttl_sweeper_config(
168        mut self,
169        sample_size: usize,
170        threshold: f32,
171        max_time_ms: u64,
172        interval_ms: u64,
173    ) -> Self {
174        self.ttl_config = Some(TtlConfig {
175            sample_size,
176            expiry_threshold: threshold,
177            max_iterations: 16,
178            max_time_per_run: Duration::from_millis(max_time_ms),
179            sleep_interval: Duration::from_millis(interval_ms),
180            enabled: true,
181        });
182        self
183    }
184
185    /// Build the FeoxStore
186    pub fn build(self) -> Result<FeoxStore> {
187        let memory_only = self.device_path.is_none();
188        let enable_caching = self.enable_caching.unwrap_or(!memory_only);
189
190        let config = StoreConfig {
191            hash_bits: self.hash_bits,
192            memory_only,
193            enable_caching,
194            device_path: self.device_path,
195            file_size: self.file_size,
196            max_memory: self.max_memory,
197            enable_ttl: self.enable_ttl,
198            ttl_config: self.ttl_config,
199        };
200
201        FeoxStore::with_config(config)
202    }
203}
204
205impl Default for StoreBuilder {
206    fn default() -> Self {
207        Self::new()
208    }
209}