#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SyncMode {
None = 0,
#[default]
Normal = 1,
Full = 2,
}
impl From<i32> for SyncMode {
fn from(value: i32) -> Self {
match value {
0 => SyncMode::None,
2 => SyncMode::Full,
_ => SyncMode::Normal,
}
}
}
impl From<SyncMode> for i32 {
fn from(mode: SyncMode) -> Self {
mode as i32
}
}
#[derive(Debug, Clone)]
pub struct PersistenceConfig {
pub enabled: bool,
pub sync_mode: SyncMode,
pub snapshot_interval: u32,
pub keep_snapshots: u32,
pub wal_flush_trigger: usize,
pub wal_buffer_size: usize,
pub wal_max_size: usize,
pub commit_batch_size: u32,
pub sync_interval_ms: u32,
pub wal_compression: bool,
pub snapshot_compression: bool,
pub compression_threshold: usize,
}
impl Default for PersistenceConfig {
fn default() -> Self {
Self {
enabled: true,
sync_mode: SyncMode::Normal,
snapshot_interval: 300, keep_snapshots: 5, wal_flush_trigger: 32 * 1024, wal_buffer_size: 64 * 1024, wal_max_size: 64 * 1024 * 1024, commit_batch_size: 100, sync_interval_ms: 10, wal_compression: true, snapshot_compression: true, compression_threshold: 64, }
}
}
impl PersistenceConfig {
pub fn new() -> Self {
Self::default()
}
pub fn durable() -> Self {
Self {
enabled: true,
sync_mode: SyncMode::Full,
snapshot_interval: 60, keep_snapshots: 10,
wal_flush_trigger: 8 * 1024, wal_buffer_size: 32 * 1024, wal_max_size: 32 * 1024 * 1024, commit_batch_size: 1, sync_interval_ms: 0, wal_compression: true,
snapshot_compression: true,
compression_threshold: 64,
}
}
pub fn fast() -> Self {
Self {
enabled: true,
sync_mode: SyncMode::None,
snapshot_interval: 600, keep_snapshots: 3,
wal_flush_trigger: 64 * 1024, wal_buffer_size: 128 * 1024, wal_max_size: 128 * 1024 * 1024, commit_batch_size: 500, sync_interval_ms: 100, wal_compression: true,
snapshot_compression: true,
compression_threshold: 64,
}
}
pub fn with_sync_mode(mut self, mode: SyncMode) -> Self {
self.sync_mode = mode;
self
}
pub fn with_snapshot_interval(mut self, seconds: u32) -> Self {
self.snapshot_interval = seconds;
self
}
pub fn with_keep_snapshots(mut self, count: u32) -> Self {
self.keep_snapshots = count;
self
}
pub fn with_wal_compression(mut self, enabled: bool) -> Self {
self.wal_compression = enabled;
self
}
pub fn with_snapshot_compression(mut self, enabled: bool) -> Self {
self.snapshot_compression = enabled;
self
}
pub fn with_compression(mut self, enabled: bool) -> Self {
self.wal_compression = enabled;
self.snapshot_compression = enabled;
self
}
pub fn with_compression_threshold(mut self, bytes: usize) -> Self {
self.compression_threshold = bytes;
self
}
}
#[derive(Debug, Clone, Default)]
pub struct Config {
pub path: Option<String>,
pub persistence: PersistenceConfig,
}
impl Config {
pub fn in_memory() -> Self {
Self {
path: None,
persistence: PersistenceConfig {
enabled: false,
..Default::default()
},
}
}
pub fn with_path<P: Into<String>>(path: P) -> Self {
Self {
path: Some(path.into()),
persistence: PersistenceConfig::default(),
}
}
pub fn is_persistent(&self) -> bool {
self.path.is_some() && self.persistence.enabled
}
pub fn with_persistence(mut self, config: PersistenceConfig) -> Self {
self.persistence = config;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sync_mode_default() {
assert_eq!(SyncMode::default(), SyncMode::Normal);
}
#[test]
fn test_sync_mode_from_i32() {
assert_eq!(SyncMode::from(0), SyncMode::None);
assert_eq!(SyncMode::from(1), SyncMode::Normal);
assert_eq!(SyncMode::from(2), SyncMode::Full);
assert_eq!(SyncMode::from(99), SyncMode::Normal); }
#[test]
fn test_persistence_config_default() {
let config = PersistenceConfig::default();
assert!(config.enabled);
assert_eq!(config.sync_mode, SyncMode::Normal);
assert_eq!(config.snapshot_interval, 300);
assert_eq!(config.keep_snapshots, 5);
assert_eq!(config.wal_flush_trigger, 32 * 1024);
assert_eq!(config.wal_buffer_size, 64 * 1024);
assert_eq!(config.wal_max_size, 64 * 1024 * 1024);
assert_eq!(config.commit_batch_size, 100);
assert_eq!(config.sync_interval_ms, 10);
assert!(config.wal_compression);
assert!(config.snapshot_compression);
assert_eq!(config.compression_threshold, 64);
}
#[test]
fn test_persistence_config_durable() {
let config = PersistenceConfig::durable();
assert_eq!(config.sync_mode, SyncMode::Full);
assert_eq!(config.commit_batch_size, 1);
assert_eq!(config.sync_interval_ms, 0);
}
#[test]
fn test_persistence_config_fast() {
let config = PersistenceConfig::fast();
assert_eq!(config.sync_mode, SyncMode::None);
assert_eq!(config.commit_batch_size, 500);
}
#[test]
fn test_persistence_config_builder() {
let config = PersistenceConfig::new()
.with_sync_mode(SyncMode::Full)
.with_snapshot_interval(120)
.with_keep_snapshots(10);
assert_eq!(config.sync_mode, SyncMode::Full);
assert_eq!(config.snapshot_interval, 120);
assert_eq!(config.keep_snapshots, 10);
}
#[test]
fn test_persistence_config_compression() {
let config = PersistenceConfig::new().with_compression(false);
assert!(!config.wal_compression);
assert!(!config.snapshot_compression);
let config = PersistenceConfig::new()
.with_wal_compression(false)
.with_snapshot_compression(true);
assert!(!config.wal_compression);
assert!(config.snapshot_compression);
let config = PersistenceConfig::new().with_compression_threshold(128);
assert_eq!(config.compression_threshold, 128);
}
#[test]
fn test_config_in_memory() {
let config = Config::in_memory();
assert!(config.path.is_none());
assert!(!config.persistence.enabled);
assert!(!config.is_persistent());
}
#[test]
fn test_config_with_path() {
let config = Config::with_path("/tmp/test.db");
assert_eq!(config.path, Some("/tmp/test.db".to_string()));
assert!(config.persistence.enabled);
assert!(config.is_persistent());
}
#[test]
fn test_config_builder() {
let config =
Config::with_path("/tmp/test.db").with_persistence(PersistenceConfig::durable());
assert!(config.is_persistent());
assert_eq!(config.persistence.sync_mode, SyncMode::Full);
}
}