use serde::{Deserialize, Serialize};
use std::time::Duration;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheConfig {
pub enabled: bool,
pub max_memory_bytes: usize,
pub l1_config: LevelConfig,
pub l2_config: LevelConfig,
pub l3_config: LevelConfig,
pub eviction_policy: EvictionPolicy,
pub stats_interval: Duration,
pub compression_enabled: bool,
pub invalidation_strategy: InvalidationStrategy,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LevelConfig {
pub max_entries: usize,
pub max_memory_bytes: usize,
pub default_ttl: Option<Duration>,
pub policy: CachePolicy,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CachePolicy {
WriteThrough,
WriteBack,
WriteAround,
ReadThrough,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EvictionPolicy {
LRU,
LFU,
FIFO,
Random,
TTL,
Size,
ARC,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InvalidationStrategy {
Manual,
TTL,
TagBased,
Versioned,
Hybrid {
primary: Box<InvalidationStrategy>,
fallback: Box<InvalidationStrategy>,
},
}
impl Default for CacheConfig {
fn default() -> Self {
Self {
enabled: true,
max_memory_bytes: 1024 * 1024 * 512, l1_config: LevelConfig {
max_entries: 1000,
max_memory_bytes: 1024 * 1024 * 64, default_ttl: Some(Duration::from_secs(300)), policy: CachePolicy::ReadThrough,
},
l2_config: LevelConfig {
max_entries: 5000,
max_memory_bytes: 1024 * 1024 * 256, default_ttl: Some(Duration::from_secs(1800)), policy: CachePolicy::ReadThrough,
},
l3_config: LevelConfig {
max_entries: 20000,
max_memory_bytes: 1024 * 1024 * 192, default_ttl: Some(Duration::from_secs(3600)), policy: CachePolicy::WriteBack,
},
eviction_policy: EvictionPolicy::ARC,
stats_interval: Duration::from_secs(60),
compression_enabled: true,
invalidation_strategy: InvalidationStrategy::Hybrid {
primary: Box::new(InvalidationStrategy::TagBased),
fallback: Box::new(InvalidationStrategy::TTL),
},
}
}
}
impl CacheConfig {
pub fn read_optimized() -> Self {
let mut config = Self::default();
config.l1_config.max_entries = 2000;
config.l2_config.max_entries = 10000;
config.l1_config.default_ttl = Some(Duration::from_secs(600)); config.l2_config.default_ttl = Some(Duration::from_secs(3600)); config
}
pub fn write_optimized() -> Self {
let mut config = Self::default();
config.l1_config.policy = CachePolicy::WriteBack;
config.l2_config.policy = CachePolicy::WriteBack;
config.eviction_policy = EvictionPolicy::LRU; config.invalidation_strategy = InvalidationStrategy::TagBased;
config
}
pub fn memory_constrained() -> Self {
let mut config = Self::default();
config.max_memory_bytes = 1024 * 1024 * 128; config.l1_config.max_memory_bytes = 1024 * 1024 * 32; config.l1_config.max_entries = 500;
config.l2_config.max_memory_bytes = 1024 * 1024 * 64; config.l2_config.max_entries = 2000;
config.l3_config.max_memory_bytes = 1024 * 1024 * 32; config.l3_config.max_entries = 5000;
config.compression_enabled = true;
config
}
pub fn validate(&self) -> Result<(), String> {
if !self.enabled {
return Ok(());
}
let total_memory = self.l1_config.max_memory_bytes
+ self.l2_config.max_memory_bytes
+ self.l3_config.max_memory_bytes;
if total_memory > self.max_memory_bytes {
return Err(format!(
"Sum of level memory limits ({} bytes) exceeds max memory ({} bytes)",
total_memory, self.max_memory_bytes
));
}
if self.l1_config.max_entries == 0
|| self.l2_config.max_entries == 0
|| self.l3_config.max_entries == 0
{
return Err("Cache levels must have max_entries > 0".to_string());
}
Ok(())
}
}