Coverage Report

Created: 2025-09-19 09:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/gh-runner/action-runner3/_work/feoxdb/feoxdb/src/core/store/builder.rs
Line
Count
Source
1
use std::time::Duration;
2
3
use crate::constants::*;
4
use crate::core::ttl_sweep::TtlConfig;
5
use crate::error::Result;
6
7
use super::FeoxStore;
8
9
/// Configuration options for FeoxStore.
10
///
11
/// Use `StoreBuilder` for a more ergonomic way to configure the store.
12
pub 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
/// ```
41
pub 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
51
impl StoreBuilder {
52
15
    pub fn new() -> Self {
53
15
        Self {
54
15
            hash_bits: DEFAULT_HASH_BITS,
55
15
            device_path: None,
56
15
            file_size: None,
57
15
            max_memory: Some(DEFAULT_MAX_MEMORY),
58
15
            enable_caching: None, // Disable caching for memory-only mode
59
15
            enable_ttl: false,
60
15
            ttl_config: None,
61
15
        }
62
15
    }
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
0
    pub fn device_path(mut self, path: impl Into<String>) -> Self {
69
0
        self.device_path = Some(path.into());
70
0
        self
71
0
    }
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
0
    pub fn file_size(mut self, size: u64) -> Self {
93
0
        self.file_size = Some(size);
94
0
        self
95
0
    }
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
2
    pub fn max_memory(mut self, limit: usize) -> Self {
102
2
        self.max_memory = Some(limit);
103
2
        self
104
2
    }
105
106
    /// Remove memory limit.
107
    ///
108
    /// Use with caution as the store can grow unbounded.
109
0
    pub fn no_memory_limit(mut self) -> Self {
110
0
        self.max_memory = None;
111
0
        self
112
0
    }
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
1
    pub fn hash_bits(mut self, bits: u32) -> Self {
119
1
        self.hash_bits = bits;
120
1
        self
121
1
    }
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
1
    pub fn enable_caching(mut self, enable: bool) -> Self {
128
1
        self.enable_caching = Some(enable);
129
1
        self
130
1
    }
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
12
    pub fn enable_ttl(mut self, enable: bool) -> Self {
138
12
        self.enable_ttl = enable;
139
12
        if enable {
140
10
            let mut config = self.ttl_config.unwrap_or_default();
141
10
            config.enabled = true;
142
10
            self.ttl_config = Some(config);
143
10
        
}2
144
12
        self
145
12
    }
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
0
    pub fn enable_ttl_cleaner(mut self, enable: bool) -> Self {
152
0
        let mut config = self.ttl_config.unwrap_or_default();
153
0
        config.enabled = enable;
154
0
        self.ttl_config = Some(config);
155
0
        self.enable_ttl = enable; // Also enable TTL when cleaner is enabled
156
0
        self
157
0
    }
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
0
    pub fn ttl_sweeper_config(
168
0
        mut self,
169
0
        sample_size: usize,
170
0
        threshold: f32,
171
0
        max_time_ms: u64,
172
0
        interval_ms: u64,
173
0
    ) -> Self {
174
0
        self.ttl_config = Some(TtlConfig {
175
0
            sample_size,
176
0
            expiry_threshold: threshold,
177
0
            max_iterations: 16,
178
0
            max_time_per_run: Duration::from_millis(max_time_ms),
179
0
            sleep_interval: Duration::from_millis(interval_ms),
180
0
            enabled: true,
181
0
        });
182
0
        self
183
0
    }
184
185
    /// Build the FeoxStore
186
15
    pub fn build(self) -> Result<FeoxStore> {
187
15
        let memory_only = self.device_path.is_none();
188
15
        let enable_caching = self.enable_caching.unwrap_or(!memory_only);
189
190
15
        let config = StoreConfig {
191
15
            hash_bits: self.hash_bits,
192
15
            memory_only,
193
15
            enable_caching,
194
15
            device_path: self.device_path,
195
15
            file_size: self.file_size,
196
15
            max_memory: self.max_memory,
197
15
            enable_ttl: self.enable_ttl,
198
15
            ttl_config: self.ttl_config,
199
15
        };
200
201
15
        FeoxStore::with_config(config)
202
15
    }
203
}
204
205
impl Default for StoreBuilder {
206
0
    fn default() -> Self {
207
0
        Self::new()
208
0
    }
209
}