Skip to main content

terminus_store/storage/
memory.rs

1//! In-memory implementation of storage traits.
2
3use std::collections::HashMap;
4use std::io;
5
6use async_trait::async_trait;
7
8use super::file::*;
9use super::label::*;
10use super::layer::*;
11
12pub use tdb_succinct::storage::memory::*;
13
14#[derive(Clone, Default)]
15pub struct MemoryLayerStore {
16    layers: futures_locks::RwLock<HashMap<[u32; 5], HashMap<String, MemoryBackedStore>>>,
17}
18
19impl MemoryLayerStore {
20    pub fn new() -> Self {
21        Self::default()
22    }
23}
24
25#[async_trait]
26impl PersistentLayerStore for MemoryLayerStore {
27    type File = MemoryBackedStore;
28
29    async fn directories(&self) -> io::Result<Vec<[u32; 5]>> {
30        let guard = self.layers.read().await;
31        Ok(guard.keys().cloned().collect())
32    }
33
34    async fn create_named_directory(&self, name: [u32; 5]) -> io::Result<[u32; 5]> {
35        let mut guard = self.layers.write().await;
36        guard.insert(name, HashMap::new());
37
38        Ok(name)
39    }
40
41    async fn directory_exists(&self, name: [u32; 5]) -> io::Result<bool> {
42        let guard = self.layers.read().await;
43        Ok(guard.contains_key(&name))
44    }
45
46    async fn file_exists(&self, directory: [u32; 5], file: &str) -> io::Result<bool> {
47        let guard = self.layers.read().await;
48        if let Some(files) = guard.get(&directory) {
49            if let Some(file) = files.get(file) {
50                file.exists().await
51            } else {
52                Ok(false)
53            }
54        } else {
55            Ok(false)
56        }
57    }
58
59    async fn get_file(&self, directory: [u32; 5], name: &str) -> io::Result<Self::File> {
60        let guard = self.layers.read().await;
61        if let Some(files) = guard.get(&directory) {
62            if let Some(file) = files.get(name) {
63                Ok(file.clone())
64            } else {
65                std::mem::drop(guard); // release read lock cause it is time to write
66                let mut guard = self.layers.write().await;
67                let files = guard.get_mut(&directory).unwrap();
68                let file = MemoryBackedStore::new();
69                let result = file.clone();
70                files.insert(name.to_string(), file);
71                Ok(result)
72            }
73        } else {
74            Err(io::Error::new(io::ErrorKind::NotFound, "layer not found"))
75        }
76    }
77}
78
79#[derive(Clone, Default)]
80pub struct MemoryLabelStore {
81    labels: futures_locks::RwLock<HashMap<String, Label>>,
82}
83
84impl MemoryLabelStore {
85    pub fn new() -> MemoryLabelStore {
86        Default::default()
87    }
88}
89
90#[async_trait]
91impl LabelStore for MemoryLabelStore {
92    async fn labels(&self) -> io::Result<Vec<Label>> {
93        let labels = self.labels.read().await;
94        Ok(labels.values().cloned().collect())
95    }
96
97    async fn create_label(&self, name: &str) -> io::Result<Label> {
98        let label = Label::new_empty(name);
99
100        let mut labels = self.labels.write().await;
101        if labels.get(&label.name).is_some() {
102            Err(std::io::Error::new(
103                std::io::ErrorKind::InvalidInput,
104                "label already exists",
105            ))
106        } else {
107            labels.insert(label.name.clone(), label.clone());
108            Ok(label)
109        }
110    }
111
112    async fn get_label(&self, name: &str) -> io::Result<Option<Label>> {
113        let name = name.to_owned();
114        let labels = self.labels.read().await;
115        Ok(labels.get(&name).cloned())
116    }
117
118    async fn set_label_option(
119        &self,
120        label: &Label,
121        layer: Option<[u32; 5]>,
122    ) -> io::Result<Option<Label>> {
123        let new_label = label.with_updated_layer(layer);
124
125        let mut labels = self.labels.write().await;
126
127        match labels.get(&new_label.name) {
128            None => Err(std::io::Error::new(
129                std::io::ErrorKind::InvalidInput,
130                "label does not exist",
131            )),
132            Some(old_label) => {
133                if old_label.version + 1 != new_label.version {
134                    Ok(None)
135                } else {
136                    labels.insert(new_label.name.clone(), new_label.clone());
137
138                    Ok(Some(new_label))
139                }
140            }
141        }
142    }
143
144    async fn delete_label(&self, name: &str) -> io::Result<bool> {
145        let mut labels = self.labels.write().await;
146
147        Ok(labels.remove(name).is_some())
148    }
149}
150
151#[cfg(test)]
152pub fn base_layer_memory_files() -> BaseLayerFiles<MemoryBackedStore> {
153    BaseLayerFiles {
154        node_dictionary_files: DictionaryFiles {
155            blocks_file: MemoryBackedStore::new(),
156            offsets_file: MemoryBackedStore::new(),
157        },
158        predicate_dictionary_files: DictionaryFiles {
159            blocks_file: MemoryBackedStore::new(),
160            offsets_file: MemoryBackedStore::new(),
161        },
162        value_dictionary_files: TypedDictionaryFiles {
163            types_present_file: MemoryBackedStore::new(),
164            type_offsets_file: MemoryBackedStore::new(),
165            blocks_file: MemoryBackedStore::new(),
166            offsets_file: MemoryBackedStore::new(),
167        },
168
169        id_map_files: IdMapFiles {
170            node_value_idmap_files: BitIndexFiles {
171                bits_file: MemoryBackedStore::new(),
172                blocks_file: MemoryBackedStore::new(),
173                sblocks_file: MemoryBackedStore::new(),
174            },
175            predicate_idmap_files: BitIndexFiles {
176                bits_file: MemoryBackedStore::new(),
177                blocks_file: MemoryBackedStore::new(),
178                sblocks_file: MemoryBackedStore::new(),
179            },
180        },
181
182        subjects_file: MemoryBackedStore::new(),
183        objects_file: MemoryBackedStore::new(),
184
185        s_p_adjacency_list_files: AdjacencyListFiles {
186            bitindex_files: BitIndexFiles {
187                bits_file: MemoryBackedStore::new(),
188                blocks_file: MemoryBackedStore::new(),
189                sblocks_file: MemoryBackedStore::new(),
190            },
191            nums_file: MemoryBackedStore::new(),
192        },
193        sp_o_adjacency_list_files: AdjacencyListFiles {
194            bitindex_files: BitIndexFiles {
195                bits_file: MemoryBackedStore::new(),
196                blocks_file: MemoryBackedStore::new(),
197                sblocks_file: MemoryBackedStore::new(),
198            },
199            nums_file: MemoryBackedStore::new(),
200        },
201        o_ps_adjacency_list_files: AdjacencyListFiles {
202            bitindex_files: BitIndexFiles {
203                bits_file: MemoryBackedStore::new(),
204                blocks_file: MemoryBackedStore::new(),
205                sblocks_file: MemoryBackedStore::new(),
206            },
207            nums_file: MemoryBackedStore::new(),
208        },
209        predicate_wavelet_tree_files: BitIndexFiles {
210            bits_file: MemoryBackedStore::new(),
211            blocks_file: MemoryBackedStore::new(),
212            sblocks_file: MemoryBackedStore::new(),
213        },
214    }
215}
216
217#[cfg(test)]
218pub fn child_layer_memory_files() -> ChildLayerFiles<MemoryBackedStore> {
219    ChildLayerFiles {
220        node_dictionary_files: DictionaryFiles {
221            blocks_file: MemoryBackedStore::new(),
222            offsets_file: MemoryBackedStore::new(),
223        },
224        predicate_dictionary_files: DictionaryFiles {
225            blocks_file: MemoryBackedStore::new(),
226            offsets_file: MemoryBackedStore::new(),
227        },
228        value_dictionary_files: TypedDictionaryFiles {
229            types_present_file: MemoryBackedStore::new(),
230            type_offsets_file: MemoryBackedStore::new(),
231            blocks_file: MemoryBackedStore::new(),
232            offsets_file: MemoryBackedStore::new(),
233        },
234
235        id_map_files: IdMapFiles {
236            node_value_idmap_files: BitIndexFiles {
237                bits_file: MemoryBackedStore::new(),
238                blocks_file: MemoryBackedStore::new(),
239                sblocks_file: MemoryBackedStore::new(),
240            },
241            predicate_idmap_files: BitIndexFiles {
242                bits_file: MemoryBackedStore::new(),
243                blocks_file: MemoryBackedStore::new(),
244                sblocks_file: MemoryBackedStore::new(),
245            },
246        },
247
248        pos_subjects_file: MemoryBackedStore::new(),
249        pos_objects_file: MemoryBackedStore::new(),
250        neg_subjects_file: MemoryBackedStore::new(),
251        neg_objects_file: MemoryBackedStore::new(),
252
253        pos_s_p_adjacency_list_files: AdjacencyListFiles {
254            bitindex_files: BitIndexFiles {
255                bits_file: MemoryBackedStore::new(),
256                blocks_file: MemoryBackedStore::new(),
257                sblocks_file: MemoryBackedStore::new(),
258            },
259            nums_file: MemoryBackedStore::new(),
260        },
261        pos_sp_o_adjacency_list_files: AdjacencyListFiles {
262            bitindex_files: BitIndexFiles {
263                bits_file: MemoryBackedStore::new(),
264                blocks_file: MemoryBackedStore::new(),
265                sblocks_file: MemoryBackedStore::new(),
266            },
267            nums_file: MemoryBackedStore::new(),
268        },
269        pos_o_ps_adjacency_list_files: AdjacencyListFiles {
270            bitindex_files: BitIndexFiles {
271                bits_file: MemoryBackedStore::new(),
272                blocks_file: MemoryBackedStore::new(),
273                sblocks_file: MemoryBackedStore::new(),
274            },
275            nums_file: MemoryBackedStore::new(),
276        },
277        neg_s_p_adjacency_list_files: AdjacencyListFiles {
278            bitindex_files: BitIndexFiles {
279                bits_file: MemoryBackedStore::new(),
280                blocks_file: MemoryBackedStore::new(),
281                sblocks_file: MemoryBackedStore::new(),
282            },
283            nums_file: MemoryBackedStore::new(),
284        },
285        neg_sp_o_adjacency_list_files: AdjacencyListFiles {
286            bitindex_files: BitIndexFiles {
287                bits_file: MemoryBackedStore::new(),
288                blocks_file: MemoryBackedStore::new(),
289                sblocks_file: MemoryBackedStore::new(),
290            },
291            nums_file: MemoryBackedStore::new(),
292        },
293        neg_o_ps_adjacency_list_files: AdjacencyListFiles {
294            bitindex_files: BitIndexFiles {
295                bits_file: MemoryBackedStore::new(),
296                blocks_file: MemoryBackedStore::new(),
297                sblocks_file: MemoryBackedStore::new(),
298            },
299            nums_file: MemoryBackedStore::new(),
300        },
301        pos_predicate_wavelet_tree_files: BitIndexFiles {
302            bits_file: MemoryBackedStore::new(),
303            blocks_file: MemoryBackedStore::new(),
304            sblocks_file: MemoryBackedStore::new(),
305        },
306        neg_predicate_wavelet_tree_files: BitIndexFiles {
307            bits_file: MemoryBackedStore::new(),
308            blocks_file: MemoryBackedStore::new(),
309            sblocks_file: MemoryBackedStore::new(),
310        },
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use super::*;
317    use crate::layer::*;
318    use tokio::io::{AsyncReadExt, AsyncWriteExt};
319
320    #[tokio::test]
321    async fn write_and_read_memory_backed() {
322        let file = MemoryBackedStore::new();
323
324        let mut w = file.open_write().await.unwrap();
325        w.write_all(&[1, 2, 3]).await.unwrap();
326        w.sync_all().await.unwrap();
327        let mut buf = Vec::new();
328        file.open_read()
329            .await
330            .unwrap()
331            .read_to_end(&mut buf)
332            .await
333            .unwrap();
334
335        assert_eq!(vec![1, 2, 3], buf);
336    }
337
338    #[tokio::test]
339    async fn write_and_map_memory_backed() {
340        let file = MemoryBackedStore::new();
341
342        let mut w = file.open_write().await.unwrap();
343        w.write_all(&[1, 2, 3]).await.unwrap();
344        w.sync_all().await.unwrap();
345        let map = file.map().await.unwrap();
346
347        assert_eq!(vec![1, 2, 3], map.as_ref());
348    }
349
350    #[tokio::test]
351    async fn create_layers_from_memory_store() {
352        let store = MemoryLayerStore::new();
353        let mut builder = store.create_base_layer().await.unwrap();
354        let base_name = builder.name();
355
356        builder.add_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
357        builder.add_value_triple(ValueTriple::new_string_value("pig", "says", "oink"));
358        builder.add_value_triple(ValueTriple::new_string_value("duck", "says", "quack"));
359
360        builder.commit_boxed().await.unwrap();
361        builder = store.create_child_layer(base_name).await.unwrap();
362        let child_name = builder.name();
363
364        builder.remove_value_triple(ValueTriple::new_string_value("duck", "says", "quack"));
365        builder.add_value_triple(ValueTriple::new_node("cow", "likes", "pig"));
366
367        builder.commit_boxed().await.unwrap();
368        let layer = store.get_layer(child_name).await.unwrap().unwrap();
369
370        assert!(layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo")));
371        assert!(layer.value_triple_exists(&ValueTriple::new_string_value("pig", "says", "oink")));
372        assert!(layer.value_triple_exists(&ValueTriple::new_node("cow", "likes", "pig")));
373        assert!(!layer.value_triple_exists(&ValueTriple::new_string_value("duck", "says", "quack")));
374    }
375
376    #[tokio::test]
377    async fn memory_create_and_retrieve_equal_label() {
378        let store = MemoryLabelStore::new();
379        let foo = store.create_label("foo").await.unwrap();
380        assert_eq!(foo, store.get_label("foo").await.unwrap().unwrap());
381    }
382
383    #[tokio::test]
384    async fn memory_update_label_succeeds() {
385        let store = MemoryLabelStore::new();
386        let foo = store.create_label("foo").await.unwrap();
387
388        assert_eq!(
389            1,
390            store
391                .set_label(&foo, [6, 7, 8, 9, 10])
392                .await
393                .unwrap()
394                .unwrap()
395                .version
396        );
397
398        assert_eq!(1, store.get_label("foo").await.unwrap().unwrap().version);
399    }
400
401    #[tokio::test]
402    async fn memory_update_label_twice_from_same_label_object_fails() {
403        let store = MemoryLabelStore::new();
404        let foo = store.create_label("foo").await.unwrap();
405
406        assert!(store
407            .set_label(&foo, [6, 7, 8, 9, 10])
408            .await
409            .unwrap()
410            .is_some());
411        assert!(store
412            .set_label(&foo, [1, 1, 1, 1, 1])
413            .await
414            .unwrap()
415            .is_none());
416    }
417
418    #[tokio::test]
419    async fn memory_update_label_twice_from_updated_label_object_succeeds() {
420        let store = MemoryLabelStore::new();
421        let foo = store.create_label("foo").await.unwrap();
422
423        let foo2 = store
424            .set_label(&foo, [6, 7, 8, 9, 10])
425            .await
426            .unwrap()
427            .unwrap();
428        assert!(store
429            .set_label(&foo2, [1, 1, 1, 1, 1])
430            .await
431            .unwrap()
432            .is_some());
433    }
434
435    #[tokio::test]
436    async fn create_and_delete_label() {
437        let store = MemoryLabelStore::new();
438
439        store.create_label("foo").await.unwrap();
440        assert!(store.get_label("foo").await.unwrap().is_some());
441        assert!(store.delete_label("foo").await.unwrap());
442        assert!(store.get_label("foo").await.unwrap().is_none());
443    }
444
445    #[tokio::test]
446    async fn delete_nonexistent_label() {
447        let store = MemoryLabelStore::new();
448
449        assert!(!store.delete_label("foo").await.unwrap());
450    }
451}