use crate::cache::l2::L2Cache;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::RwLock;
use tracing::{debug, info};
pub struct SmartCacheStrategy {
l2_cache: Arc<L2Cache>,
#[allow(dead_code)]
prefetch_threshold: u64,
compress_threshold: usize,
stats: Arc<RwLock<CacheStats>>,
}
#[derive(Debug, Default, Clone)]
pub struct CacheStats {
pub hits: u64,
pub misses: u64,
pub prefetch_hits: u64,
pub compress_hits: u64,
pub total_requests: u64,
pub hit_rate: f64,
}
impl SmartCacheStrategy {
pub fn new(l2_cache: Arc<L2Cache>, prefetch_threshold: u64, compress_threshold: usize) -> Self {
Self {
l2_cache,
prefetch_threshold,
compress_threshold,
stats: Arc::new(RwLock::new(Default::default())),
}
}
pub async fn should_prefetch(&self, _key: &str, entry_size: usize) -> bool {
let stats = self.stats.read().await;
let total_requests = stats.hits + stats.misses;
if total_requests == 0 {
return false;
}
let hit_rate = stats.hits as f64 / total_requests as f64;
hit_rate > 0.5 && entry_size < 10_000
}
pub async fn should_compress(&self, _key: &str, value: &str, size: usize) -> bool {
size > self.compress_threshold && self.is_compressible(value)
}
fn is_compressible(&self, data: &str) -> bool {
data.len() > 10
}
pub async fn get_with_strategy(&self, key: &str) -> Option<String> {
let start = Instant::now();
if let Some(value) = self.l2_cache.get(key).await {
if self.should_prefetch(key, value.len()).await {
self.trigger_prefetch(key).await;
}
self.update_stats(true, false, false, false).await;
let duration = start.elapsed();
debug!("L2缓存命中,耗时: {:?}", duration);
return Some(value);
}
let value = self.load_from_storage(key).await?;
let compressed = if self.should_compress(key, &value, value.len()).await {
Some(self.compress(&value).await?)
} else {
Some(value)
};
self.update_stats(false, true, false, compressed.is_some())
.await;
if let Some(ref compressed_value) = compressed {
self.l2_cache.set(key, compressed_value, None).await;
}
let duration = start.elapsed();
debug!("缓存未命中,加载耗时: {:?}", duration);
compressed
}
async fn trigger_prefetch(&self, key: &str) {
info!("触发预取: {}", key);
}
async fn load_from_storage(&self, key: &str) -> Option<String> {
debug!("从存储加载数据: {}", key);
None
}
async fn compress(&self, data: &str) -> Option<String> {
if data.len() < 100 {
return None;
}
if !self.is_compressible(data) {
return None;
}
let compressed = data.split_whitespace().collect::<Vec<&str>>().join(" ");
let compression_ratio = compressed.len() as f64 / data.len() as f64;
if compression_ratio < 0.8 {
Some(compressed)
} else {
None
}
}
async fn update_stats(&self, hit: bool, _miss: bool, prefetch: bool, compressed: bool) {
let mut stats = self.stats.write().await;
if hit {
stats.hits += 1;
} else {
stats.misses += 1;
}
if prefetch {
stats.prefetch_hits += 1;
}
if compressed {
stats.compress_hits += 1;
}
stats.total_requests += 1;
stats.hit_rate = stats.hits as f64 / stats.total_requests as f64;
debug!("更新缓存统计: 命中率={:.2}%", stats.hit_rate * 100.0);
}
pub async fn get_stats(&self) -> CacheStats {
self.stats.read().await.clone()
}
pub async fn reset_stats(&self) {
*self.stats.write().await = CacheStats::default();
info!("缓存统计已重置");
}
}