Skip to main content

reddb/
config.rs

1use std::path::PathBuf;
2
3/// Controls whether the in-memory store or the backing file is updated first
4/// on each write operation.
5///
6/// - `MemoryFirst` (default): update the in-memory map, then append to the WAL.
7///   Faster; a crash between the two leaves the WAL behind, which is recovered
8///   on next open.
9/// - `FileFirst`: append to the WAL first, then update the in-memory map.
10///   Stronger durability guarantee: if the process crashes after the WAL write
11///   the in-memory state is rebuilt correctly on restart.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13pub enum WriteOrder {
14    #[default]
15    MemoryFirst,
16    FileFirst,
17}
18
19#[derive(Debug, Clone)]
20pub struct DbConfig {
21    pub name: String,
22    pub dir: PathBuf,
23    /// Trigger compaction when file_size >= live_data_size * ratio.
24    /// Default: 2.0 — compact when file is 2× larger than live data.
25    pub compaction_ratio: f64,
26    pub write_order: WriteOrder,
27}
28
29impl DbConfig {
30    pub fn new(name: impl Into<String>) -> Self {
31        DbConfig {
32            name: name.into(),
33            dir: PathBuf::from("."),
34            compaction_ratio: 2.0,
35            write_order: WriteOrder::MemoryFirst,
36        }
37    }
38
39    pub fn dir(mut self, dir: impl Into<PathBuf>) -> Self {
40        self.dir = dir.into();
41        self
42    }
43
44    pub fn compaction_ratio(mut self, ratio: f64) -> Self {
45        self.compaction_ratio = ratio;
46        self
47    }
48
49    pub fn write_order(mut self, order: WriteOrder) -> Self {
50        self.write_order = order;
51        self
52    }
53
54    pub fn file_stem(&self) -> PathBuf {
55        self.dir.join(&self.name)
56    }
57}
58
59impl Default for DbConfig {
60    fn default() -> Self {
61        DbConfig::new("reddb")
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn default_dir_is_current() {
71        let cfg = DbConfig::new("mydb");
72        assert_eq!(cfg.dir, PathBuf::from("."));
73    }
74
75    #[test]
76    fn default_compaction_ratio() {
77        let cfg = DbConfig::new("mydb");
78        assert_eq!(cfg.compaction_ratio, 2.0);
79    }
80
81    #[test]
82    fn default_write_order_is_memory_first() {
83        let cfg = DbConfig::new("mydb");
84        assert_eq!(cfg.write_order, WriteOrder::MemoryFirst);
85    }
86
87    #[test]
88    fn builder_overrides_write_order() {
89        let cfg = DbConfig::new("mydb").write_order(WriteOrder::FileFirst);
90        assert_eq!(cfg.write_order, WriteOrder::FileFirst);
91    }
92
93    #[test]
94    fn builder_overrides_dir() {
95        let cfg = DbConfig::new("mydb").dir("/tmp");
96        assert_eq!(cfg.dir, PathBuf::from("/tmp"));
97    }
98
99    #[test]
100    fn builder_overrides_compaction_ratio() {
101        let cfg = DbConfig::new("mydb").compaction_ratio(3.5);
102        assert_eq!(cfg.compaction_ratio, 3.5);
103    }
104
105    #[test]
106    fn file_stem_joins_dir_and_name() {
107        let cfg = DbConfig::new("users").dir("/data");
108        assert_eq!(cfg.file_stem(), PathBuf::from("/data/users"));
109    }
110
111    #[test]
112    fn default_impl_uses_reddb_name() {
113        let cfg = DbConfig::default();
114        assert_eq!(cfg.name, "reddb");
115    }
116}