walrus_rust/wal/
config.rs

1use std::path::PathBuf;
2use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
3use std::time::SystemTime;
4
5// Global flag to choose backend
6pub(crate) static USE_FD_BACKEND: AtomicBool = AtomicBool::new(true);
7
8// Public function to enable FD backend
9pub fn enable_fd_backend() {
10    USE_FD_BACKEND.store(true, Ordering::Relaxed);
11}
12
13// Public function to disable FD backend (use mmap instead)
14pub fn disable_fd_backend() {
15    USE_FD_BACKEND.store(false, Ordering::Relaxed);
16}
17
18// Macro to conditionally print debug messages
19macro_rules! debug_print {
20    ($($arg:tt)*) => {
21        if std::env::var("WALRUS_QUIET").is_err() {
22            println!($($arg)*);
23        }
24    };
25}
26
27pub(crate) use debug_print;
28
29#[derive(Clone, Copy, Debug)]
30pub enum FsyncSchedule {
31    Milliseconds(u64),
32    SyncEach, // fsync after every single entry
33    NoFsync,  // disable fsyncing entirely (maximum throughput, no durability)
34}
35
36pub(crate) const DEFAULT_BLOCK_SIZE: u64 = 10 * 1024 * 1024; // 10mb
37pub(crate) const BLOCKS_PER_FILE: u64 = 100;
38pub(crate) const MAX_ALLOC: u64 = 1 * 1024 * 1024 * 1024; // 1 GiB cap per block
39pub(crate) const PREFIX_META_SIZE: usize = 64;
40pub(crate) const MAX_FILE_SIZE: u64 = DEFAULT_BLOCK_SIZE * BLOCKS_PER_FILE;
41pub(crate) const MAX_BATCH_ENTRIES: usize = 2000;
42pub(crate) const MAX_BATCH_BYTES: u64 = 10 * 1024 * 1024 * 1024; // 10 GiB total payload limit
43
44static LAST_MILLIS: AtomicU64 = AtomicU64::new(0);
45
46pub(crate) fn now_millis_str() -> String {
47    let system_ms = SystemTime::now()
48        .duration_since(SystemTime::UNIX_EPOCH)
49        .unwrap_or_else(|_| std::time::Duration::from_secs(0))
50        .as_millis();
51
52    let mut observed = LAST_MILLIS.load(Ordering::Relaxed);
53    loop {
54        let system_ms_u64 = system_ms.try_into().unwrap_or(u64::MAX);
55        let candidate = if system_ms_u64 <= observed {
56            observed.saturating_add(1)
57        } else {
58            system_ms_u64
59        };
60
61        match LAST_MILLIS.compare_exchange(observed, candidate, Ordering::AcqRel, Ordering::Acquire)
62        {
63            Ok(_) => return candidate.to_string(),
64            Err(actual) => observed = actual,
65        }
66    }
67}
68
69pub(crate) fn checksum64(data: &[u8]) -> u64 {
70    // FNV-1a 64-bit checksum
71    const FNV_OFFSET: u64 = 0xcbf29ce484222325;
72    const FNV_PRIME: u64 = 0x00000100000001B3;
73    let mut hash = FNV_OFFSET;
74    for &b in data {
75        hash ^= b as u64;
76        hash = hash.wrapping_mul(FNV_PRIME);
77    }
78    hash
79}
80
81pub(crate) fn wal_data_dir() -> PathBuf {
82    std::env::var_os("WALRUS_DATA_DIR")
83        .map(PathBuf::from)
84        .unwrap_or_else(|| PathBuf::from("wal_files"))
85}
86
87pub(crate) fn sanitize_namespace(key: &str) -> String {
88    let mut sanitized: String = key
89        .chars()
90        .map(|c| {
91            if c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.') {
92                c
93            } else {
94                '_'
95            }
96        })
97        .collect();
98
99    if sanitized.trim_matches('_').is_empty() {
100        sanitized = format!("ns_{:x}", checksum64(key.as_bytes()));
101    }
102    sanitized
103}