rez_next_cache/
unified_cache.rs1use crate::{CacheError, UnifiedCacheStats};
7use async_trait::async_trait;
8use serde::{Deserialize, Serialize};
9use std::fmt::Debug;
10use std::hash::Hash;
11
12#[async_trait]
18pub trait UnifiedCache<K, V>: Send + Sync + Debug
19where
20 K: Clone + Hash + Eq + Send + Sync + Debug,
21 V: Clone + Send + Sync + Debug,
22{
23 async fn get(&self, key: &K) -> Option<V>;
28
29 async fn put(&self, key: K, value: V) -> Result<(), CacheError>;
34
35 async fn remove(&self, key: &K) -> bool;
40
41 async fn contains_key(&self, key: &K) -> bool;
46
47 async fn get_stats(&self) -> UnifiedCacheStats;
52
53 async fn clear(&self) -> Result<(), CacheError>;
57
58 async fn size(&self) -> usize;
60
61 async fn is_empty(&self) -> bool {
63 self.size().await == 0
64 }
65
66 async fn capacity(&self) -> usize;
68
69 fn cache_type(&self) -> &'static str;
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct CacheEntryMetadata {
76 pub created_at: u64,
78 pub last_accessed: u64,
80 pub access_count: u64,
82 pub ttl: u64,
84 pub size_bytes: u64,
86 pub cache_level: CacheLevel,
88 pub priority_score: f64,
90}
91
92impl CacheEntryMetadata {
93 pub fn new(ttl: u64, size_bytes: u64, cache_level: CacheLevel) -> Self {
95 let now = std::time::SystemTime::now()
96 .duration_since(std::time::UNIX_EPOCH)
97 .map(|d| d.as_secs())
98 .unwrap_or(0);
99
100 Self {
101 created_at: now,
102 last_accessed: now,
103 access_count: 0,
104 ttl,
105 size_bytes,
106 cache_level,
107 priority_score: 1.0,
108 }
109 }
110
111 pub fn mark_accessed(&mut self) {
113 self.access_count += 1;
114 self.last_accessed = std::time::SystemTime::now()
115 .duration_since(std::time::UNIX_EPOCH)
116 .map(|d| d.as_secs())
117 .unwrap_or(0);
118 }
119
120 pub fn is_expired(&self) -> bool {
122 let now = std::time::SystemTime::now()
123 .duration_since(std::time::UNIX_EPOCH)
124 .map(|d| d.as_secs())
125 .unwrap_or(0);
126 now > self.created_at + self.ttl
127 }
128
129 pub fn retention_score(&self) -> f64 {
131 let age_factor =
132 1.0 / (1.0 + (self.last_accessed as f64 - self.created_at as f64) / 3600.0);
133 let frequency_factor = (self.access_count as f64).ln().max(1.0);
134 let size_factor = 1.0 / (1.0 + self.size_bytes as f64 / 1024.0);
135
136 self.priority_score * frequency_factor * age_factor * size_factor
137 }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
142pub enum CacheLevel {
143 L1,
145 L2,
147 L3,
149}
150
151impl CacheLevel {
152 pub fn speed_rank(&self) -> u8 {
154 match self {
155 CacheLevel::L1 => 1,
156 CacheLevel::L2 => 2,
157 CacheLevel::L3 => 3,
158 }
159 }
160
161 pub fn capacity_rank(&self) -> u8 {
163 match self {
164 CacheLevel::L1 => 1,
165 CacheLevel::L2 => 2,
166 CacheLevel::L3 => 3,
167 }
168 }
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct CacheEntry<V> {
174 pub value: V,
176 pub metadata: CacheEntryMetadata,
178}
179
180impl<V> CacheEntry<V> {
181 pub fn new(value: V, ttl: u64, size_bytes: u64, cache_level: CacheLevel) -> Self {
183 Self {
184 value,
185 metadata: CacheEntryMetadata::new(ttl, size_bytes, cache_level),
186 }
187 }
188
189 pub fn access(&mut self) -> &V {
191 self.metadata.mark_accessed();
192 &self.value
193 }
194
195 pub fn is_expired(&self) -> bool {
197 self.metadata.is_expired()
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_cache_entry_metadata() {
207 let metadata = CacheEntryMetadata::new(3600, 1024, CacheLevel::L1);
208 assert_eq!(metadata.ttl, 3600);
209 assert_eq!(metadata.size_bytes, 1024);
210 assert_eq!(metadata.cache_level, CacheLevel::L1);
211 assert!(!metadata.is_expired());
212 }
213
214 #[test]
215 fn test_cache_level_rankings() {
216 assert!(CacheLevel::L1.speed_rank() < CacheLevel::L2.speed_rank());
217 assert!(CacheLevel::L2.speed_rank() < CacheLevel::L3.speed_rank());
218 assert!(CacheLevel::L1.capacity_rank() < CacheLevel::L2.capacity_rank());
219 }
220
221 #[test]
222 fn test_cache_entry() {
223 let entry = CacheEntry::new("test_value".to_string(), 3600, 100, CacheLevel::L1);
224 assert_eq!(entry.value, "test_value");
225 assert!(!entry.is_expired());
226 }
227}