pub(crate) mod engine;
pub use engine::BatchTrait;
use parking_lot::Mutex;
use ruc::*;
use std::{
env, fs,
mem::size_of,
path::{Path, PathBuf},
sync::{
LazyLock,
atomic::{AtomicBool, Ordering},
},
};
pub const NULL: &[u8] = &[];
pub type RawBytes = Vec<u8>;
pub type RawKey = RawBytes;
pub type RawValue = RawBytes;
pub type Pre = u64;
pub const PREFIX_SIZE: usize = size_of::<Pre>();
pub type PreBytes = [u8; PREFIX_SIZE];
pub const KB: u64 = 1 << 10;
pub const MB: u64 = 1 << 20;
pub const GB: u64 = 1 << 30;
const RESERVED_ID_CNT: Pre = 4096_0000;
pub const BIGGEST_RESERVED_ID: Pre = RESERVED_ID_CNT - 1;
const BASE_DIR_VAR: &str = "VSDB_BASE_DIR";
static VSDB_BASE_DIR: LazyLock<Mutex<PathBuf>> =
LazyLock::new(|| Mutex::new(gen_data_dir()));
static VSDB_CUSTOM_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
let mut d = VSDB_BASE_DIR.lock().clone();
d.push("__CUSTOM__");
pnk!(fs::create_dir_all(&d));
unsafe { env::set_var("VSDB_CUSTOM_DIR", d.as_os_str()) }
d
});
static VSDB_SYSTEM_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
let mut d = VSDB_BASE_DIR.lock().clone();
d.push("__SYSTEM__");
pnk!(fs::create_dir_all(&d));
d
});
static VSDB_META_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
let mut d = VSDB_SYSTEM_DIR.clone();
d.push("__instance_meta__");
pnk!(fs::create_dir_all(&d));
d
});
#[inline(always)]
pub fn vsdb_get_meta_dir() -> &'static Path {
VSDB_META_DIR.as_path()
}
#[inline(always)]
pub fn vsdb_meta_path(instance_id: u64) -> PathBuf {
let mut p = VSDB_META_DIR.clone();
p.push(format!("{:016x}", instance_id));
p
}
pub static VSDB: LazyLock<VsDB> = LazyLock::new(|| pnk!(VsDB::new()));
#[macro_export]
macro_rules! parse_int {
($bytes: expr, $ty: ty) => {{
let array: [u8; std::mem::size_of::<$ty>()] = $bytes[..].try_into().unwrap();
<$ty>::from_le_bytes(array)
}};
}
#[macro_export]
macro_rules! parse_prefix {
($bytes: expr) => {
$crate::parse_int!($bytes, $crate::common::Pre)
};
}
pub struct VsDB {
db: engine::Engine,
}
impl VsDB {
#[inline(always)]
fn new() -> Result<Self> {
Ok(Self {
db: engine::Engine::new().c(d!())?,
})
}
#[inline(always)]
fn flush(&self) {
self.db.flush()
}
}
#[inline(always)]
fn gen_data_dir() -> PathBuf {
let d = env::var(BASE_DIR_VAR)
.or_else(|_| env::var("HOME").map(|h| format!("{h}/.vsdb")))
.unwrap_or_else(|_| {
let mut p = env::temp_dir();
p.push(format!(".vsdb_{}", std::process::id()));
let s = p.to_string_lossy().into_owned();
eprintln!(
"vsdb: neither VSDB_BASE_DIR nor HOME is set; \
using temporary directory {s} (data will not persist across restarts)"
);
s
});
pnk!(fs::create_dir_all(&d));
PathBuf::from(d)
}
#[inline(always)]
pub fn vsdb_get_custom_dir() -> &'static Path {
VSDB_CUSTOM_DIR.as_path()
}
#[inline(always)]
pub fn vsdb_get_system_dir() -> &'static Path {
VSDB_SYSTEM_DIR.as_path()
}
#[inline(always)]
pub fn vsdb_get_base_dir() -> PathBuf {
VSDB_BASE_DIR.lock().clone()
}
#[inline(always)]
pub fn vsdb_set_base_dir(dir: impl AsRef<Path>) -> Result<()> {
static HAS_INITED: AtomicBool = AtomicBool::new(false);
if HAS_INITED.swap(true, Ordering::AcqRel) {
Err(eg!("VSDB has been initialized !!"))
} else {
unsafe { env::set_var(BASE_DIR_VAR, dir.as_ref().as_os_str()) }
*VSDB_BASE_DIR.lock() = dir.as_ref().to_path_buf();
Ok(())
}
}
#[inline(always)]
pub fn vsdb_flush() {
VSDB.flush();
}