vsdb_core/common/mod.rs
1//!
2//! # Common components
3//!
4//! This module provides common components and utilities used throughout the VSDB framework.
5//! It includes type definitions, constants, macros, and functions for managing the
6//! underlying database environment.
7//!
8
9pub(crate) mod engines;
10
11use engines::Engine;
12use parking_lot::Mutex;
13use ruc::*;
14use std::{
15 env, fs,
16 mem::size_of,
17 path::{Path, PathBuf},
18 sync::{
19 LazyLock,
20 atomic::{AtomicBool, Ordering},
21 },
22};
23use threadpool::ThreadPool;
24
25/////////////////////////////////////////////////////////////////////////////
26/////////////////////////////////////////////////////////////////////////////
27
28/// A constant representing a null or empty byte slice.
29pub const NULL: &[u8] = &[];
30
31/// A type alias for a vector of bytes, commonly used for raw data.
32pub type RawBytes = Vec<u8>;
33/// A type alias for a raw key, represented as a vector of bytes.
34pub type RawKey = RawBytes;
35/// A type alias for a raw value, represented as a vector of bytes.
36pub type RawValue = RawBytes;
37
38/// A type alias for a prefix, represented as a `u64`.
39pub type Pre = u64;
40/// The size of a prefix in bytes.
41pub const PREFIX_SIZE: usize = size_of::<Pre>();
42/// A type alias for a prefix represented as a byte array.
43pub type PreBytes = [u8; PREFIX_SIZE];
44
45/// A constant representing 1 kilobyte in bytes.
46pub const KB: u64 = 1 << 10;
47/// A constant representing 1 megabyte in bytes.
48pub const MB: u64 = 1 << 20;
49/// A constant representing 1 gigabyte in bytes.
50pub const GB: u64 = 1 << 30;
51
52/// The number of reserved IDs.
53const RESERVED_ID_CNT: Pre = 4096_0000;
54/// The biggest reserved ID.
55pub const BIGGEST_RESERVED_ID: Pre = RESERVED_ID_CNT - 1;
56
57/////////////////////////////////////////////////////////////////////////////
58/////////////////////////////////////////////////////////////////////////////
59
60const BASE_DIR_VAR: &str = "VSDB_BASE_DIR";
61
62static VSDB_BASE_DIR: LazyLock<Mutex<PathBuf>> =
63 LazyLock::new(|| Mutex::new(gen_data_dir()));
64
65static VSDB_CUSTOM_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
66 let mut d = VSDB_BASE_DIR.lock().clone();
67 d.push("__CUSTOM__");
68 pnk!(fs::create_dir_all(&d));
69 unsafe { env::set_var("VSDB_CUSTOM_DIR", d.as_os_str()) }
70 d
71});
72
73/// The global instance of the VsDB database.
74///
75/// This static variable is lazily initialized and provides a single point of
76/// access to the underlying database. The backend is determined by the
77/// feature flags passed at compile time.
78#[cfg(feature = "rocks_backend")]
79pub static VSDB: LazyLock<VsDB<engines::RocksDB>> = LazyLock::new(|| pnk!(VsDB::new()));
80
81/// The global instance of the VsDB database.
82///
83/// This static variable is lazily initialized and provides a single point of
84/// access to the underlying database. The backend is determined by the
85/// feature flags passed at compile time.
86#[cfg(feature = "parity_backend")]
87pub static VSDB: LazyLock<VsDB<engines::ParityDB>> = LazyLock::new(|| pnk!(VsDB::new()));
88
89/// A thread pool for cleaning up orphan instances in the background.
90///
91/// This static variable is lazily initialized and provides a thread pool
92/// with a single thread and a large stack size to handle background cleanup tasks.
93pub static TRASH_CLEANER: LazyLock<Mutex<ThreadPool>> = LazyLock::new(|| {
94 let pool = threadpool::Builder::new()
95 .num_threads(1)
96 .thread_stack_size(512 * MB as usize) // use large stack size
97 .build();
98 Mutex::new(pool)
99});
100
101/////////////////////////////////////////////////////////////////////////////
102/////////////////////////////////////////////////////////////////////////////
103
104/// A macro to parse a byte slice into a specified integer type.
105///
106/// # Arguments
107///
108/// * `$bytes` - The byte slice to parse.
109/// * `$ty` - The integer type to parse the bytes into.
110///
111/// # Panics
112///
113/// This macro will panic if the byte slice cannot be converted into the specified integer type.
114#[macro_export]
115macro_rules! parse_int {
116 ($bytes: expr, $ty: ty) => {{
117 let array: [u8; std::mem::size_of::<$ty>()] = $bytes[..].try_into().unwrap();
118 <$ty>::from_be_bytes(array)
119 }};
120}
121
122/// A macro to parse a byte slice into a `Pre` type.
123///
124/// # Arguments
125///
126/// * `$bytes` - The byte slice to parse.
127///
128/// # Panics
129///
130/// This macro will panic if the byte slice cannot be converted into a `Pre` type.
131#[macro_export]
132macro_rules! parse_prefix {
133 ($bytes: expr) => {
134 $crate::parse_int!($bytes, $crate::common::Pre)
135 };
136}
137
138/////////////////////////////////////////////////////////////////////////////
139/////////////////////////////////////////////////////////////////////////////
140
141/// A struct representing the VsDB database.
142///
143/// This struct encapsulates the underlying database engine and provides a
144/// high-level interface for interacting with the database.
145pub struct VsDB<T: Engine> {
146 db: T,
147}
148
149impl<T: Engine> VsDB<T> {
150 #[inline(always)]
151 fn new() -> Result<Self> {
152 Ok(Self {
153 db: T::new().c(d!())?,
154 })
155 }
156
157 #[inline(always)]
158 fn flush(&self) {
159 self.db.flush()
160 }
161}
162
163/////////////////////////////////////////////////////////////////////////////
164/////////////////////////////////////////////////////////////////////////////
165
166#[inline(always)]
167fn gen_data_dir() -> PathBuf {
168 // Compatible with Windows OS?
169 let d = env::var(BASE_DIR_VAR)
170 .or_else(|_| env::var("HOME").map(|h| format!("{h}/.vsdb")))
171 .unwrap_or_else(|_| "/tmp/.vsdb".to_owned());
172 pnk!(fs::create_dir_all(&d));
173 PathBuf::from(d)
174}
175
176/// Returns the custom directory path for VSDB.
177///
178/// This function returns a static reference to the path of the custom directory,
179/// which is set by the `VSDB_CUSTOM_DIR` environment variable.
180///
181/// # Returns
182///
183/// A `&'static Path` to the custom directory.
184#[inline(always)]
185pub fn vsdb_get_custom_dir() -> &'static Path {
186 VSDB_CUSTOM_DIR.as_path()
187}
188
189/// Returns the base directory path for VSDB.
190///
191/// This function returns the path of the base directory, which is determined
192/// by the `VSDB_BASE_DIR` environment variable, the `HOME` environment variable,
193/// or a default path of `/tmp/.vsdb`.
194///
195/// # Returns
196///
197/// A `PathBuf` to the base directory.
198#[inline(always)]
199pub fn vsdb_get_base_dir() -> PathBuf {
200 VSDB_BASE_DIR.lock().clone()
201}
202
203/// Sets the base directory path for VSDB manually.
204///
205/// This function allows you to programmatically set the base directory for VSDB.
206/// It can only be called once, before the database is initialized.
207///
208/// # Arguments
209///
210/// * `dir` - An object that can be converted into a `Path`.
211///
212/// # Errors
213///
214/// This function will return an error if the base directory has already been initialized.
215#[inline(always)]
216pub fn vsdb_set_base_dir(dir: impl AsRef<Path>) -> Result<()> {
217 static HAS_INITED: AtomicBool = AtomicBool::new(false);
218
219 if HAS_INITED.swap(true, Ordering::Relaxed) {
220 Err(eg!("VSDB has been initialized !!"))
221 } else {
222 unsafe { env::set_var(BASE_DIR_VAR, dir.as_ref().as_os_str()) }
223 *VSDB_BASE_DIR.lock() = dir.as_ref().to_path_buf();
224 Ok(())
225 }
226}
227
228/// Flushes all data to disk.
229///
230/// This function triggers a flush operation on the underlying database,
231/// ensuring that all pending writes are persisted to disk. This operation
232/// may take a long time to complete, depending on the amount of data to be flushed.
233#[inline(always)]
234pub fn vsdb_flush() {
235 VSDB.flush();
236}