dustdata/
dustdata.rs

1use super::storage;
2
3use std::ops::Add;
4use std::path;
5use storage::lsm;
6
7/// A LSM configuration
8/// # Arguments
9/// * `flush_threshold` - The number of bytes to flush before flushing to disk
10/// * `detect_exit_signals` - Whether or not to detect exit signals (SIGTERM, SIGHUP, etc.)
11#[derive(Clone)]
12pub struct LsmConfig {
13    pub flush_threshold: Size,
14}
15
16/// A DustData configuration
17/// # Arguments
18/// * `verbose` - Whether or not to print verbose output
19/// * `path` - The path to the data directory
20/// * `lsm_config` - The LSM configuration
21#[derive(Clone)]
22pub struct DustDataConfig {
23    pub path: path::PathBuf,
24    pub lsm_config: LsmConfig,
25}
26
27pub struct DustData {
28    pub config: DustDataConfig,
29    pub lsm: storage::lsm::Lsm,
30}
31
32#[derive(Clone, PartialEq, Eq, Debug)]
33pub enum Size {
34    Bytes(usize),
35    Kilobytes(usize),
36    Megabytes(usize),
37    Gigabytes(usize),
38}
39
40impl Add for Size {
41    type Output = Size;
42
43    fn add(self, rhs: Self) -> Self::Output {
44        fn calc(a: usize, b: usize) -> Size {
45            let mut bytes = a + b;
46
47            let mut gigabytes = 0;
48            let mut megabytes = 0;
49            let mut kilobytes = 0;
50
51            while bytes >= 1024 * 1024 * 1024 {
52                gigabytes += 1;
53                bytes -= 1024 * 1024 * 1024;
54            }
55
56            while bytes >= 1024 * 1024 {
57                megabytes += 1;
58                bytes -= 1024 * 1024;
59            }
60
61            while bytes >= 1024 {
62                kilobytes += 1;
63                bytes -= 1024;
64            }
65
66            if gigabytes > 0 {
67                Size::Gigabytes(gigabytes)
68            } else if megabytes > 0 {
69                Size::Megabytes(megabytes)
70            } else if kilobytes > 0 {
71                Size::Kilobytes(kilobytes)
72            } else {
73                Size::Bytes(bytes)
74            }
75        }
76
77        match (self, rhs) {
78            (Size::Bytes(a), Size::Bytes(b)) => calc(a, b),
79            (Size::Bytes(a), Size::Kilobytes(b)) => calc(a, b * 1024),
80            (Size::Bytes(a), Size::Megabytes(b)) => calc(a, b * 1024 * 1024),
81            (Size::Bytes(a), Size::Gigabytes(b)) => calc(a, b * 1024 * 1024 * 1024),
82
83            (Size::Kilobytes(a), Size::Bytes(b)) => calc(a * 1024, b * 1024),
84            (Size::Kilobytes(a), Size::Kilobytes(b)) => calc(a * 1024, b * 1024),
85            (Size::Kilobytes(a), Size::Megabytes(b)) => calc(a * 1024, b * 1024 * 1024),
86            (Size::Kilobytes(a), Size::Gigabytes(b)) => calc(a * 1024, b * 1024 * 1024 * 1024),
87
88            (Size::Megabytes(a), Size::Bytes(b)) => calc(a * 1024 * 1024, b),
89            (Size::Megabytes(a), Size::Kilobytes(b)) => calc(a * 1024 * 1024, b * 1024),
90            (Size::Megabytes(a), Size::Megabytes(b)) => calc(a * 1024 * 1024, b * 1024 * 1024),
91            (Size::Megabytes(a), Size::Gigabytes(b)) => {
92                calc(a * 1024 * 1024, b * 1024 * 1024 * 1024)
93            }
94
95            (Size::Gigabytes(a), Size::Bytes(b)) => calc(a * 1024 * 1024 * 1024, b),
96            (Size::Gigabytes(a), Size::Kilobytes(b)) => calc(a * 1024 * 1024 * 1024, b * 1024),
97            (Size::Gigabytes(a), Size::Megabytes(b)) => {
98                calc(a * 1024 * 1024 * 1024, b * 1024 * 1024)
99            }
100            (Size::Gigabytes(a), Size::Gigabytes(b)) => {
101                calc(a * 1024 * 1024 * 1024, b * 1024 * 1024 * 1024)
102            }
103        }
104    }
105}
106
107pub fn size_to_usize(size: Size) -> usize {
108    match size {
109        Size::Bytes(bytes) => bytes,
110        Size::Kilobytes(kilobytes) => kilobytes * 1024,
111        Size::Megabytes(megabytes) => megabytes * 1024 * 1024,
112        Size::Gigabytes(gigabytes) => gigabytes * 1024 * 1024 * 1024,
113    }
114}
115
116pub type Result<T> = std::result::Result<T, Error>;
117
118#[derive(Debug, Clone)]
119pub struct Error {
120    pub code: ErrorCode,
121    pub message: String,
122}
123
124#[derive(Debug, Clone)]
125pub enum ErrorCode {
126    NotFound,
127    KeyExists,
128    KeyNotExists,
129}
130
131impl std::fmt::Display for Error {
132    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
133        write!(f, "Code: {} - Message: {}", self.code, self.message)
134    }
135}
136
137impl std::fmt::Display for ErrorCode {
138    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
139        match self {
140            ErrorCode::NotFound => write!(f, "NotFound"),
141            ErrorCode::KeyExists => write!(f, "KeyExists"),
142            ErrorCode::KeyNotExists => write!(f, "KeyNotExists"),
143        }
144    }
145}
146
147impl DustData {
148    pub fn new(configuration: DustDataConfig) -> Self {
149        let lsm = storage::lsm::Lsm::new(lsm::LsmConfig {
150            flush_threshold: size_to_usize(configuration.clone().lsm_config.flush_threshold),
151            sstable_path: configuration.clone().path,
152        });
153
154        Self {
155            lsm,
156            config: configuration,
157        }
158    }
159
160    /// Get a value with a key
161    /// # Arguments
162    /// - `key`: a key to search for
163    /// # Returns
164    /// - `Result<Option<(bson::Bson)>>` if value was found returns a bson document
165    pub fn get(&self, key: &str) -> Result<Option<bson::Bson>> {
166        self.lsm.get(key)
167    }
168
169    /// Insert a value with a key
170    /// # Arguments
171    /// - `key`: a key.
172    /// - `document`: a bson document to insert
173    pub fn insert(&mut self, key: &str, bson: bson::Bson) -> Result<()> {
174        self.lsm.insert(key, bson)
175    }
176
177    /// Delete a value with a key
178    /// # Arguments
179    /// - `key`: a key to search for and delete it.
180    pub fn delete(&mut self, key: &str) -> Result<()> {
181        self.lsm.delete(key)
182    }
183
184    /// Update a value with a key
185    /// # Arguments
186    /// - `key`: a key to search for and update it.
187    /// - `document`: the new document to replace the old one.
188    pub fn update(&mut self, key: &str, bson: bson::Bson) -> Result<()> {
189        self.lsm.update(key, bson)
190    }
191
192    /// Check if key exists.
193    /// # Arguments
194    /// - `key`: a key to check if exists.
195    pub fn contains(&mut self, key: &str) -> bool {
196        self.lsm.contains(key)
197    }
198
199    /// List all keys.
200    /// # Returns
201    /// - `Result<Vec<String>>` a vector of all keys.
202    pub fn list_keys(&self) -> Result<Vec<String>> {
203        Ok(self.lsm.list_keys())
204    }
205
206    /// Flush all data to disk.
207    /// # Returns
208    /// - `Result<()>` if successful returns nothing.
209    pub fn flush(&mut self) -> Result<()> {
210        self.lsm.flush()
211    }
212}
213
214#[cfg(test)]
215mod size_tests {
216    use super::*;
217
218    #[test]
219    fn add_impl_bytes() {
220        let size = Size::Bytes(1);
221        let size2 = Size::Bytes(2);
222        assert_eq!(size + size2, Size::Bytes(3));
223    }
224
225    #[test]
226    fn add_impl_gb() {
227        let size = Size::Gigabytes(1);
228        let size2 = Size::Gigabytes(2);
229        assert_eq!(size + size2, Size::Gigabytes(3));
230    }
231
232    #[test]
233    fn add_impl_mb() {
234        let size = Size::Megabytes(1);
235        let size2 = Size::Megabytes(2);
236        assert_eq!(size + size2, Size::Megabytes(3));
237    }
238
239    #[test]
240    fn add_impl_kb() {
241        let size = Size::Kilobytes(1);
242        let size2 = Size::Kilobytes(2);
243        assert_eq!(size + size2, Size::Kilobytes(3));
244    }
245}