Skip to main content

oxirs_vec/
advanced_caching.rs

1//! Advanced multi-level caching system for vector embeddings and search results.
2//!
3//! This module is organized as a set of focused sub-modules:
4//!
5//! - [`advanced_caching_eviction`] — `MemoryCache`, `PersistentCache`, eviction policies
6//! - [`advanced_caching_multilevel`] — `MultiLevelCache`, `CacheInvalidator`
7//! - [`advanced_caching_worker`] — `BackgroundCacheWorker`, `CacheWarmer`, `CacheAnalyzer`
8//!
9//! Shared primitive types (`EvictionPolicy`, `CacheConfig`, `CacheEntry`, `CacheKey`,
10//! `CacheStats`) are defined here in the root and re-exported so that all sibling
11//! modules can import them via `use super::*` or specific `use super::{…}` paths.
12
13use crate::Vector;
14use serde::{Deserialize, Serialize};
15use std::collections::HashMap;
16use std::fmt;
17use std::time::{Duration, Instant};
18
19// ---------------------------------------------------------------------------
20// Re-exports from sibling modules (declared as top-level modules in lib.rs)
21// ---------------------------------------------------------------------------
22
23// The three sibling files live flat in src/ and are declared as top-level
24// modules in lib.rs.  We re-export their public types here so that the
25// `advanced_caching::*` public surface is unchanged for callers.
26
27pub use crate::advanced_caching_eviction::{MemoryCache, PersistentCache};
28pub use crate::advanced_caching_multilevel::{
29    CacheInvalidator, InvalidationStats, MultiLevelCache, MultiLevelCacheStats,
30};
31pub use crate::advanced_caching_worker::{
32    BackgroundCacheWorker, CacheAnalysisReport, CacheAnalyzer, CacheWarmer,
33};
34
35// ---------------------------------------------------------------------------
36// Shared primitive types (used by all sub-modules via `use super::*`)
37// ---------------------------------------------------------------------------
38
39/// Cache eviction policy
40#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
41pub enum EvictionPolicy {
42    /// Least Recently Used
43    LRU,
44    /// Least Frequently Used
45    LFU,
46    /// Adaptive Replacement Cache
47    ARC,
48    /// First In, First Out
49    FIFO,
50    /// Time-based expiration only
51    TTL,
52}
53
54/// Cache configuration
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct CacheConfig {
57    /// Maximum number of entries in memory cache
58    pub max_memory_entries: usize,
59    /// Maximum memory usage in bytes
60    pub max_memory_bytes: usize,
61    /// Time-to-live for cache entries
62    pub ttl: Option<Duration>,
63    /// Eviction policy
64    pub eviction_policy: EvictionPolicy,
65    /// Enable persistent cache
66    pub enable_persistent: bool,
67    /// Persistent cache directory
68    pub persistent_cache_dir: Option<std::path::PathBuf>,
69    /// Maximum persistent cache size in bytes
70    pub max_persistent_bytes: usize,
71    /// Enable cache compression
72    pub enable_compression: bool,
73    /// Enable background updates
74    pub enable_background_updates: bool,
75    /// Background update interval
76    pub background_update_interval: Duration,
77}
78
79impl Default for CacheConfig {
80    fn default() -> Self {
81        Self {
82            max_memory_entries: 10_000,
83            max_memory_bytes: 1024 * 1024 * 100,  // 100 MB
84            ttl: Some(Duration::from_secs(3600)), // 1 hour
85            eviction_policy: EvictionPolicy::LRU,
86            enable_persistent: true,
87            persistent_cache_dir: None,
88            max_persistent_bytes: 1024 * 1024 * 1024, // 1 GB
89            enable_compression: true,
90            enable_background_updates: false,
91            background_update_interval: Duration::from_secs(300), // 5 minutes
92        }
93    }
94}
95
96/// Cache entry with metadata
97#[derive(Debug, Clone)]
98pub struct CacheEntry {
99    /// Cached data
100    pub data: Vector,
101    /// Creation timestamp
102    pub created_at: Instant,
103    /// Last access timestamp
104    pub last_accessed: Instant,
105    /// Access count for LFU
106    pub access_count: u64,
107    /// Entry size in bytes
108    pub size_bytes: usize,
109    /// TTL for this specific entry
110    pub ttl: Option<Duration>,
111    /// Metadata tags
112    pub tags: HashMap<String, String>,
113}
114
115impl CacheEntry {
116    pub fn new(data: Vector) -> Self {
117        let now = Instant::now();
118        let size_bytes = data.dimensions * std::mem::size_of::<f32>() + 64;
119
120        Self {
121            data,
122            created_at: now,
123            last_accessed: now,
124            access_count: 1,
125            size_bytes,
126            ttl: None,
127            tags: HashMap::new(),
128        }
129    }
130
131    pub fn with_ttl(mut self, ttl: Duration) -> Self {
132        self.ttl = Some(ttl);
133        self
134    }
135
136    pub fn with_tags(mut self, tags: HashMap<String, String>) -> Self {
137        self.tags = tags;
138        self
139    }
140
141    /// Returns `true` if this entry's TTL has elapsed.
142    pub fn is_expired(&self) -> bool {
143        if let Some(ttl) = self.ttl {
144            self.created_at.elapsed() > ttl
145        } else {
146            false
147        }
148    }
149
150    /// Update access statistics.
151    pub fn touch(&mut self) {
152        self.last_accessed = Instant::now();
153        self.access_count += 1;
154    }
155}
156
157/// Cache key that can be hashed
158#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
159pub struct CacheKey {
160    pub namespace: String,
161    pub key: String,
162    pub variant: Option<String>,
163}
164
165impl CacheKey {
166    pub fn new(namespace: impl Into<String>, key: impl Into<String>) -> Self {
167        Self {
168            namespace: namespace.into(),
169            key: key.into(),
170            variant: None,
171        }
172    }
173
174    pub fn with_variant(mut self, variant: impl Into<String>) -> Self {
175        self.variant = Some(variant.into());
176        self
177    }
178}
179
180impl fmt::Display for CacheKey {
181    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182        if let Some(ref variant) = self.variant {
183            write!(f, "{}:{}:{}", self.namespace, self.key, variant)
184        } else {
185            write!(f, "{}:{}", self.namespace, self.key)
186        }
187    }
188}
189
190/// Cache statistics
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct CacheStats {
193    pub entries: usize,
194    pub memory_bytes: usize,
195    pub max_entries: usize,
196    pub max_memory_bytes: usize,
197    pub hit_ratio: f32,
198}