use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use tracing::{debug, info, warn};
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
use std::time::SystemTime;
use std::num::NonZeroUsize;
#[derive(Debug, Clone)]
pub struct CacheEntry {
pub module: Arc<Module>,
pub access_count: u64,
pub last_access: SystemTime,
pub created_at: SystemTime,
pub size_bytes: u64,
pub ttl: Option<Duration>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheStatistics {
pub total_entries: usize,
pub hits: u64,
pub misses: u64,
pub evictions: u64,
pub hit_rate: f64,
pub avg_access_time_ms: f64,
pub total_size_bytes: u64,
}
#[derive(Debug, Clone)]
pub enum CacheStrategy {
LRU, LFU, TTL, Adaptive, }
#[derive(Debug, Clone)]
pub struct CacheConfig {
pub max_size: usize,
pub max_memory_mb: u64,
pub default_ttl: Option<Duration>,
pub strategy: CacheStrategy,
pub preload_enabled: bool,
}
pub struct WasmCacheManager {
cache: Arc<RwLock<LruCache<String, CacheEntry>>>,
access_patterns: Arc<RwLock<HashMap<String, AccessPattern>>>,
config: CacheConfig,
statistics: Arc<RwLock<CacheStatistics>>,
}
#[derive(Debug, Clone)]
pub struct AccessPattern {
pub access_count: u64,
pub avg_interval: Duration,
pub last_access: SystemTime,
}
impl WasmCacheManager {
pub fn new(config: CacheConfig) -> Result<Self> {
info!("🚀 初始化 WASM 缓存管理器 (策略: {:?}, 最大大小: {}, 最大内存: {}MB)",
config.strategy, config.max_size, config.max_memory_mb);
let cache: _ = Arc::new(Mutex::new(LruCache::new(NonZero::new(config.max_size).unwrap_or_else(|| NonZero::new(100).unwrap()))));
let manager: _ = Self {
cache,
access_patterns: Arc::new(Mutex::new(HashMap::new())),
config,
statistics: Arc::new(Mutex::new(CacheStatistics {
total_entries: 0,
hits: 0,
misses: 0,
evictions: 0,
hit_rate: 0.0,
avg_access_time_ms: 0.0,
total_size_bytes: 0,
}))
};
info!("✅ 缓存管理器初始化完成");
Ok(manager)
}
pub async fn get(&self, name: &str) -> Result<Option<Arc<Module>>> {
let start_time: _ = std::time::Instant::now();
let mut cache = self.cache.write().await;
if let Some(entry) = cache.get(name) {
if let Some(ttl) = entry.ttl {
let now: _ = SystemTime::now();
if now.duration_since(entry.created_at).unwrap_or_default() > ttl {
debug!("⏰ 缓存条目过期: {}", name);
cache.pop(name);
self.record_miss().await;
return Ok(None);
}
}
self.update_access_pattern(name, &entry).await;
self.record_hit(start_time).await;
debug!("✅ 缓存命中: {} (访问时间: {:.2}ms)", name,
start_time.elapsed().as_secs_f64() * 1000.0);
return Ok(Some(Arc::clone(&entry.module)));
}
self.record_miss().await;
debug!("❌ 缓存未命中: {}", name);
Ok(None)
}
pub async fn put(&self, name: String, module: Arc<Module>) -> Result<()> {
let start_time: _ = std::time::Instant::now();
let entry: _ = CacheEntry {
module: Arc::clone(module),
access_count: 1,
last_access: SystemTime::now(),
created_at: SystemTime::now(),
size_bytes: self.estimate_module_size(&module),
ttl: self.config.default_ttl,
};
let entry_size: _ = entry.size_bytes;
let mut cache = self.cache.write().await;
if !self.check_memory_limit(&cache, &entry).await {
self.evict_if_needed(&mut cache).await?;
}
cache.put(name.clone(), entry);
self.update_statistics().await;
debug!("📦 缓存模块: {} (耗时: {:.2}ms, 大小: {} bytes)",
name, start_time.elapsed().as_secs_f64() * 1000.0,
entry_size);
Ok(())
}
pub async fn preload(&self, modules: Vec<(String, Arc<Module>)>) -> Result<()> {
if !self.config.preload_enabled {
warn!("⚠️ 预加载功能未启用");
return Ok(());
}
info!("🔥 预加载 {} 个模块", modules.len());
let start_time: _ = std::time::Instant::now();
for (name, module) in modules {
if self.get(&name).await?.is_none() {
self.put(name, module).await?;
}
}
let preload_time: _ = start_time.elapsed().as_secs_f64() * 1000.0;
info!("✅ 预加载完成 (耗时: {:.2}ms)", preload_time);
Ok(())
}
pub async fn smart_prewarm(&self, usage_history: &HashMap<String, usize>) -> Result<()> {
info!("🧠 开始智能预热 (基于 {} 个模块的使用历史)", usage_history.len());
let start_time: _ = std::time::Instant::now();
let mut sorted_modules: Vec<_> = usage_history.iter().collect();
sorted_modules.sort_by(|a, b| b.1.cmp(a.1));
let prewarm_count: _ = (sorted_modules.len() * 20 / 100).max(1);
let hot_modules: _ = &sorted_modules[..prewarm_count];
info!("🔥 预热前 {} 个热门模块", prewarm_count);
for (name, count) in hot_modules {
debug!("🔥 预热模块: {} (使用次数: {})", name, count);
}
let prewarm_time: _ = start_time.elapsed().as_secs_f64() * 1000.0;
info!("✅ 智能预热完成 (耗时: {:.2}ms)", prewarm_time);
Ok(())
}
pub async fn cleanup_expired(&self) -> Result<usize> {
let mut cache = self.cache.write().await;
let now: _ = SystemTime::now();
let mut expired_count = 0;
let keys_to_remove: Vec<String> = cache
.iter()
.filter_map(|(name, entry)| {
if let Some(ttl) = entry.ttl {
if now.duration_since(entry.created_at).unwrap_or_default() > ttl {
Some(name.clone())
} else {
None
}
} else {
None
}
})
.collect();
for key in keys_to_remove {
if cache.pop(&key).is_some() {
expired_count += 1;
}
}
if expired_count > 0 {
info!("🧹 清理了 {} 个过期缓存条目", expired_count);
}
self.update_statistics().await;
Ok(expired_count)
}
pub async fn get_statistics(&self) -> CacheStatistics {
let stats: _ = self.statistics.read().await;
stats.clone()
}
pub async fn get_cache_contents(&self) -> Vec<(String, CacheEntry)> {
let cache: _ = self.cache.read().await;
cache.iter().map(|(name, entry)| (name.clone(), entry.clone())).collect()
}
async fn record_hit(&self, start_time: std::time::Instant) {
let mut stats = self.statistics.write().await;
stats.hits += 1;
let access_time: _ = start_time.elapsed().as_secs_f64() * 1000.0;
let total_hits: _ = stats.hits as f64;
stats.avg_access_time_ms = (stats.avg_access_time_ms * (total_hits - 1.0) + access_time) / total_hits;
if stats.hits + stats.misses > 0 {
stats.hit_rate = stats.hits as f64 / (stats.hits + stats.misses) as f64 * 100.0;
}
}
async fn record_miss(&self) {
let mut stats = self.statistics.write().await;
stats.misses += 1;
if stats.hits + stats.misses > 0 {
stats.hit_rate = stats.hits as f64 / (stats.hits + stats.misses) as f64 * 100.0;
}
}
async fn update_access_pattern(&self, name: &str, entry: &CacheEntry) {
let mut patterns = self.access_patterns.write().await;
if let Some(pattern) = patterns.get_mut(name) {
pattern.access_count += 1;
pattern.avg_interval = entry.last_access.duration_since(pattern.last_access)
.unwrap_or_default();
pattern.last_access = entry.last_access;
} else {
patterns.insert(name.to_string(), AccessPattern {
access_count: 1,
avg_interval: Duration::from_secs(0),
last_access: entry.last_access,
});
}
}
async fn check_memory_limit(&self, cache: &LruCache<String, CacheEntry>, entry: &CacheEntry) -> bool {
let total_size: u64 = cache.iter().map(|(_, e)| e.size_bytes).sum();
total_size + entry.size_bytes <= self.config.max_memory_mb * 1024 * 1024
}
fn find_lfu_entry(cache: &LruCache<String, CacheEntry>) -> Option<(String, &CacheEntry)> {
cache.iter()
.min_by_key(|(_, entry)| entry.access_count)
.map(|(name, entry)| (name.clone(), entry))
}
async fn evict_if_needed(&self, cache: &mut LruCache<String, CacheEntry>) -> Result<()> {
match &self.config.strategy {
CacheStrategy::LRU => {
}
CacheStrategy::LFU => {
if let Some((lfu_key, _)) = Self::find_lfu_entry(cache) {
if let Some(evicted) = cache.pop(&lfu_key) {
let mut stats = self.statistics.write().await;
stats.evictions += 1;
info!("🗑️ LFU 淘汰条目: {} (访问次数: {})", lfu_key, evicted.access_count);
}
}
}
CacheStrategy::TTL => {
self.cleanup_expired().await?;
}
CacheStrategy::Adaptive => {
let patterns = self.access_patterns.read().await;
if let Some((lfu_key, _)) = Self::find_lfu_entry(cache) {
let should_evict = patterns.get(&lfu_key)
.map(|p| p.access_count < 3 && p.avg_interval.as_secs() > 300)
.unwrap_or(false);
if should_evict {
if let Some(evicted) = cache.pop(&lfu_key) {
let mut stats = self.statistics.write().await;
stats.evictions += 1;
info!("🧠 自适应淘汰: {} (访问次数: {}, 间隔: {:?})",
lfu_key, evicted.access_count,
patterns.get(&lfu_key).map(|p| p.avg_interval).unwrap_or_default());
}
}
}
}
}
Ok(())
}
async fn update_statistics(&self) {
let mut stats = self.statistics.write().await;
let cache: _ = self.cache.read().await;
stats.total_entries = cache.len();
stats.total_size_bytes = cache.iter().map(|(_, e)| e.size_bytes).sum();
}
fn estimate_module_size(&self, module: &Module) -> u64 {
1024 * 1024 }
}
impl Default for WasmCacheManager {
fn default() -> Self {
let config: _ = CacheConfig {
max_size: 1000,
max_memory_mb: 512,
default_ttl: Some(Duration::from_secs(3600)), strategy: CacheStrategy::Adaptive,
preload_enabled: true,
};
Self::new(config).expect("初始化 WasmCacheManager 失败")
}
}