wedb_embed 0.1.2

Embedded database engine providing Redis-like APIs, built on fjall / 嵌入式数据库引擎,提供类似 Redis 的接口,底层基于 fjall 开发
Documentation
use serde::{Deserialize, Serialize};

/// 压缩算法枚举(强类型 enum,默认开启 Lz4)
#[derive(
  Debug,
  Clone,
  Copy,
  PartialEq,
  Eq,
  Serialize,
  Deserialize,
  bitcode::Encode,
  bitcode::Decode,
  Default,
)]
#[repr(u8)]
pub enum Compression {
  #[default]
  Lz4 = 0,
  None = 1,
}

impl From<Compression> for fjall::CompressionType {
  #[inline]
  fn from(c: Compression) -> Self {
    match c {
      Compression::Lz4 => fjall::CompressionType::Lz4,
      Compression::None => fjall::CompressionType::None,
    }
  }
}

impl From<fjall::CompressionType> for Compression {
  #[inline]
  fn from(c: fjall::CompressionType) -> Self {
    match c {
      fjall::CompressionType::Lz4 => Compression::Lz4,
      fjall::CompressionType::None => Compression::None,
    }
  }
}

/// 持久化模式枚举(强类型 enum,默认 SyncData)
#[derive(
  Debug,
  Clone,
  Copy,
  PartialEq,
  Eq,
  Serialize,
  Deserialize,
  bitcode::Encode,
  bitcode::Decode,
  Default,
)]
#[repr(u8)]
pub enum PersistMode {
  Buffer = 0,
  #[default]
  SyncData = 1,
  SyncAll = 2,
}

impl From<PersistMode> for fjall::PersistMode {
  #[inline]
  fn from(m: PersistMode) -> Self {
    match m {
      PersistMode::Buffer => fjall::PersistMode::Buffer,
      PersistMode::SyncData => fjall::PersistMode::SyncData,
      PersistMode::SyncAll => fjall::PersistMode::SyncAll,
    }
  }
}

/// 数据库配置选项枚举(纯 enum 强类型,绝无字符串,默认开启 LZ4 压缩)
#[derive(
  Debug, Clone, Copy, PartialEq, Serialize, Deserialize, bitcode::Encode, bitcode::Decode,
)]
pub enum Conf {
  /// 块缓存容量(字节,默认 512MB)
  CacheSize(usize),
  /// 数据压缩策略(默认 Lz4)
  Compression(Compression),
  /// WAL 日志压缩(默认 None)
  JournalCompression(Compression),
  /// 是否启用手动 Journal 异步持久化(true 换取毫秒级异步微批刷盘,默认 true)
  ManualJournalPersist(bool),
  /// 异步刷盘周期毫秒数(默认 50ms,0 表示禁用后台定时刷盘)
  PersistIntervalMs(u64),
  /// 持久化同步模式(默认 SyncData)
  PersistMode(PersistMode),
  /// 工作线程数
  WorkerThreads(usize),
  /// 最大 WAL 日志总大小(字节,底层 fjall 要求至少 64MB)
  MaxJournalingSize(usize),
  /// 最大文件句柄缓存数
  MaxCachedFiles(usize),
  /// 业务数据 Keyspace 块大小(字节,默认 8KB)
  DataBlockSize(usize),
  /// 复合元数据 Keyspace 块大小(字节,默认 4KB)
  MetaBlockSize(usize),
  /// 业务数据 Memtable 缓冲区大小(字节,默认 64MB)
  DataMemtableSize(usize),
  /// 复合元数据 Memtable 缓冲区大小(字节,默认 32MB)
  MetaMemtableSize(usize),
  /// KV 分离阈值(字节,大于该阈值的 Value 直写 Blob 日志,默认 4096)
  KvSeparationThreshold(usize),
  /// 禁用 KV 分离
  DisableKvSeparation,
  /// 块内哈希索引比率(默认 0.75)
  DataHashRatio(f32),
  /// 是否预知点查高命中(底层跳过构建最后一层 Bloom 过滤器以节省内存,默认 false)
  ExpectPointReadHits(bool),
  /// 临时数据库(Drop 时自动清理目录,默认 false)
  Temporary(bool),
}

/// 内部解析后的完整配置状态
#[derive(Debug, Clone)]
pub struct DbConfig {
  pub cache_size: usize,
  pub compression: Compression,
  pub journal_compression: Compression,
  pub manual_journal_persist: bool,
  pub persist_interval_ms: u64,
  pub persist_mode: PersistMode,
  pub worker_threads: Option<usize>,
  pub max_journaling_size: Option<usize>,
  pub max_cached_files: Option<usize>,
  pub data_block_size: usize,
  pub meta_block_size: usize,
  pub data_memtable_size: usize,
  pub meta_memtable_size: usize,
  pub kv_separation_threshold: Option<usize>,
  pub data_hash_ratio: f32,
  pub expect_point_read_hits: bool,
  pub temporary: bool,
}

impl Default for DbConfig {
  fn default() -> Self {
    Self {
      cache_size: 512 * 1024 * 1024,
      compression: Compression::Lz4,
      journal_compression: Compression::None,
      manual_journal_persist: true,
      persist_interval_ms: 50,
      persist_mode: PersistMode::SyncData,
      worker_threads: None,
      max_journaling_size: None,
      max_cached_files: None,
      data_block_size: 8 * 1024,
      meta_block_size: 4 * 1024,
      data_memtable_size: 64 * 1024 * 1024,
      meta_memtable_size: 32 * 1024 * 1024,
      kv_separation_threshold: Some(4096),
      data_hash_ratio: 0.75,
      expect_point_read_hits: false,
      temporary: false,
    }
  }
}

impl DbConfig {
  /// 从配置枚举项迭代器构造完整配置
  pub fn from_conf_li<I>(conf_li: I) -> Self
  where
    I: IntoIterator<Item = Conf>,
  {
    let mut cfg = Self::default();
    for opt in conf_li {
      match opt {
        Conf::CacheSize(sz) => cfg.cache_size = sz,
        Conf::Compression(c) => cfg.compression = c,
        Conf::JournalCompression(jc) => cfg.journal_compression = jc,
        Conf::ManualJournalPersist(m) => cfg.manual_journal_persist = m,
        Conf::PersistIntervalMs(ms) => cfg.persist_interval_ms = ms,
        Conf::PersistMode(pm) => cfg.persist_mode = pm,
        Conf::WorkerThreads(wt) => cfg.worker_threads = Some(wt),
        Conf::MaxJournalingSize(sz) => cfg.max_journaling_size = Some(sz),
        Conf::MaxCachedFiles(cf) => cfg.max_cached_files = Some(cf),
        Conf::DataBlockSize(sz) => cfg.data_block_size = sz,
        Conf::MetaBlockSize(sz) => cfg.meta_block_size = sz,
        Conf::DataMemtableSize(sz) => cfg.data_memtable_size = sz,
        Conf::MetaMemtableSize(sz) => cfg.meta_memtable_size = sz,
        Conf::KvSeparationThreshold(sz) => cfg.kv_separation_threshold = Some(sz),
        Conf::DisableKvSeparation => cfg.kv_separation_threshold = None,
        Conf::DataHashRatio(r) => cfg.data_hash_ratio = r,
        Conf::ExpectPointReadHits(b) => cfg.expect_point_read_hits = b,
        Conf::Temporary(t) => cfg.temporary = t,
      }
    }
    cfg
  }
}