limiteron 0.1.0

Unified flow control framework for Rust
Documentation
//! Copyright (c) 2026, Kirky.X
//!
//! MIT License
//!
//! 智能缓存策略
//!
//! 实现智能缓存失效、预取和压缩策略以提高性能。

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缓存层
    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 {
        // 简单的启发式压缩检查
        // 可以实现更复杂的压缩算法,如 LZ4、Snappy 等
        data.len() > 10
    }

    /// 增强的缓存获取方法
    ///
    /// 集成智能缓存策略的获取逻辑
    pub async fn get_with_strategy(&self, key: &str) -> Option<String> {
        let start = Instant::now();

        // 首先尝试从 L2 缓存获取
        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;

        // 存储到 L2 缓存
        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> {
        // 这里应该从实际存储(如数据库、Redis等)加载数据
        // 这是一个框架实现,用户需要注入存储
        debug!("从存储加载数据: {}", key);

        // 暂时返回 None,表示未实现
        // 在实际应用中,这里应该:
        // 1. 从 Redis/PostgreSQL 等存储加载数据
        // 2. 处理加载失败的情况
        // 3. 考虑加载超时

        None
    }

    /// 数据压缩
    async fn compress(&self, data: &str) -> Option<String> {
        // 简单的压缩示例:移除重复的空白字符
        // 在实际应用中,应该使用真正的压缩库如 snap、lz4 等

        // 小数据不压缩
        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!("缓存统计已重置");
    }
}