block_db/
lib.rs

1// Authors: Robert Lopez
2
3pub mod batch;
4pub mod error;
5pub mod options;
6pub mod size;
7pub mod uncorrupt;
8
9pub(crate) mod clear_data_file;
10pub(crate) mod compact_data_file;
11pub(crate) mod data_file;
12pub(crate) mod delete;
13pub(crate) mod delete_data_file;
14pub(crate) mod free;
15pub(crate) mod read;
16pub(crate) mod recover;
17pub(crate) mod recover_data_file;
18pub(crate) mod util;
19pub(crate) mod wal;
20pub(crate) mod write;
21
22#[cfg(test)]
23mod tests;
24
25use data_file::DataFile;
26use error::Error;
27use options::{store::OptionsStore, BlockDBOptions};
28use serde::{Deserialize, Serialize};
29use std::{
30    collections::HashMap,
31    path::{Path, PathBuf},
32    sync::Arc,
33};
34use tokio::sync::RwLock;
35use util::fs::{create_directory, delete_directory, delete_temp_files, DirectoryIter};
36use wal::{BlockDBState, BlockDBWAL};
37
38/// Identifies a `DataBlock` in a `DataFile`
39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
40pub struct BlockKey {
41    pub data_file_id: String,
42    pub data_block_id: String,
43}
44
45/// Confirms actions that are very destructive like deleting
46/// or clearing an entire `DataFile`
47pub enum ConfirmDestructiveAction {
48    IKnowWhatImDoing,
49}
50
51/// Local, multi-threaded, durable byte DB.
52///
53/// Please see the [README](https://gitlab.com/robertlopezdev/block-db/-/blob/main/README.md) and or [docs.rs](https://docs.rs/block-db/latest/block_db/) for usage information.
54#[derive(Debug, Clone)]
55pub struct BlockDB {
56    pub path: Arc<PathBuf>,
57    pub options_store: Arc<OptionsStore>,
58
59    pub(crate) wal: Arc<RwLock<BlockDBWAL>>,
60    pub(crate) data_files: Arc<RwLock<HashMap<String, Arc<RwLock<DataFile>>>>>,
61}
62
63impl BlockDB {
64    /// Open or create a `BlockDB` at `path`.
65    ///
66    /// ---
67    /// Example
68    /// ```
69    /// let block_db = BlockDB::open("./db").await?;
70    /// ```
71    pub async fn open<P: AsRef<Path>>(
72        path: P,
73        options: Option<BlockDBOptions>,
74    ) -> Result<Self, Error> {
75        let path = path.as_ref().to_path_buf();
76        create_directory(&path).await?;
77
78        let mut wal = BlockDBWAL::open(path.join("wal")).await?;
79        let BlockDBState { valid_data_files } = wal.replay(None).await?;
80
81        let options_store_path = path.join("options_store");
82        create_directory(&options_store_path).await?;
83        delete_temp_files(&options_store_path).await?;
84
85        let options_store = Arc::new(OptionsStore::open(options_store_path, options).await?);
86
87        let data_files_path = path.join("data_files");
88        create_directory(&data_files_path).await?;
89
90        let mut data_files = HashMap::new();
91        let mut data_files_directory_iter = DirectoryIter::new(&data_files_path).await?;
92
93        while let Some((directory_name, directory_path)) = data_files_directory_iter.next().await? {
94            if valid_data_files.contains(&directory_name) {
95                delete_temp_files(&directory_path).await?;
96
97                let data_file = DataFile::open(
98                    directory_name.clone(),
99                    directory_path,
100                    options_store.clone(),
101                )
102                .await?;
103
104                data_files.insert(directory_name, Arc::new(RwLock::new(data_file)));
105            } else {
106                delete_directory(&directory_path).await?;
107            }
108        }
109
110        Ok(Self {
111            wal: Arc::new(RwLock::new(wal)),
112            path: Arc::new(path),
113            data_files: Arc::new(RwLock::new(data_files)),
114            options_store,
115        })
116    }
117}