stack_db/default/
alloc.rs

1//! Some default `stack-db` allocator implementations
2
3use std::{fs::{self, File}, io::Cursor, path::{Path, PathBuf}};
4use crate::{base::{database::allocator::Allocator, layer::Layer}, errors::Error};
5
6/// # In-Memory Allocator
7/// ---
8/// For a redis-like database for caching, testing the database, etc. Lives only on the heap and gets wiped on program exit.
9pub struct SkdbMemAlloc;
10impl<'a> Allocator<'a> for SkdbMemAlloc {
11    type LayerStream = Cursor<Vec<u8>>;
12    #[inline]
13    fn load_layers(&self) -> Result<Vec<Layer<'a, Self::LayerStream>>, Error> {
14        Ok(Vec::new())
15    }
16    #[inline]
17    fn add_layer(&mut self) -> Result<Layer<'a, Self::LayerStream>, Error> {
18        Ok(Layer::new(Cursor::new(Vec::new())))
19    }
20    #[inline]
21    fn drop_top_layer(&mut self) -> Result<(), Error> {
22        Ok(())
23    }
24    #[inline]
25    fn rebase(&mut self, _: usize) -> Result<(), Error> {
26        Ok(())
27    }
28}
29
30/// # Directory Allocator
31/// ---
32/// Allocates within a directory that lives on the file-system with the layer order determined by the layer file names
33pub struct SkdbDirAlloc {
34    /// the path of the directory database
35    pub path: PathBuf,
36    /// the (sorted) paths of the layers in the database
37    pub layers: Vec<PathBuf>,
38    pub cursor: u32,
39}
40impl SkdbDirAlloc {
41    /// Creates a new SkDB
42    pub fn new(path: impl AsRef<Path>) -> Result<Self, Error> {
43        let path = path.as_ref();
44
45        fs::create_dir_all(path)?;
46        Ok(Self {
47            path: path.to_path_buf(),
48            layers: Vec::new(),
49            cursor: 0,
50        })
51    }
52    
53    /// Loads a Skdb from a directory
54    pub fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
55        // grab file paths
56        let mut file_paths = Vec::new();
57        for entry in fs::read_dir(&path)? {
58            let entry = entry?;
59            if entry.file_type()?.is_file() {
60                file_paths.push(entry.path());
61            }
62        }
63
64        // index files and sort them
65        let mut layers = file_paths.iter()
66            .enumerate()
67            .filter_map(|(i, file)| file.file_name().map(|x| (x.to_string_lossy(), i)))
68            .filter_map(|(name, i)| name.parse::<u32>().ok().map(|x| (x, i)))
69            .collect::<Vec<(u32, usize)>>();
70        layers.sort_unstable_by_key(|x| x.0);
71
72        let cursor = layers.last().map(|x| x.0 + 1).unwrap_or(0);
73        let layers = layers.into_iter()
74            .map(|(_, i)| std::mem::take(&mut file_paths[i]))
75            .collect::<Vec<_>>();
76
77        // return self
78        Ok(Self {
79            path: path.as_ref().to_path_buf(),
80            layers,
81            cursor,
82        })
83    }
84}
85impl<'a> Allocator<'a> for SkdbDirAlloc {
86    type LayerStream = File;
87
88    /// Loads the layer files from the directory
89    fn load_layers(&self) -> Result<Vec<Layer<'a, Self::LayerStream>>, Error> {
90        let mut layers = Vec::with_capacity(self.layers.len());
91        for path in self.layers.iter() {
92            let file = File::options()
93                .read(true)
94                .write(true)
95                .append(false)
96                .truncate(false)
97                .open(path)?;
98            layers.push(Layer::load(file)?);
99        } Ok(layers)
100    }
101
102    fn add_layer(&mut self) -> Result<Layer<'a, Self::LayerStream>, Error> {
103        let path = self.path.join(self.cursor.to_string());
104        let file = File::options()
105            .read(true)
106            .write(true)
107            .append(false)
108            .truncate(false)
109            .create_new(true)
110            .open(&path)?;
111        self.cursor += 1;
112        self.layers.push(path);
113        Ok(Layer::new(file))
114    }
115
116    fn drop_top_layer(&mut self) -> Result<(), Error> {
117        let path = if let Some(x) = self.layers.pop() { x } else { return Ok(()) };
118        self.cursor -= 1;
119        fs::remove_file(path)?;
120
121        Ok(())
122    }
123
124    fn rebase(&mut self, top_layer: usize) -> Result<(), Error> {
125        let mut top = Vec::with_capacity(self.layers.len()-top_layer);
126        top.extend(self.layers.drain(top_layer..));
127
128        // delete the other layer files
129        for path in self.layers.iter() {
130            fs::remove_file(path)?;
131        }
132
133        // move the base layer
134        self.layers.clear();
135        for (i, path) in top.into_iter().enumerate() {
136            let new_path = self.path.join(i.to_string());
137            fs::rename(path, &new_path)?;
138            self.layers.push(new_path);
139        } Ok(())
140    }
141}