use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DurabilityLevel {
Synchronous,
GroupCommit {
max_batch_size: usize,
max_wait_us: u64,
},
Periodic {
interval_ms: u64,
},
NoSync,
}
impl Default for DurabilityLevel {
fn default() -> Self {
DurabilityLevel::GroupCommit {
max_batch_size: 1000,
max_wait_us: 1000, }
}
}
impl DurabilityLevel {
pub fn synchronous() -> Self {
Self::Synchronous
}
pub fn group_commit() -> Self {
Self::GroupCommit {
max_batch_size: 1000,
max_wait_us: 1000,
}
}
pub fn group_commit_custom(max_batch_size: usize, max_wait_us: u64) -> Self {
Self::GroupCommit {
max_batch_size,
max_wait_us,
}
}
pub fn periodic(interval_ms: u64) -> Self {
Self::Periodic { interval_ms }
}
pub fn no_sync() -> Self {
Self::NoSync
}
pub fn requires_immediate_sync(&self) -> bool {
matches!(self, Self::Synchronous)
}
pub fn is_no_sync(&self) -> bool {
matches!(self, Self::NoSync)
}
pub fn description(&self) -> &'static str {
match self {
Self::Synchronous => "同步模式(最安全)",
Self::GroupCommit { .. } => "Group Commit(推荐)",
Self::Periodic { .. } => "定期刷盘(高性能)",
Self::NoSync => "不刷盘(仅测试)",
}
}
pub fn expected_throughput(&self) -> &'static str {
match self {
Self::Synchronous => "50 ops/s",
Self::GroupCommit { .. } => "5K-10K ops/s",
Self::Periodic { .. } => "50K+ ops/s",
Self::NoSync => "100K+ ops/s",
}
}
pub fn safety_level(&self) -> &'static str {
match self {
Self::Synchronous | Self::GroupCommit { .. } => "100% 安全",
Self::Periodic { interval_ms } => {
if *interval_ms <= 100 {
"丢失 <100ms 数据"
} else {
"丢失数据风险较高"
}
}
Self::NoSync => "⚠️ 不安全",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WALConfig {
pub durability_level: DurabilityLevel,
pub wal_dir: String,
pub max_wal_size: u64,
pub enable_compression: bool,
}
impl Default for WALConfig {
fn default() -> Self {
Self {
durability_level: DurabilityLevel::default(),
wal_dir: "wal".to_string(),
max_wal_size: 64 * 1024 * 1024, enable_compression: false,
}
}
}
impl WALConfig {
pub fn for_financial() -> Self {
Self {
durability_level: DurabilityLevel::Synchronous,
..Default::default()
}
}
pub fn for_general() -> Self {
Self {
durability_level: DurabilityLevel::group_commit(),
..Default::default()
}
}
pub fn for_logging() -> Self {
Self {
durability_level: DurabilityLevel::periodic(100),
..Default::default()
}
}
pub fn for_testing() -> Self {
Self {
durability_level: DurabilityLevel::NoSync,
..Default::default()
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Default)]
pub enum IndexUpdateStrategy {
#[default]
BatchOnly,
Hybrid {
realtime_index_types: Vec<RealtimeIndexType>,
},
Realtime,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RealtimeIndexType {
PrimaryKey,
Unique,
SecondaryColumn,
Vector,
Spatial,
FullText,
}
impl IndexUpdateStrategy {
pub fn batch_only() -> Self {
Self::BatchOnly
}
pub fn hybrid_default() -> Self {
Self::Hybrid {
realtime_index_types: vec![
RealtimeIndexType::PrimaryKey,
RealtimeIndexType::Unique,
RealtimeIndexType::SecondaryColumn,
],
}
}
pub fn hybrid_custom(realtime_index_types: Vec<RealtimeIndexType>) -> Self {
Self::Hybrid { realtime_index_types }
}
pub fn realtime() -> Self {
Self::Realtime
}
pub fn should_update_realtime(&self, index_type: RealtimeIndexType) -> bool {
match self {
Self::BatchOnly => {
index_type == RealtimeIndexType::PrimaryKey
}
Self::Hybrid { realtime_index_types } => {
realtime_index_types.contains(&index_type)
}
Self::Realtime => true, }
}
pub fn description(&self) -> &'static str {
match self {
Self::BatchOnly => "批量构建(最高性能)",
Self::Hybrid { .. } => "混合模式(推荐)",
Self::Realtime => "实时模式(最低延迟)",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DBConfig {
pub wal_config: WALConfig,
pub num_partitions: u8,
pub lsm_config: LSMConfig,
pub enable_stats: bool,
pub row_cache_size: Option<usize>,
pub index_update_strategy: IndexUpdateStrategy,
pub query_timeout_secs: Option<u64>,
}
impl Default for DBConfig {
fn default() -> Self {
Self {
wal_config: WALConfig::default(),
num_partitions: 4,
lsm_config: LSMConfig::default(),
enable_stats: true,
row_cache_size: None, index_update_strategy: IndexUpdateStrategy::default(), query_timeout_secs: None, }
}
}
impl DBConfig {
pub fn for_financial() -> Self {
Self {
wal_config: WALConfig::for_financial(),
..Default::default()
}
}
pub fn for_general() -> Self {
Self {
wal_config: WALConfig::for_general(),
..Default::default()
}
}
pub fn for_high_performance() -> Self {
Self {
wal_config: WALConfig::for_logging(),
..Default::default()
}
}
pub fn for_testing() -> Self {
Self {
wal_config: WALConfig::for_testing(),
..Default::default()
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LSMConfig {
pub memtable_size_limit: usize,
pub level0_compaction_threshold: usize,
pub bloom_filter_false_positive_rate: f64,
}
impl Default for LSMConfig {
fn default() -> Self {
Self {
memtable_size_limit: 64 * 1024 * 1024, level0_compaction_threshold: 4,
bloom_filter_false_positive_rate: 0.01, }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_durability_levels() {
let sync = DurabilityLevel::Synchronous;
assert!(sync.requires_immediate_sync());
assert_eq!(sync.expected_throughput(), "50 ops/s");
let group = DurabilityLevel::group_commit();
assert!(!group.requires_immediate_sync());
assert_eq!(group.safety_level(), "100% 安全");
let no_sync = DurabilityLevel::NoSync;
assert!(no_sync.is_no_sync());
assert!(no_sync.safety_level().contains("不安全"));
}
#[test]
fn test_config_presets() {
let financial = DBConfig::for_financial();
assert!(financial.wal_config.durability_level.requires_immediate_sync());
let general = DBConfig::for_general();
assert!(!general.wal_config.durability_level.requires_immediate_sync());
let testing = DBConfig::for_testing();
assert!(testing.wal_config.durability_level.is_no_sync());
}
}