rrag/caching/
mod.rs

1//! # Intelligent Caching Layer
2//!
3//! Enterprise-grade multi-level caching system designed specifically for RAG applications
4//! with semantic awareness, intelligent eviction policies, and advanced performance
5//! optimization features.
6//!
7//! This module provides a comprehensive caching solution that understands the unique
8//! characteristics of RAG workloads, including query similarity, embedding reuse,
9//! semantic relationships, and result patterns. It offers multiple cache layers
10//! working together to minimize latency and computational overhead.
11//!
12//! ## Key Features
13//!
14//! - **Multi-Layer Architecture**: Query, embedding, semantic, and result caches
15//! - **Semantic Awareness**: Understanding query similarity and content relationships
16//! - **Intelligent Eviction**: Multiple policies (LRU, LFU, TTL, ARC, Semantic-aware)
17//! - **Persistence Support**: Durable caching across system restarts
18//! - **Performance Monitoring**: Comprehensive metrics and analytics
19//! - **Memory Management**: Automatic cleanup and pressure-based eviction
20//! - **Async Operations**: Non-blocking cache operations for high throughput
21//!
22//! ## Architecture
23//!
24//! The caching system consists of four specialized cache layers:
25//!
26//! 1. **Query Cache**: Caches complete query-response pairs with similarity matching
27//! 2. **Embedding Cache**: Reuses expensive embedding computations
28//! 3. **Semantic Cache**: Groups semantically similar queries for broader cache hits
29//! 4. **Result Cache**: Caches search results for parameter combinations
30//!
31//! ## Examples
32//!
33//! ### Basic Cache Setup
34//! ```rust
35//! use rrag::caching::{CacheService, CacheConfig};
36//!
37//! # async fn example() -> rrag::RragResult<()> {
38//! let cache_config = CacheConfig::default()
39//!     .with_query_cache(true)
40//!     .with_embedding_cache(true)
41//!     .with_semantic_cache(true);
42//!
43//! let mut cache = CacheService::new(cache_config)?;
44//!
45//! // Cache will automatically optimize based on your RAG workload patterns
46//! println!("Cache initialized with {} layers", 4);
47//! # Ok(())
48//! # }
49//! ```
50//!
51//! ### Query Result Caching
52//! ```rust
53//! use rrag::caching::{QueryCacheEntry, CachedSearchResult};
54//!
55//! # async fn example() -> rrag::RragResult<()> {
56//! # let mut cache = rrag::caching::CacheService::new(rrag::caching::CacheConfig::default())?;
57//! let query = "What is machine learning?";
58//!
59//! // Check cache first
60//! if let Some(cached_entry) = cache.get_query_results(query).await {
61//!     println!("Cache hit! Retrieved {} results", cached_entry.results.len());
62//!     return Ok(());
63//! }
64//!
65//! // If not cached, perform search and cache results
66//! let search_results = vec![
67//!     CachedSearchResult {
68//!         document_id: "doc_1".to_string(),
69//!         content: "Machine learning is a subset of AI...".to_string(),
70//!         score: 0.95,
71//!         rank: 1,
72//!         metadata: std::collections::HashMap::new(),
73//!     }
74//! ];
75//!
76//! let cache_entry = QueryCacheEntry {
77//!     query: query.to_string(),
78//!     embedding_hash: "hash123".to_string(),
79//!     results: search_results,
80//!     generated_answer: Some("ML is a field of AI...".to_string()),
81//!     metadata: rrag::caching::CacheEntryMetadata::new(),
82//! };
83//!
84//! cache.cache_query_results(query.to_string(), cache_entry).await?;
85//! # Ok(())
86//! # }
87//! ```
88//!
89//! ### Embedding Caching for Performance
90//! ```rust
91//! # async fn example() -> rrag::RragResult<()> {
92//! # let mut cache = rrag::caching::CacheService::new(rrag::caching::CacheConfig::default())?;
93//! let text = "Advanced machine learning techniques";
94//! let model = "sentence-transformers/all-MiniLM-L6-v2";
95//!
96//! // Check if embedding is already computed
97//! if let Some(cached_embedding) = cache.get_embedding(text, model).await {
98//!     println!("Using cached embedding of dimension {}", cached_embedding.len());
99//! } else {
100//!     // Compute embedding (expensive operation)
101//!     let embedding = compute_embedding(text, model).await?;
102//!     
103//!     // Cache for future use
104//!     cache.cache_embedding(
105//!         text.to_string(),
106//!         model.to_string(),
107//!         embedding
108//!     ).await?;
109//!     
110//!     println!("Computed and cached new embedding");
111//! }
112//!
113//! # async fn compute_embedding(text: &str, model: &str) -> rrag::RragResult<Vec<f32>> {
114//! #     Ok(vec![0.1, 0.2, 0.3]) // Mock embedding
115//! # }
116//! # Ok(())
117//! # }
118//! ```
119//!
120//! ### Semantic Similarity Caching
121//! ```rust
122//! use rrag::caching::{SemanticCacheEntry, SimilarEntry};
123//!
124//! # async fn example() -> rrag::RragResult<()> {
125//! # let mut cache = rrag::caching::CacheService::new(rrag::caching::CacheConfig::default())?;
126//! let similar_queries = [
127//!     "What is artificial intelligence?",
128//!     "Explain AI concepts",
129//!     "Define artificial intelligence",
130//! ];
131//!
132//! // Check for semantically similar cached results
133//! for query in &similar_queries {
134//!     if let Some(semantic_entry) = cache.get_semantic_results(query).await {
135//!         println!("Found semantic match for: {}", query);
136//!         println!("Representative: {}", semantic_entry.representative);
137//!         println!("Similar entries: {}", semantic_entry.similar_entries.len());
138//!         return Ok(());
139//!     }
140//! }
141//!
142//! // Create semantic cache entry for related queries
143//! let semantic_entry = SemanticCacheEntry {
144//!     representative: "What is artificial intelligence?".to_string(),
145//!     cluster_id: Some(1),
146//!     similar_entries: vec![
147//!         SimilarEntry {
148//!             text: "Explain AI concepts".to_string(),
149//!             similarity: 0.92,
150//!             added_at: std::time::SystemTime::now(),
151//!         },
152//!         SimilarEntry {
153//!             text: "Define artificial intelligence".to_string(),
154//!             similarity: 0.89,
155//!             added_at: std::time::SystemTime::now(),
156//!         },
157//!     ],
158//!     results: vec![], // Shared results for all similar queries
159//!     metadata: rrag::caching::CacheEntryMetadata::new(),
160//! };
161//!
162//! cache.cache_semantic_results(
163//!     "ai_concepts_cluster".to_string(),
164//!     semantic_entry
165//! ).await?;
166//! # Ok(())
167//! # }
168//! ```
169//!
170//! ### Advanced Cache Configuration
171//! ```rust
172//! use rrag::caching::{
173//!     CacheConfig, QueryCacheConfig, EmbeddingCacheConfig,
174//!     EvictionPolicy, PersistenceConfig, PersistenceFormat
175//! };
176//! use std::time::Duration;
177//!
178//! # async fn example() -> rrag::RragResult<()> {
179//! let advanced_config = CacheConfig {
180//!     enabled: true,
181//!     query_cache: QueryCacheConfig {
182//!         enabled: true,
183//!         max_size: 5000,
184//!         ttl: Duration::from_secs(7200), // 2 hours
185//!         eviction_policy: EvictionPolicy::SemanticAware,
186//!         similarity_threshold: 0.92,
187//!     },
188//!     embedding_cache: EmbeddingCacheConfig {
189//!         enabled: true,
190//!         max_size: 50000,
191//!         ttl: Duration::from_secs(86400), // 24 hours
192//!         eviction_policy: EvictionPolicy::LFU,
193//!         compression_enabled: true,
194//!     },
195//!     persistence: PersistenceConfig {
196//!         enabled: true,
197//!         storage_path: "/data/rag_cache".to_string(),
198//!         auto_save_interval: Duration::from_secs(300),
199//!         format: PersistenceFormat::MessagePack,
200//!     },
201//!     ..Default::default()
202//! };
203//!
204//! let cache = CacheService::new(advanced_config)?;
205//! println!("Advanced cache configured with persistence and compression");
206//! # Ok(())
207//! # }
208//! ```
209//!
210//! ### Cache Performance Monitoring
211//! ```rust
212//! # async fn example() -> rrag::RragResult<()> {
213//! # let mut cache = rrag::caching::CacheService::new(rrag::caching::CacheConfig::default())?;
214//! // Get comprehensive cache metrics
215//! let metrics = cache.get_metrics();
216//!
217//! println!("📊 Cache Performance Report");
218//! println!("Query Cache: {:.1}% hit rate, {} entries",
219//!          metrics.query_cache.hit_rate * 100.0,
220//!          metrics.query_cache.total_entries);
221//!
222//! println!("Embedding Cache: {:.1}% hit rate, {:.1}MB memory",
223//!          metrics.embedding_cache.hit_rate * 100.0,
224//!          metrics.embedding_cache.memory_usage as f32 / 1024.0 / 1024.0);
225//!
226//! println!("Semantic Cache: {:.1}% hit rate, {} evictions",
227//!          metrics.semantic_cache.hit_rate * 100.0,
228//!          metrics.semantic_cache.evictions);
229//!
230//! println!("Overall Efficiency: {:.1}%, Time Saved: {:.1}ms",
231//!          metrics.overall.efficiency_score * 100.0,
232//!          metrics.overall.time_saved_ms);
233//!
234//! // Performance optimization based on metrics
235//! if metrics.overall.memory_pressure > 0.8 {
236//!     println!("⚠️  High memory pressure detected, triggering cleanup");
237//!     cache.maintenance().await?;
238//! }
239//! # Ok(())
240//! # }
241//! ```
242//!
243//! ## Cache Eviction Policies
244//!
245//! ### LRU (Least Recently Used)
246//! Best for: General-purpose caching with temporal locality
247//! - Evicts items that haven't been accessed recently
248//! - Good memory efficiency
249//! - Simple and fast
250//!
251//! ### LFU (Least Frequently Used)
252//! Best for: Embedding caches where popular items should stay
253//! - Evicts items with lowest access frequency
254//! - Excellent for reusable computations
255//! - Handles long-term access patterns
256//!
257//! ### TTL (Time-To-Live)
258//! Best for: Fresh data requirements
259//! - Evicts items after fixed time period
260//! - Ensures data freshness
261//! - Predictable memory usage
262//!
263//! ### Semantic-Aware
264//! Best for: RAG-specific query patterns
265//! - Considers semantic similarity in eviction decisions
266//! - Maintains representative queries from clusters
267//! - Optimizes for query pattern diversity
268//!
269//! ## Performance Optimization Tips
270//!
271//! 1. **Tune Cache Sizes**: Monitor hit rates and adjust max_size accordingly
272//! 2. **Enable Compression**: For embedding caches with large vectors
273//! 3. **Use Persistence**: For frequently reused embeddings across sessions
274//! 4. **Semantic Clustering**: Enable for diverse query workloads
275//! 5. **Async Operations**: Enable for high-throughput applications
276//! 6. **Memory Monitoring**: Set appropriate pressure thresholds
277//!
278//! ## Integration with RAG Systems
279//!
280//! ```rust
281//! use rrag::{RragSystemBuilder, caching::CacheConfig};
282//!
283//! # async fn example() -> rrag::RragResult<()> {
284//! let rag_system = RragSystemBuilder::new()
285//!     .with_caching(
286//!         CacheConfig::production()
287//!             .with_semantic_awareness(true)
288//!             .with_persistence(true)
289//!             .with_intelligent_eviction(true)
290//!     )
291//!     .build()
292//!     .await?;
293//!
294//! // Cache automatically optimizes based on your query patterns
295//! let results = rag_system.search("machine learning applications", Some(10)).await?;
296//! // Subsequent similar queries will benefit from semantic caching
297//! # Ok(())
298//! # }
299//! ```
300
301pub mod cache_core;
302pub mod embedding_cache;
303pub mod metrics;
304pub mod persistence;
305pub mod policies;
306pub mod query_cache;
307pub mod result_cache;
308pub mod semantic_cache;
309
310use crate::RragResult;
311use serde::{Deserialize, Serialize};
312use std::collections::HashMap;
313use std::hash::{Hash, Hasher};
314use std::time::{Duration, SystemTime};
315
316/// Main caching service orchestrating multiple cache layers
317pub struct CacheService {
318    /// Query result cache
319    query_cache: Box<dyn Cache<String, QueryCacheEntry>>,
320
321    /// Embedding cache for reusing computations
322    embedding_cache: Box<dyn Cache<String, EmbeddingCacheEntry>>,
323
324    /// Semantic similarity cache
325    semantic_cache: Box<dyn Cache<String, SemanticCacheEntry>>,
326
327    /// Document retrieval cache
328    result_cache: Box<dyn Cache<String, ResultCacheEntry>>,
329
330    /// Cache configuration
331    config: CacheConfig,
332
333    /// Performance metrics
334    metrics: CacheMetrics,
335}
336
337/// Global cache configuration
338#[derive(Debug, Clone)]
339pub struct CacheConfig {
340    /// Enable/disable caching globally
341    pub enabled: bool,
342
343    /// Query cache configuration
344    pub query_cache: QueryCacheConfig,
345
346    /// Embedding cache configuration
347    pub embedding_cache: EmbeddingCacheConfig,
348
349    /// Semantic cache configuration
350    pub semantic_cache: SemanticCacheConfig,
351
352    /// Result cache configuration
353    pub result_cache: ResultCacheConfig,
354
355    /// Persistence configuration
356    pub persistence: PersistenceConfig,
357
358    /// Performance tuning
359    pub performance: PerformanceConfig,
360}
361
362/// Query cache configuration
363#[derive(Debug, Clone)]
364pub struct QueryCacheConfig {
365    pub enabled: bool,
366    pub max_size: usize,
367    pub ttl: Duration,
368    pub eviction_policy: EvictionPolicy,
369    pub similarity_threshold: f32,
370}
371
372/// Embedding cache configuration
373#[derive(Debug, Clone)]
374pub struct EmbeddingCacheConfig {
375    pub enabled: bool,
376    pub max_size: usize,
377    pub ttl: Duration,
378    pub eviction_policy: EvictionPolicy,
379    pub compression_enabled: bool,
380}
381
382/// Semantic cache configuration
383#[derive(Debug, Clone)]
384pub struct SemanticCacheConfig {
385    pub enabled: bool,
386    pub max_size: usize,
387    pub ttl: Duration,
388    pub similarity_threshold: f32,
389    pub clustering_enabled: bool,
390    pub max_clusters: usize,
391}
392
393/// Result cache configuration
394#[derive(Debug, Clone)]
395pub struct ResultCacheConfig {
396    pub enabled: bool,
397    pub max_size: usize,
398    pub ttl: Duration,
399    pub eviction_policy: EvictionPolicy,
400    pub compress_large_results: bool,
401}
402
403/// Persistence configuration
404#[derive(Debug, Clone)]
405pub struct PersistenceConfig {
406    pub enabled: bool,
407    pub storage_path: String,
408    pub auto_save_interval: Duration,
409    pub format: PersistenceFormat,
410}
411
412/// Performance configuration
413#[derive(Debug, Clone)]
414pub struct PerformanceConfig {
415    pub async_writes: bool,
416    pub batch_operations: bool,
417    pub background_cleanup: bool,
418    pub memory_pressure_threshold: f32,
419}
420
421/// Cache eviction policies
422#[derive(Debug, Clone, Copy)]
423pub enum EvictionPolicy {
424    /// Least Recently Used
425    LRU,
426    /// Least Frequently Used
427    LFU,
428    /// Time-To-Live based
429    TTL,
430    /// Adaptive Replacement Cache
431    ARC,
432    /// Custom semantic-aware policy
433    SemanticAware,
434}
435
436/// Persistence formats
437#[derive(Debug, Clone)]
438pub enum PersistenceFormat {
439    Binary,
440    Json,
441    MessagePack,
442}
443
444/// Generic cache trait
445pub trait Cache<K, V>: Send + Sync
446where
447    K: Hash + Eq + Clone + Send + Sync + 'static,
448    V: Clone + Send + Sync + 'static,
449{
450    /// Get value from cache
451    fn get(&self, key: &K) -> Option<V>;
452
453    /// Put value into cache
454    fn put(&mut self, key: K, value: V) -> RragResult<()>;
455
456    /// Remove value from cache
457    fn remove(&mut self, key: &K) -> Option<V>;
458
459    /// Check if key exists
460    fn contains(&self, key: &K) -> bool;
461
462    /// Clear all entries
463    fn clear(&mut self);
464
465    /// Get cache size
466    fn size(&self) -> usize;
467
468    /// Get cache statistics
469    fn stats(&self) -> CacheStats;
470}
471
472/// Cache entry metadata
473#[derive(Debug, Clone, Serialize, Deserialize)]
474pub struct CacheEntryMetadata {
475    /// Creation timestamp
476    pub created_at: SystemTime,
477
478    /// Last access timestamp
479    pub last_accessed: SystemTime,
480
481    /// Access count
482    pub access_count: u64,
483
484    /// Entry size in bytes
485    pub size_bytes: usize,
486
487    /// Time-to-live
488    pub ttl: Option<Duration>,
489
490    /// Custom metadata
491    pub custom: HashMap<String, String>,
492}
493
494/// Query cache entry
495#[derive(Debug, Clone, Serialize, Deserialize)]
496pub struct QueryCacheEntry {
497    /// Original query
498    pub query: String,
499
500    /// Query embedding hash
501    pub embedding_hash: String,
502
503    /// Cached results
504    pub results: Vec<CachedSearchResult>,
505
506    /// Generation result if any
507    pub generated_answer: Option<String>,
508
509    /// Metadata
510    pub metadata: CacheEntryMetadata,
511}
512
513/// Embedding cache entry
514#[derive(Debug, Clone, Serialize, Deserialize)]
515pub struct EmbeddingCacheEntry {
516    /// Input text
517    pub text: String,
518
519    /// Text hash for verification
520    pub text_hash: String,
521
522    /// Computed embedding
523    pub embedding: Vec<f32>,
524
525    /// Model used for embedding
526    pub model: String,
527
528    /// Metadata
529    pub metadata: CacheEntryMetadata,
530}
531
532/// Semantic cache entry
533#[derive(Debug, Clone, Serialize, Deserialize)]
534pub struct SemanticCacheEntry {
535    /// Representative query/text
536    pub representative: String,
537
538    /// Cluster ID if clustering enabled
539    pub cluster_id: Option<usize>,
540
541    /// Similar queries/texts
542    pub similar_entries: Vec<SimilarEntry>,
543
544    /// Cached semantic results
545    pub results: Vec<CachedSearchResult>,
546
547    /// Metadata
548    pub metadata: CacheEntryMetadata,
549}
550
551/// Result cache entry
552#[derive(Debug, Clone, Serialize, Deserialize)]
553pub struct ResultCacheEntry {
554    /// Search parameters hash
555    pub params_hash: String,
556
557    /// Cached search results
558    pub results: Vec<CachedSearchResult>,
559
560    /// Result metadata
561    pub result_metadata: HashMap<String, String>,
562
563    /// Metadata
564    pub metadata: CacheEntryMetadata,
565}
566
567/// Similar entry for semantic cache
568#[derive(Debug, Clone, Serialize, Deserialize)]
569pub struct SimilarEntry {
570    /// Similar text
571    pub text: String,
572
573    /// Similarity score
574    pub similarity: f32,
575
576    /// When added
577    pub added_at: SystemTime,
578}
579
580/// Cached search result
581#[derive(Debug, Clone, Serialize, Deserialize)]
582pub struct CachedSearchResult {
583    /// Document ID
584    pub document_id: String,
585
586    /// Document content
587    pub content: String,
588
589    /// Relevance score
590    pub score: f32,
591
592    /// Result rank
593    pub rank: usize,
594
595    /// Additional metadata
596    pub metadata: HashMap<String, String>,
597}
598
599/// Cache statistics
600#[derive(Debug, Clone, Serialize, Deserialize)]
601pub struct CacheStats {
602    /// Total number of entries
603    pub total_entries: usize,
604
605    /// Total cache hits
606    pub hits: u64,
607
608    /// Total cache misses
609    pub misses: u64,
610
611    /// Hit rate percentage
612    pub hit_rate: f32,
613
614    /// Total memory usage in bytes
615    pub memory_usage: usize,
616
617    /// Average access time in microseconds
618    pub avg_access_time_us: f32,
619
620    /// Eviction count
621    pub evictions: u64,
622
623    /// Last cleanup time
624    pub last_cleanup: SystemTime,
625}
626
627/// Cache performance metrics
628#[derive(Debug, Clone, Serialize, Deserialize)]
629pub struct CacheMetrics {
630    /// Query cache metrics
631    pub query_cache: CacheStats,
632
633    /// Embedding cache metrics
634    pub embedding_cache: CacheStats,
635
636    /// Semantic cache metrics
637    pub semantic_cache: CacheStats,
638
639    /// Result cache metrics
640    pub result_cache: CacheStats,
641
642    /// Overall performance metrics
643    pub overall: OverallCacheMetrics,
644}
645
646/// Overall cache performance metrics
647#[derive(Debug, Clone, Serialize, Deserialize)]
648pub struct OverallCacheMetrics {
649    /// Total memory saved (bytes)
650    pub memory_saved: usize,
651
652    /// Total time saved (milliseconds)
653    pub time_saved_ms: f32,
654
655    /// Cache efficiency score
656    pub efficiency_score: f32,
657
658    /// Memory pressure level (0.0 to 1.0)
659    pub memory_pressure: f32,
660
661    /// Total operations per second
662    pub ops_per_second: f32,
663}
664
665impl CacheService {
666    /// Create new cache service
667    pub fn new(config: CacheConfig) -> RragResult<Self> {
668        let query_cache = Box::new(query_cache::QueryCache::new(config.query_cache.clone())?);
669
670        let embedding_cache = Box::new(embedding_cache::EmbeddingCache::new(
671            config.embedding_cache.clone(),
672        )?);
673
674        let semantic_cache = Box::new(semantic_cache::SemanticCache::new(
675            config.semantic_cache.clone(),
676        )?);
677
678        let result_cache = Box::new(result_cache::ResultCache::new(config.result_cache.clone())?);
679
680        Ok(Self {
681            query_cache,
682            embedding_cache,
683            semantic_cache,
684            result_cache,
685            config,
686            metrics: CacheMetrics::default(),
687        })
688    }
689
690    /// Get cached query results
691    pub async fn get_query_results(&self, query: &str) -> Option<QueryCacheEntry> {
692        if !self.config.enabled || !self.config.query_cache.enabled {
693            return None;
694        }
695
696        self.query_cache.get(&query.to_string())
697    }
698
699    /// Cache query results
700    pub async fn cache_query_results(
701        &mut self,
702        query: String,
703        entry: QueryCacheEntry,
704    ) -> RragResult<()> {
705        if !self.config.enabled || !self.config.query_cache.enabled {
706            return Ok(());
707        }
708
709        self.query_cache.put(query, entry)
710    }
711
712    /// Get cached embedding
713    pub async fn get_embedding(&self, text: &str, model: &str) -> Option<Vec<f32>> {
714        if !self.config.enabled || !self.config.embedding_cache.enabled {
715            return None;
716        }
717
718        let key = format!("{}:{}", model, text);
719        self.embedding_cache.get(&key).map(|entry| entry.embedding)
720    }
721
722    /// Cache embedding
723    pub async fn cache_embedding(
724        &mut self,
725        text: String,
726        model: String,
727        embedding: Vec<f32>,
728    ) -> RragResult<()> {
729        if !self.config.enabled || !self.config.embedding_cache.enabled {
730            return Ok(());
731        }
732
733        let key = format!("{}:{}", model, text);
734        let entry = EmbeddingCacheEntry {
735            text: text.clone(),
736            text_hash: Self::hash_string(&text),
737            embedding,
738            model,
739            metadata: CacheEntryMetadata::new(),
740        };
741
742        self.embedding_cache.put(key, entry)
743    }
744
745    /// Get semantically similar cached results
746    pub async fn get_semantic_results(&self, query: &str) -> Option<SemanticCacheEntry> {
747        if !self.config.enabled || !self.config.semantic_cache.enabled {
748            return None;
749        }
750
751        self.semantic_cache.get(&query.to_string())
752    }
753
754    /// Cache semantic results
755    pub async fn cache_semantic_results(
756        &mut self,
757        query: String,
758        entry: SemanticCacheEntry,
759    ) -> RragResult<()> {
760        if !self.config.enabled || !self.config.semantic_cache.enabled {
761            return Ok(());
762        }
763
764        self.semantic_cache.put(query, entry)
765    }
766
767    /// Get cache metrics
768    pub fn get_metrics(&self) -> &CacheMetrics {
769        &self.metrics
770    }
771
772    /// Clear all caches
773    pub fn clear_all(&mut self) {
774        self.query_cache.clear();
775        self.embedding_cache.clear();
776        self.semantic_cache.clear();
777        self.result_cache.clear();
778    }
779
780    /// Perform cache maintenance
781    pub async fn maintenance(&mut self) -> RragResult<()> {
782        // Background cleanup, eviction, persistence, etc.
783        Ok(())
784    }
785
786    /// Hash string for cache keys
787    fn hash_string(s: &str) -> String {
788        use std::collections::hash_map::DefaultHasher;
789        let mut hasher = DefaultHasher::new();
790        s.hash(&mut hasher);
791        format!("{:x}", hasher.finish())
792    }
793}
794
795impl CacheEntryMetadata {
796    /// Create new metadata
797    pub fn new() -> Self {
798        let now = SystemTime::now();
799        Self {
800            created_at: now,
801            last_accessed: now,
802            access_count: 0,
803            size_bytes: 0,
804            ttl: None,
805            custom: HashMap::new(),
806        }
807    }
808
809    /// Update access info
810    pub fn accessed(&mut self) {
811        self.last_accessed = SystemTime::now();
812        self.access_count += 1;
813    }
814
815    /// Check if entry has expired
816    pub fn is_expired(&self) -> bool {
817        if let Some(ttl) = self.ttl {
818            if let Ok(elapsed) = self.created_at.elapsed() {
819                return elapsed > ttl;
820            }
821        }
822        false
823    }
824}
825
826impl Default for CacheConfig {
827    fn default() -> Self {
828        Self {
829            enabled: true,
830            query_cache: QueryCacheConfig::default(),
831            embedding_cache: EmbeddingCacheConfig::default(),
832            semantic_cache: SemanticCacheConfig::default(),
833            result_cache: ResultCacheConfig::default(),
834            persistence: PersistenceConfig::default(),
835            performance: PerformanceConfig::default(),
836        }
837    }
838}
839
840impl Default for QueryCacheConfig {
841    fn default() -> Self {
842        Self {
843            enabled: true,
844            max_size: 1000,
845            ttl: Duration::from_secs(3600), // 1 hour
846            eviction_policy: EvictionPolicy::LRU,
847            similarity_threshold: 0.95,
848        }
849    }
850}
851
852impl Default for EmbeddingCacheConfig {
853    fn default() -> Self {
854        Self {
855            enabled: true,
856            max_size: 10000,
857            ttl: Duration::from_secs(86400), // 24 hours
858            eviction_policy: EvictionPolicy::LFU,
859            compression_enabled: true,
860        }
861    }
862}
863
864impl Default for SemanticCacheConfig {
865    fn default() -> Self {
866        Self {
867            enabled: true,
868            max_size: 5000,
869            ttl: Duration::from_secs(7200), // 2 hours
870            similarity_threshold: 0.85,
871            clustering_enabled: true,
872            max_clusters: 100,
873        }
874    }
875}
876
877impl Default for ResultCacheConfig {
878    fn default() -> Self {
879        Self {
880            enabled: true,
881            max_size: 2000,
882            ttl: Duration::from_secs(1800), // 30 minutes
883            eviction_policy: EvictionPolicy::TTL,
884            compress_large_results: true,
885        }
886    }
887}
888
889impl Default for PersistenceConfig {
890    fn default() -> Self {
891        Self {
892            enabled: false,
893            storage_path: "./cache".to_string(),
894            auto_save_interval: Duration::from_secs(300), // 5 minutes
895            format: PersistenceFormat::Binary,
896        }
897    }
898}
899
900impl Default for PerformanceConfig {
901    fn default() -> Self {
902        Self {
903            async_writes: true,
904            batch_operations: true,
905            background_cleanup: true,
906            memory_pressure_threshold: 0.8,
907        }
908    }
909}
910
911impl Default for CacheStats {
912    fn default() -> Self {
913        Self {
914            total_entries: 0,
915            hits: 0,
916            misses: 0,
917            hit_rate: 0.0,
918            memory_usage: 0,
919            avg_access_time_us: 0.0,
920            evictions: 0,
921            last_cleanup: SystemTime::now(),
922        }
923    }
924}
925
926impl Default for CacheMetrics {
927    fn default() -> Self {
928        Self {
929            query_cache: CacheStats::default(),
930            embedding_cache: CacheStats::default(),
931            semantic_cache: CacheStats::default(),
932            result_cache: CacheStats::default(),
933            overall: OverallCacheMetrics::default(),
934        }
935    }
936}
937
938impl Default for OverallCacheMetrics {
939    fn default() -> Self {
940        Self {
941            memory_saved: 0,
942            time_saved_ms: 0.0,
943            efficiency_score: 0.0,
944            memory_pressure: 0.0,
945            ops_per_second: 0.0,
946        }
947    }
948}
949
950#[cfg(test)]
951mod tests {
952    use super::*;
953
954    #[tokio::test]
955    async fn test_cache_service_creation() {
956        let config = CacheConfig::default();
957        let cache_service = CacheService::new(config).unwrap();
958
959        let metrics = cache_service.get_metrics();
960        assert_eq!(metrics.overall.efficiency_score, 0.0);
961    }
962
963    #[test]
964    fn test_cache_entry_metadata() {
965        let mut metadata = CacheEntryMetadata::new();
966        assert_eq!(metadata.access_count, 0);
967
968        metadata.accessed();
969        assert_eq!(metadata.access_count, 1);
970    }
971
972    #[test]
973    fn test_cache_config_defaults() {
974        let config = CacheConfig::default();
975        assert!(config.enabled);
976        assert!(config.query_cache.enabled);
977        assert!(config.embedding_cache.enabled);
978    }
979}