1pub 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#[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
45pub enum ConfirmDestructiveAction {
48 IKnowWhatImDoing,
49}
50
51#[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 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}