use std::collections::HashMap; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use crate::error::AppError; use crate::models::{DocumentFormat, DocumentTask, TaskStatus}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sled::{ Db, Transactional, Tree, transaction::{TransactionError, TransactionResult}, }; use tokio::sync::RwLock; /// 存储键前缀 const TASK_PREFIX: &str = "task:"; const INDEX_PREFIX: &str = "index:"; const CACHE_PREFIX: &str = "cache:"; const METADATA_PREFIX: &str = "meta:"; /// 索引类型 #[derive(Debug, Clone, Serialize, Deserialize)] pub enum IndexType { ByStatus(TaskStatus), ByFormat(DocumentFormat), ByCreatedTime(u64), // Unix timestamp ByUpdatedTime(u64), } /// 查询过滤器 #[derive(Debug, Clone)] pub struct QueryFilter { pub status: Option, pub format: Option, pub created_after: Option, pub created_before: Option, pub limit: Option, pub offset: Option, } impl Default for QueryFilter { fn default() -> Self { Self { status: None, format: None, created_after: None, created_before: None, limit: Some(100), offset: None, } } } /// 存储配置 #[derive(Debug, Clone)] pub struct StorageConfig { pub cache_ttl: std::time::Duration, pub max_cache_size: usize, pub cleanup_interval: std::time::Duration, pub retention_period: std::time::Duration, pub batch_size: usize, pub enable_compression: bool, pub sync_interval: std::time::Duration, } impl Default for StorageConfig { fn default() -> Self { Self { cache_ttl: std::time::Duration::from_secs(3600), // 1小时 max_cache_size: 10000, cleanup_interval: std::time::Duration::from_secs(3600), // 1小时 retention_period: std::time::Duration::from_secs(30 * 24 * 3600), // 30天 batch_size: 100, enable_compression: true, sync_interval: std::time::Duration::from_secs(60), // 1分钟 } } } /// 存储统计信息 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StorageStats { pub total_tasks: usize, pub total_size_bytes: u64, pub index_count: usize, pub cache_hit_rate: f64, pub cache_size: usize, pub last_cleanup: Option, pub last_sync: Option, pub transaction_count: u64, pub failed_transactions: u64, pub average_query_time_ms: f64, } /// 事务操作类型 #[derive(Debug, Clone)] pub enum TransactionOp { Insert { key: Vec, value: Vec }, Update { key: Vec, value: Vec }, Delete { key: Vec }, IndexUpdate { index_key: Vec, task_id: String }, IndexDelete { index_key: Vec }, } /// 缓存项 #[derive(Debug, Clone, Serialize, Deserialize)] struct CacheItem { data: T, created_at: SystemTime, expires_at: Option, access_count: u64, } /// 数据库存储服务 #[derive(Debug)] pub struct StorageService { db: Arc, tasks_tree: Tree, index_tree: Tree, cache_tree: Tree, metadata_tree: Tree, // 配置 config: StorageConfig, // 内存缓存 memory_cache: Arc>>>, // 统计信息 stats: Arc>, // 事务计数器 transaction_counter: std::sync::atomic::AtomicU64, failed_transaction_counter: std::sync::atomic::AtomicU64, } impl StorageService { /// 创建新的存储服务 pub fn new(db: Arc) -> Result { Self::with_config(db, StorageConfig::default()) } /// 使用自定义配置创建存储服务 pub fn with_config(db: Arc, config: StorageConfig) -> Result { let tasks_tree = db .open_tree("tasks") .map_err(|e| AppError::Database(format!("打开任务树失败: {e}")))?; let index_tree = db .open_tree("indexes") .map_err(|e| AppError::Database(format!("打开索引树失败: {e}")))?; let cache_tree = db .open_tree("cache") .map_err(|e| AppError::Database(format!("打开缓存树失败: {e}")))?; let metadata_tree = db .open_tree("metadata") .map_err(|e| AppError::Database(format!("打开元数据树失败: {e}")))?; let stats = StorageStats { total_tasks: 0, total_size_bytes: 0, index_count: 0, cache_hit_rate: 0.0, cache_size: 0, last_cleanup: None, last_sync: None, transaction_count: 0, failed_transactions: 0, average_query_time_ms: 0.0, }; Ok(Self { db, tasks_tree, index_tree, cache_tree, metadata_tree, config, memory_cache: Arc::new(RwLock::new(HashMap::new())), stats: Arc::new(RwLock::new(stats)), transaction_counter: std::sync::atomic::AtomicU64::new(0), failed_transaction_counter: std::sync::atomic::AtomicU64::new(0), }) } /// 保存任务 pub async fn save_task(&self, task: &DocumentTask) -> Result<(), AppError> { let start_time = std::time::Instant::now(); // 执行事务 let result = self .execute_transaction(|tx_ops| { let task_key = format!("{}{}", TASK_PREFIX, task.id); // 序列化任务数据 let task_data = serde_json::to_vec(task) .map_err(|e| AppError::Database(format!("序列化任务失败: {e}")))?; // 添加主要操作 tx_ops.push(TransactionOp::Insert { key: task_key.into_bytes(), value: task_data, }); // 添加索引操作 self.add_index_operations(task, tx_ops)?; Ok(()) }) .await; match result { Ok(()) => { // 更新内存缓存 self.update_memory_cache(&task.id, task.clone()).await; // 清除相关缓存 self.invalidate_cache_for_task(&task.id).await?; // 更新统计信息 self.update_query_stats(start_time.elapsed()).await; log::debug!("Task saved: {}", task.id); Ok(()) } Err(e) => { self.failed_transaction_counter .fetch_add(1, std::sync::atomic::Ordering::Relaxed); Err(e) } } } /// 执行事务 async fn execute_transaction(&self, mut operation: F) -> Result<(), AppError> where F: FnMut(&mut Vec) -> Result<(), AppError>, { let mut tx_ops = Vec::new(); operation(&mut tx_ops)?; // 执行事务 let result: TransactionResult<(), ()> = (&self.tasks_tree, &self.index_tree).transaction(|(tasks_tree, index_tree)| { for op in &tx_ops { match op { TransactionOp::Insert { key, value } => { tasks_tree.insert(key.as_slice(), value.as_slice())?; } TransactionOp::Update { key, value } => { tasks_tree.insert(key.as_slice(), value.as_slice())?; } TransactionOp::Delete { key } => { tasks_tree.remove(key.as_slice())?; } TransactionOp::IndexUpdate { index_key, task_id } => { index_tree.insert(index_key.as_slice(), task_id.as_bytes())?; } TransactionOp::IndexDelete { index_key } => { index_tree.remove(index_key.as_slice())?; } } } Ok(()) }); match result { Ok(()) => { self.transaction_counter .fetch_add(1, std::sync::atomic::Ordering::Relaxed); Ok(()) } Err(TransactionError::Abort(e)) => Err(AppError::Database(format!("事务中止: {e:?}"))), Err(TransactionError::Storage(e)) => Err(AppError::Database(format!("存储错误: {e}"))), } } /// 获取任务 pub async fn get_task(&self, task_id: &str) -> Result, AppError> { let start_time = std::time::Instant::now(); // 先检查内存缓存 if let Some(cached_task) = self.get_from_memory_cache(task_id).await { self.update_query_stats(start_time.elapsed()).await; return Ok(Some(cached_task)); } // 检查持久化缓存 if let Some(cached_task) = self .get_from_cache::(&format!("task:{task_id}")) .await? { // 更新内存缓存 self.update_memory_cache(task_id, cached_task.clone()).await; self.update_query_stats(start_time.elapsed()).await; return Ok(Some(cached_task)); } let task_key = format!("{TASK_PREFIX}{task_id}"); match self.tasks_tree.get(&task_key) { Ok(Some(data)) => { let task: DocumentTask = serde_json::from_slice(&data) .map_err(|e| AppError::Database(format!("反序列化任务失败: {e}")))?; // 更新缓存 self.update_memory_cache(task_id, task.clone()).await; self.set_cache(&format!("task:{task_id}"), &task, None) .await?; self.update_query_stats(start_time.elapsed()).await; Ok(Some(task)) } Ok(None) => { self.update_query_stats(start_time.elapsed()).await; Ok(None) } Err(e) => Err(AppError::Database(format!("查询任务失败: {e}"))), } } /// 删除任务 pub async fn delete_task(&self, task_id: &str) -> Result { let start_time = std::time::Instant::now(); // 获取任务以便清理索引 let task = self.get_task(task_id).await?; if let Some(task) = task { // 执行删除事务 let result = self .execute_transaction(|tx_ops| { let task_key = format!("{TASK_PREFIX}{task_id}"); // 添加删除操作 tx_ops.push(TransactionOp::Delete { key: task_key.into_bytes(), }); // 添加索引删除操作 self.add_index_delete_operations(&task, tx_ops)?; Ok(()) }) .await; match result { Ok(()) => { // 清除缓存 self.remove_from_memory_cache(task_id).await; self.invalidate_cache_for_task(task_id).await?; self.update_query_stats(start_time.elapsed()).await; log::info!("Task deleted: {task_id}"); Ok(true) } Err(e) => { self.failed_transaction_counter .fetch_add(1, std::sync::atomic::Ordering::Relaxed); Err(e) } } } else { Ok(false) } } /// 批量保存任务 pub async fn save_tasks_batch(&self, tasks: &[DocumentTask]) -> Result { let start_time = std::time::Instant::now(); let mut saved_count = 0; // 分批处理 for chunk in tasks.chunks(self.config.batch_size) { let result = self .execute_transaction(|tx_ops| { for task in chunk { let task_key = format!("{}{}", TASK_PREFIX, task.id); // 序列化任务数据 let task_data = serde_json::to_vec(task) .map_err(|e| AppError::Database(format!("序列化任务失败: {e}")))?; tx_ops.push(TransactionOp::Insert { key: task_key.into_bytes(), value: task_data, }); // 添加索引操作 self.add_index_operations(task, tx_ops)?; } Ok(()) }) .await; match result { Ok(()) => { saved_count += chunk.len(); // 更新内存缓存 for task in chunk { self.update_memory_cache(&task.id, task.clone()).await; } } Err(e) => { log::error!("Batch save failed: {e}"); return Err(e); } } } self.update_query_stats(start_time.elapsed()).await; log::info!("Batch saving completed: {saved_count} tasks"); Ok(saved_count) } /// 内存缓存操作 async fn get_from_memory_cache(&self, task_id: &str) -> Option { let cache = self.memory_cache.read().await; if let Some(cache_item) = cache.get(task_id) { // 检查是否过期 if let Some(expires_at) = cache_item.expires_at { if SystemTime::now() > expires_at { return None; } } Some(cache_item.data.clone()) } else { None } } async fn update_memory_cache(&self, task_id: &str, task: DocumentTask) { let mut cache = self.memory_cache.write().await; // 检查缓存大小限制 if cache.len() >= self.config.max_cache_size { // 简单的LRU:移除最旧的项 if let Some((oldest_key, _)) = cache.iter().min_by_key(|(_, item)| item.created_at) { let oldest_key = oldest_key.clone(); cache.remove(&oldest_key); } } let cache_item = CacheItem { data: task, created_at: SystemTime::now(), expires_at: Some(SystemTime::now() + self.config.cache_ttl), access_count: 1, }; cache.insert(task_id.to_string(), cache_item); } async fn remove_from_memory_cache(&self, task_id: &str) { let mut cache = self.memory_cache.write().await; cache.remove(task_id); } /// 添加索引操作到事务 fn add_index_operations( &self, task: &DocumentTask, tx_ops: &mut Vec, ) -> Result<(), AppError> { let task_id = &task.id; // 仅基于 task_id 的索引键 let task_index_key = format!("{INDEX_PREFIX}task:{task_id}"); tx_ops.push(TransactionOp::IndexUpdate { index_key: task_index_key.into_bytes(), task_id: task_id.clone(), }); Ok(()) } /// 添加索引删除操作到事务 fn add_index_delete_operations( &self, task: &DocumentTask, tx_ops: &mut Vec, ) -> Result<(), AppError> { let task_id = &task.id; // 删除仅基于 task_id 的索引键 let task_index_key = format!("{INDEX_PREFIX}task:{task_id}"); tx_ops.push(TransactionOp::IndexDelete { index_key: task_index_key.into_bytes(), }); Ok(()) } /// 更新查询统计信息 async fn update_query_stats(&self, query_time: std::time::Duration) { let mut stats = self.stats.write().await; // 更新平均查询时间 let query_time_ms = query_time.as_millis() as f64; if stats.average_query_time_ms == 0.0 { stats.average_query_time_ms = query_time_ms; } else { // 简单的移动平均 stats.average_query_time_ms = (stats.average_query_time_ms * 0.9) + (query_time_ms * 0.1); } } /// 查询任务 pub async fn query_tasks(&self, filter: &QueryFilter) -> Result, AppError> { let cache_key = format!("query:{}", self.filter_to_cache_key(filter)); // 检查缓存 if let Some(cached_result) = self.get_from_cache::>(&cache_key).await? { return Ok(cached_result); } let mut results = Vec::new(); let mut count = 0; let offset = filter.offset.unwrap_or(0); let limit = filter.limit.unwrap_or(100); // 遍历所有任务 for result in self.tasks_tree.scan_prefix(TASK_PREFIX.as_bytes()) { let (_, data) = result.map_err(|e| AppError::Database(format!("扫描任务失败: {e}")))?; let task: DocumentTask = serde_json::from_slice(&data) .map_err(|e| AppError::Database(format!("反序列化任务失败: {e}")))?; // 应用过滤器 if self.task_matches_filter(&task, filter) { if count >= offset { results.push(task); if results.len() >= limit { break; } } count += 1; } } // 缓存结果 self.set_cache( &cache_key, &results, Some(std::time::Duration::from_secs(300)), ) .await?; Ok(results) } /// 获取存储统计信息 pub async fn get_stats(&self) -> Result { let cache_key = "storage_stats"; // 检查缓存 if let Some(cached_stats) = self.get_from_cache::(cache_key).await? { return Ok(cached_stats); } let mut total_tasks = 0; let mut total_size_bytes = 0; // 统计任务数量和大小 for result in self.tasks_tree.scan_prefix(TASK_PREFIX.as_bytes()) { let (_, data) = result.map_err(|e| AppError::Database(format!("扫描任务失败: {e}")))?; total_tasks += 1; total_size_bytes += data.len() as u64; } // 统计索引数量 let index_count = self.index_tree.len(); // 获取内存缓存大小 let cache_size = { let cache = self.memory_cache.read().await; cache.len() }; // 计算缓存命中率(简化版本) let cache_hit_rate = 0.85; // 占位值,实际应该基于访问统计 // 获取事务统计 let transaction_count = self .transaction_counter .load(std::sync::atomic::Ordering::Relaxed); let failed_transactions = self .failed_transaction_counter .load(std::sync::atomic::Ordering::Relaxed); // 获取平均查询时间 let average_query_time_ms = { let stats = self.stats.read().await; stats.average_query_time_ms }; let stats = StorageStats { total_tasks, total_size_bytes, index_count, cache_hit_rate, cache_size, last_cleanup: self.get_last_cleanup_time().await?, last_sync: { let stats = self.stats.read().await; stats.last_sync }, transaction_count, failed_transactions, average_query_time_ms, }; // 缓存统计信息 self.set_cache(cache_key, &stats, Some(std::time::Duration::from_secs(60))) .await?; Ok(stats) } /// 清理过期数据 pub async fn cleanup_expired_data(&self) -> Result { log::info!("Start cleaning expired data"); let mut cleaned_count = 0; let now = SystemTime::now(); // 清理过期任务 let expired_tasks = self.find_expired_tasks(now).await?; if !expired_tasks.is_empty() { // 批量删除过期任务 for chunk in expired_tasks.chunks(self.config.batch_size) { let result = self .execute_transaction(|tx_ops| { for task in chunk { let task_key = format!("{}{}", TASK_PREFIX, task.id); tx_ops.push(TransactionOp::Delete { key: task_key.into_bytes(), }); // 添加索引删除操作 self.add_index_delete_operations(task, tx_ops)?; } Ok(()) }) .await; match result { Ok(()) => { cleaned_count += chunk.len(); // 清理内存缓存 for task in chunk { self.remove_from_memory_cache(&task.id).await; } } Err(e) => { log::error!("Failed to delete expired tasks in batches: {e}"); return Err(e); } } } } // 清理过期缓存 cleaned_count += self.cleanup_expired_cache().await?; // 清理内存缓存 cleaned_count += self.cleanup_memory_cache().await; // 更新清理时间 self.set_last_cleanup_time(now).await?; // 压缩数据库 self.compact_database().await?; log::info!("Cleanup completed, {cleaned_count} records deleted"); Ok(cleaned_count) } /// 查找过期任务 async fn find_expired_tasks(&self, now: SystemTime) -> Result, AppError> { let mut expired_tasks = Vec::new(); for result in self.tasks_tree.scan_prefix(TASK_PREFIX.as_bytes()) { let (_, data) = result.map_err(|e| AppError::Database(format!("扫描任务失败: {e}")))?; let task: DocumentTask = serde_json::from_slice(&data) .map_err(|e| AppError::Database(format!("反序列化任务失败: {e}")))?; // 检查是否过期 let task_created_at = UNIX_EPOCH + std::time::Duration::from_secs(task.created_at.timestamp() as u64); if let Ok(elapsed) = now.duration_since(task_created_at) { if elapsed > self.config.retention_period && task.status.is_terminal() { expired_tasks.push(task); } } } Ok(expired_tasks) } /// 清理内存缓存 async fn cleanup_memory_cache(&self) -> usize { let mut cache = self.memory_cache.write().await; let now = SystemTime::now(); let mut cleaned_count = 0; cache.retain(|_, item| { if let Some(expires_at) = item.expires_at { if now > expires_at { cleaned_count += 1; false } else { true } } else { true } }); cleaned_count } /// 压缩数据库 async fn compact_database(&self) -> Result<(), AppError> { log::info!("Start compressing the database"); // 刷新所有树 self.tasks_tree .flush() .map_err(|e| AppError::Database(format!("刷新任务树失败: {e}")))?; self.index_tree .flush() .map_err(|e| AppError::Database(format!("刷新索引树失败: {e}")))?; self.cache_tree .flush() .map_err(|e| AppError::Database(format!("刷新缓存树失败: {e}")))?; self.metadata_tree .flush() .map_err(|e| AppError::Database(format!("刷新元数据树失败: {e}")))?; // 刷新整个数据库 self.db .flush() .map_err(|e| AppError::Database(format!("刷新数据库失败: {e}")))?; log::info!("Database compression completed"); Ok(()) } /// 启动后台维护任务 pub async fn start_maintenance_tasks(&self) -> Result<(), AppError> { let storage_service = self.clone_for_background(); tokio::spawn(async move { let mut cleanup_interval = tokio::time::interval(storage_service.config.cleanup_interval); let mut sync_interval = tokio::time::interval(storage_service.config.sync_interval); loop { tokio::select! { _ = cleanup_interval.tick() => { if let Err(e) = storage_service.cleanup_expired_data().await { log::error!("Periodic cleanup failed: {e}"); } } _ = sync_interval.tick() => { if let Err(e) = storage_service.sync_to_disk().await { log::error!("Periodic synchronization failed: {e}"); } } } } }); Ok(()) } /// 同步到磁盘 async fn sync_to_disk(&self) -> Result<(), AppError> { self.compact_database().await?; // 更新同步时间 { let mut stats = self.stats.write().await; stats.last_sync = Some(SystemTime::now()); } Ok(()) } /// 为后台任务克隆服务 fn clone_for_background(&self) -> Self { Self { db: Arc::clone(&self.db), tasks_tree: self.tasks_tree.clone(), index_tree: self.index_tree.clone(), cache_tree: self.cache_tree.clone(), metadata_tree: self.metadata_tree.clone(), config: self.config.clone(), memory_cache: Arc::clone(&self.memory_cache), stats: Arc::clone(&self.stats), transaction_counter: std::sync::atomic::AtomicU64::new( self.transaction_counter .load(std::sync::atomic::Ordering::Relaxed), ), failed_transaction_counter: std::sync::atomic::AtomicU64::new( self.failed_transaction_counter .load(std::sync::atomic::Ordering::Relaxed), ), } } /// 备份数据 pub async fn backup_to_path(&self, backup_path: &str) -> Result<(), AppError> { log::info!("Start backing up data to: {backup_path}"); // 创建备份目录 std::fs::create_dir_all(backup_path) .map_err(|e| AppError::File(format!("创建备份目录失败: {e}")))?; // 导出所有任务 let mut tasks = Vec::new(); for result in self.tasks_tree.scan_prefix(TASK_PREFIX.as_bytes()) { let (_, data) = result.map_err(|e| AppError::Database(format!("扫描任务失败: {e}")))?; let task: DocumentTask = serde_json::from_slice(&data) .map_err(|e| AppError::Database(format!("反序列化任务失败: {e}")))?; tasks.push(task); } // 写入备份文件 let backup_file = format!( "{}/tasks_backup_{}.json", backup_path, SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_secs() ); let backup_data = serde_json::to_string_pretty(&tasks) .map_err(|e| AppError::Database(format!("序列化备份数据失败: {e}")))?; std::fs::write(&backup_file, backup_data) .map_err(|e| AppError::File(format!("写入备份文件失败: {e}")))?; log::info!("Backup completed: {} ({} tasks)", backup_file, tasks.len()); Ok(()) } /// 从备份恢复数据 pub async fn restore_from_backup(&self, backup_file: &str) -> Result { log::info!("Restore data from backup: {backup_file}"); let backup_data = std::fs::read_to_string(backup_file) .map_err(|e| AppError::File(format!("读取备份文件失败: {e}")))?; let tasks: Vec = serde_json::from_str(&backup_data) .map_err(|e| AppError::Database(format!("反序列化备份数据失败: {e}")))?; let mut restored_count = 0; for task in tasks { self.save_task(&task).await?; restored_count += 1; } log::info!("Recovery completed: {restored_count} tasks"); Ok(restored_count) } // 私有方法 /// 检查任务是否匹配过滤器 fn task_matches_filter(&self, task: &DocumentTask, filter: &QueryFilter) -> bool { // 状态过滤 if let Some(status) = &filter.status { if &task.status != status { return false; } } // 格式过滤 if let Some(format) = &filter.format { if task.document_format.as_ref() != Some(format) { return false; } } // 创建时间过滤 if let Some(after) = filter.created_after { let after_dt = DateTime::::from(after); if task.created_at < after_dt { return false; } } if let Some(before) = filter.created_before { let before_dt = DateTime::::from(before); if task.created_at > before_dt { return false; } } true } /// 生成过滤器的缓存键 fn filter_to_cache_key(&self, filter: &QueryFilter) -> String { format!( "{}:{}:{}:{}:{}:{}", filter .status .as_ref() .map(|s| s.to_string()) .unwrap_or_else(|| "any".to_string()), filter .format .as_ref() .map(|f| f.to_string()) .unwrap_or_else(|| "any".to_string()), filter .created_after .map(|t| t.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs()) .unwrap_or(0), filter .created_before .map(|t| t.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs()) .unwrap_or(u64::MAX), filter.limit.unwrap_or(100), filter.offset.unwrap_or(0) ) } /// 从缓存获取数据 async fn get_from_cache(&self, key: &str) -> Result, AppError> where T: for<'de> Deserialize<'de>, { let cache_key = format!("{CACHE_PREFIX}{key}"); if let Ok(Some(data)) = self.cache_tree.get(&cache_key) { let cache_item: CacheItem = serde_json::from_slice(&data) .map_err(|e| AppError::Database(format!("反序列化缓存项失败: {e}")))?; // 检查是否过期 if let Some(expires_at) = cache_item.expires_at { if SystemTime::now() > expires_at { // 过期,删除缓存项 self.cache_tree .remove(&cache_key) .map_err(|e| AppError::Database(format!("删除过期缓存失败: {e}")))?; return Ok(None); } } // 更新访问计数(简化版本,不实际更新) Ok(Some(cache_item.data)) } else { Ok(None) } } /// 设置缓存 async fn set_cache( &self, key: &str, data: &T, ttl: Option, ) -> Result<(), AppError> where T: Serialize, { let cache_key = format!("{CACHE_PREFIX}{key}"); let now = SystemTime::now(); let cache_item = CacheItem { data, created_at: now, expires_at: ttl.map(|duration| now + duration), access_count: 1, }; let cache_data = serde_json::to_vec(&cache_item) .map_err(|e| AppError::Database(format!("序列化缓存项失败: {e}")))?; self.cache_tree .insert(&cache_key, cache_data) .map_err(|e| AppError::Database(format!("设置缓存失败: {e}")))?; Ok(()) } /// 清除任务相关缓存 async fn invalidate_cache_for_task(&self, task_id: &str) -> Result<(), AppError> { let patterns = vec![ format!("task:{}", task_id), "query:".to_string(), "storage_stats".to_string(), ]; for pattern in patterns { let cache_key = format!("{CACHE_PREFIX}{pattern}"); if pattern.starts_with("query:") { // 清除所有查询缓存 let prefix = cache_key.as_bytes(); let mut to_remove = Vec::new(); for result in self.cache_tree.scan_prefix(prefix) { let (key, _) = result.map_err(|e| AppError::Database(format!("扫描缓存失败: {e}")))?; to_remove.push(key.to_vec()); } for key in to_remove { self.cache_tree .remove(&key) .map_err(|e| AppError::Database(format!("删除缓存失败: {e}")))?; } } else { self.cache_tree .remove(&cache_key) .map_err(|e| AppError::Database(format!("删除缓存失败: {e}")))?; } } Ok(()) } /// 清理过期缓存 async fn cleanup_expired_cache(&self) -> Result { let mut cleaned_count = 0; let now = SystemTime::now(); let mut to_remove = Vec::new(); for result in self.cache_tree.scan_prefix(CACHE_PREFIX.as_bytes()) { let (key, data) = result.map_err(|e| AppError::Database(format!("扫描缓存失败: {e}")))?; // 尝试解析缓存项(简化版本) if let Ok(cache_item) = serde_json::from_slice::(&data) { if let Some(expires_at_timestamp) = cache_item.get("expires_at").and_then(|v| v.as_u64()) { let expires_at = UNIX_EPOCH + std::time::Duration::from_secs(expires_at_timestamp); if now > expires_at { to_remove.push(key.to_vec()); } } } } for key in to_remove { self.cache_tree .remove(&key) .map_err(|e| AppError::Database(format!("删除过期缓存失败: {e}")))?; cleaned_count += 1; } Ok(cleaned_count) } /// 获取最后清理时间 async fn get_last_cleanup_time(&self) -> Result, AppError> { let key = format!("{}{}", METADATA_PREFIX, "last_cleanup"); if let Ok(Some(data)) = self.metadata_tree.get(&key) { let timestamp: u64 = serde_json::from_slice(&data) .map_err(|e| AppError::Database(format!("反序列化清理时间失败: {e}")))?; Ok(Some(UNIX_EPOCH + std::time::Duration::from_secs(timestamp))) } else { Ok(None) } } /// 设置最后清理时间 async fn set_last_cleanup_time(&self, time: SystemTime) -> Result<(), AppError> { let key = format!("{}{}", METADATA_PREFIX, "last_cleanup"); let timestamp = time .duration_since(UNIX_EPOCH) .unwrap_or_default() .as_secs(); let data = serde_json::to_vec(×tamp) .map_err(|e| AppError::Database(format!("序列化清理时间失败: {e}")))?; self.metadata_tree .insert(&key, data) .map_err(|e| AppError::Database(format!("设置清理时间失败: {e}")))?; Ok(()) } } #[cfg(test)] mod tests { use super::*; use crate::models::SourceType; use tempfile::TempDir; #[tokio::test] async fn test_storage_service_basic() { let app_config = crate::tests::test_helpers::create_real_environment_test_config(); crate::config::init_global_config(app_config).unwrap(); let temp_dir = TempDir::new().unwrap(); let db = Arc::new(sled::open(temp_dir.path()).unwrap()); let storage = StorageService::new(db).unwrap(); // 创建测试任务 let task_id = uuid::Uuid::new_v4().to_string(); let mut task = DocumentTask::new( task_id.clone(), SourceType::Upload, Some("/test/path".to_string()), Some("path.pdf".to_string()), Some(DocumentFormat::PDF), Some("pipeline".to_string()), Some(24), Some(3), ); task.parser_engine = Some(crate::models::ParserEngine::MinerU); task.file_size = Some(1024); task.mime_type = Some("application/pdf".to_string()); // 保存任务 storage.save_task(&task).await.unwrap(); // 获取任务 let retrieved = storage.get_task(&task_id).await.unwrap(); assert!(retrieved.is_some()); assert_eq!(retrieved.unwrap().id, task_id); // 删除任务 let deleted = storage.delete_task(&task_id).await.unwrap(); assert!(deleted); // 确认删除 let not_found = storage.get_task(&task_id).await.unwrap(); assert!(not_found.is_none()); } #[tokio::test] async fn test_transaction_handling() { let app_config = crate::tests::test_helpers::create_real_environment_test_config(); crate::config::init_global_config(app_config).unwrap(); let temp_dir = TempDir::new().unwrap(); let db = Arc::new(sled::open(temp_dir.path()).unwrap()); let storage = StorageService::new(db).unwrap(); // 创建多个任务进行批量保存 let mut tasks = Vec::new(); for i in 0..5 { let mut task = DocumentTask::new( format!("batch_task_{i}"), SourceType::Upload, Some(format!("/test/path_{i}")), Some(format!("path_{i}.pdf")), Some(DocumentFormat::PDF), Some("pipeline".to_string()), Some(24), Some(3), ); task.parser_engine = Some(crate::models::ParserEngine::MinerU); task.file_size = Some(1024); task.mime_type = Some("application/pdf".to_string()); tasks.push(task); } // 批量保存 let saved_count = storage.save_tasks_batch(&tasks).await.unwrap(); assert_eq!(saved_count, 5); // 验证所有任务都已保存 for i in 0..5 { let task_id = format!("batch_task_{i}"); let retrieved = storage.get_task(&task_id).await.unwrap(); assert!(retrieved.is_some()); } } #[tokio::test] async fn test_memory_cache() { let app_config = crate::tests::test_helpers::create_real_environment_test_config(); crate::config::init_global_config(app_config).unwrap(); let temp_dir = TempDir::new().unwrap(); let db = Arc::new(sled::open(temp_dir.path()).unwrap()); let config = StorageConfig { max_cache_size: 2, // 限制缓存大小 ..Default::default() }; let storage = StorageService::with_config(db, config).unwrap(); // 创建测试任务 let task1_id = uuid::Uuid::new_v4().to_string(); let mut task1 = DocumentTask::new( task1_id.clone(), SourceType::Upload, Some("/test/path1".to_string()), Some("path1.pdf".to_string()), Some(DocumentFormat::PDF), Some("pipeline".to_string()), Some(24), Some(3), ); task1.parser_engine = Some(crate::models::ParserEngine::MinerU); task1.file_size = Some(1024); task1.mime_type = Some("application/pdf".to_string()); let task2_id = uuid::Uuid::new_v4().to_string(); let mut task2 = DocumentTask::new( task2_id.clone(), SourceType::Upload, Some("/test/path2".to_string()), Some("path2.pdf".to_string()), Some(DocumentFormat::PDF), Some("pipeline".to_string()), Some(24), Some(3), ); task2.parser_engine = Some(crate::models::ParserEngine::MinerU); task2.file_size = Some(1024); task2.mime_type = Some("application/pdf".to_string()); // 保存任务(会自动缓存) storage.save_task(&task1).await.unwrap(); storage.save_task(&task2).await.unwrap(); // 第一次获取应该从缓存中获取 let retrieved1 = storage.get_task(&task1_id).await.unwrap(); assert!(retrieved1.is_some()); // 检查缓存状态 let cache_size = { let cache = storage.memory_cache.read().await; cache.len() }; assert!(cache_size <= 2); // 不应该超过最大缓存大小 } #[tokio::test] async fn test_cleanup_expired_data() { let app_config = crate::tests::test_helpers::create_real_environment_test_config(); crate::config::init_global_config(app_config).unwrap(); let temp_dir = TempDir::new().unwrap(); let db = Arc::new(sled::open(temp_dir.path()).unwrap()); let config = StorageConfig { retention_period: std::time::Duration::from_secs(1), // 1秒过期 ..Default::default() }; let storage = StorageService::with_config(db, config).unwrap(); // 创建已完成的任务 let task_id = uuid::Uuid::new_v4().to_string(); let mut task = DocumentTask::new( task_id.clone(), SourceType::Upload, Some("/test/path".to_string()), Some("path.pdf".to_string()), Some(DocumentFormat::PDF), Some("pipeline".to_string()), Some(24), Some(3), ); task.parser_engine = Some(crate::models::ParserEngine::MinerU); task.file_size = Some(1024); task.mime_type = Some("application/pdf".to_string()); // 设置为已完成状态 let _ = task.update_status(TaskStatus::new_completed(std::time::Duration::from_secs( 60, ))); storage.save_task(&task).await.unwrap(); // 等待过期 tokio::time::sleep(std::time::Duration::from_secs(2)).await; // 执行清理 let cleaned_count = storage.cleanup_expired_data().await.unwrap(); assert!(cleaned_count > 0); // 验证任务已被删除 let retrieved = storage.get_task(&task_id).await.unwrap(); assert!(retrieved.is_none()); } #[tokio::test] async fn test_storage_stats() { let app_config = crate::tests::test_helpers::create_real_environment_test_config(); crate::config::init_global_config(app_config).unwrap(); let temp_dir = TempDir::new().unwrap(); let db = Arc::new(sled::open(temp_dir.path()).unwrap()); let storage = StorageService::new(db).unwrap(); // 创建一些测试任务 for i in 0..3 { let task_id = uuid::Uuid::new_v4().to_string(); let mut task = DocumentTask::new( task_id, SourceType::Upload, Some(format!("/test/path_{i}")), Some(format!("path_{i}.pdf")), Some(DocumentFormat::PDF), Some("pipeline".to_string()), Some(24), Some(3), ); task.parser_engine = Some(crate::models::ParserEngine::MinerU); task.file_size = Some(1024); task.mime_type = Some("application/pdf".to_string()); storage.save_task(&task).await.unwrap(); } // 获取统计信息 let stats = storage.get_stats().await.unwrap(); assert_eq!(stats.total_tasks, 3); assert!(stats.total_size_bytes > 0); assert!(stats.transaction_count > 0); } }