use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Default, Deserialize)]
pub struct LayerConfig {
pub l1: L1LayerConfig,
pub l2: L2LayerConfig,
pub two_level: TwoLevelLayerConfig,
}
impl LayerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_l1(mut self, l1: L1LayerConfig) -> Self {
self.l1 = l1;
self
}
pub fn with_l2(mut self, l2: L2LayerConfig) -> Self {
self.l2 = l2;
self
}
pub fn with_two_level(mut self, two_level: TwoLevelLayerConfig) -> Self {
self.two_level = two_level;
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct L1LayerConfig {
pub max_capacity: u64,
pub max_key_length: usize,
pub max_value_size: usize,
pub cleanup_interval_secs: u64,
pub eviction_policy: EvictionPolicy,
}
impl L1LayerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_max_capacity(mut self, capacity: u64) -> Self {
self.max_capacity = capacity;
self
}
pub fn with_eviction_policy(mut self, policy: EvictionPolicy) -> Self {
self.eviction_policy = policy;
self
}
}
impl Default for L1LayerConfig {
fn default() -> Self {
Self {
max_capacity: 10000,
max_key_length: 512,
max_value_size: 1024 * 1024, cleanup_interval_secs: 300,
eviction_policy: EvictionPolicy::default(),
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct L2LayerConfig {
pub mode: RedisMode,
pub connection_string: String,
pub connection_timeout_ms: u64,
pub command_timeout_ms: u64,
pub default_ttl: u64,
pub max_key_length: usize,
pub max_value_size: usize,
}
impl L2LayerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_connection_string(mut self, connection_string: String) -> Self {
self.connection_string = connection_string;
self
}
pub fn with_mode(mut self, mode: RedisMode) -> Self {
self.mode = mode;
self
}
pub fn with_default_ttl(mut self, ttl: u64) -> Self {
self.default_ttl = ttl;
self
}
}
impl Default for L2LayerConfig {
fn default() -> Self {
Self {
mode: RedisMode::Standalone,
connection_string: String::new(),
connection_timeout_ms: 5000,
command_timeout_ms: 30000,
default_ttl: 3600,
max_key_length: 512,
max_value_size: 10 * 1024 * 1024, }
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct TwoLevelLayerConfig {
pub promote_on_hit: bool,
pub enable_batch_write: bool,
pub batch_size: usize,
pub batch_interval_ms: u64,
pub max_key_length: Option<usize>,
pub max_value_size: Option<usize>,
}
impl TwoLevelLayerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_enable_batch_write(mut self, enable: bool) -> Self {
self.enable_batch_write = enable;
self
}
pub fn with_batch_size(mut self, size: usize) -> Self {
self.batch_size = size;
self
}
}
impl Default for TwoLevelLayerConfig {
fn default() -> Self {
Self {
promote_on_hit: true,
enable_batch_write: false,
batch_size: 100,
batch_interval_ms: 10,
max_key_length: Some(512),
max_value_size: Some(10 * 1024 * 1024), }
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum EvictionPolicy {
#[default]
Lru,
Lfu,
TinyLfu,
Random,
}
impl fmt::Display for EvictionPolicy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EvictionPolicy::Lru => write!(f, "lru"),
EvictionPolicy::Lfu => write!(f, "lfu"),
EvictionPolicy::TinyLfu => write!(f, "tiny_lfu"),
EvictionPolicy::Random => write!(f, "random"),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum RedisMode {
#[default]
Standalone,
Sentinel,
Cluster,
}
impl fmt::Display for RedisMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RedisMode::Standalone => write!(f, "standalone"),
RedisMode::Sentinel => write!(f, "sentinel"),
RedisMode::Cluster => write!(f, "cluster"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_layer_config_default() {
let layer = LayerConfig::default();
assert_eq!(layer.l1.max_capacity, 10000);
assert_eq!(layer.l2.default_ttl, 3600);
}
#[test]
fn test_l1_layer_config() {
let l1 = L1LayerConfig::new()
.with_max_capacity(50000)
.with_eviction_policy(EvictionPolicy::Lru);
assert_eq!(l1.max_capacity, 50000);
assert_eq!(l1.eviction_policy, EvictionPolicy::Lru);
}
#[test]
fn test_l2_layer_config() {
let l2 = L2LayerConfig::new()
.with_connection_string("redis://localhost:6379".to_string())
.with_default_ttl(7200);
assert_eq!(l2.connection_string, "redis://localhost:6379");
assert_eq!(l2.default_ttl, 7200);
}
#[test]
fn test_two_level_layer_config() {
let two_level = TwoLevelLayerConfig::new()
.with_enable_batch_write(true)
.with_batch_size(200);
assert!(two_level.enable_batch_write);
assert_eq!(two_level.batch_size, 200);
}
}