1use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7use std::time::{Duration, Instant};
8use sz_orm_model::CacheError;
9
10pub trait Cache: Send + Sync {
11 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
12 fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError>;
13 fn delete(&self, key: &str) -> Result<(), CacheError>;
14 fn clear(&self) -> Result<(), CacheError>;
15 fn exists(&self, key: &str) -> Result<bool, CacheError>;
16 fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError>;
17 fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError>;
18}
19
20#[derive(Clone)]
21pub struct MemoryCache {
22 data: Arc<RwLock<HashMap<String, CacheEntry>>>,
23 default_ttl: Option<Duration>,
24}
25
26struct CacheEntry {
27 value: Vec<u8>,
28 expires_at: Option<Instant>,
29}
30
31impl MemoryCache {
32 pub fn new() -> Self {
33 Self {
34 data: Arc::new(RwLock::new(HashMap::new())),
35 default_ttl: None,
36 }
37 }
38
39 pub fn with_ttl(ttl: Duration) -> Self {
40 Self {
41 data: Arc::new(RwLock::new(HashMap::new())),
42 default_ttl: Some(ttl),
43 }
44 }
45}
46
47impl Default for MemoryCache {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53impl Cache for MemoryCache {
54 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
55 let data = self.data.read()?;
56 if let Some(entry) = data.get(key) {
57 if let Some(expires_at) = entry.expires_at {
58 if expires_at <= Instant::now() {
59 return Ok(None);
60 }
61 }
62 Ok(Some(entry.value.clone()))
63 } else {
64 Ok(None)
65 }
66 }
67
68 fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
69 let expires_at = ttl.or(self.default_ttl).map(|d| Instant::now() + d);
70 let mut data = self.data.write()?;
71 data.insert(key.to_string(), CacheEntry { value, expires_at });
72 Ok(())
73 }
74
75 fn delete(&self, key: &str) -> Result<(), CacheError> {
76 let mut data = self.data.write()?;
77 data.remove(key);
78 Ok(())
79 }
80
81 fn clear(&self) -> Result<(), CacheError> {
82 let mut data = self.data.write()?;
83 data.clear();
84 Ok(())
85 }
86
87 fn exists(&self, key: &str) -> Result<bool, CacheError> {
88 let data = self.data.read()?;
89 if let Some(entry) = data.get(key) {
90 if let Some(expires_at) = entry.expires_at {
91 if expires_at <= Instant::now() {
92 return Ok(false);
93 }
94 }
95 Ok(true)
96 } else {
97 Ok(false)
98 }
99 }
100
101 fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError> {
102 let mut data = self.data.write()?;
103 if let Some(entry) = data.get_mut(key) {
104 entry.expires_at = Some(Instant::now() + ttl);
105 Ok(())
106 } else {
107 Err(CacheError::NotFound(key.to_string()))
108 }
109 }
110
111 fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError> {
112 let data = self.data.read()?;
113 if let Some(entry) = data.get(key) {
114 if let Some(expires_at) = entry.expires_at {
115 if expires_at <= Instant::now() {
116 return Ok(None);
117 }
118 let remaining = expires_at.duration_since(Instant::now());
119 Ok(Some(remaining))
120 } else {
121 Ok(None)
122 }
123 } else {
124 Err(CacheError::NotFound(key.to_string()))
125 }
126 }
127}
128
129pub struct MultiLevelCache {
130 caches: Vec<Box<dyn Cache>>,
131}
132
133impl MultiLevelCache {
134 pub fn new() -> Self {
135 Self { caches: Vec::new() }
136 }
137
138 pub fn add_cache(mut self, cache: Box<dyn Cache>) -> Self {
139 self.caches.push(cache);
140 self
141 }
142}
143
144impl Default for MultiLevelCache {
145 fn default() -> Self {
146 Self::new()
147 }
148}
149
150impl Cache for MultiLevelCache {
151 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
152 for (i, cache) in self.caches.iter().enumerate() {
153 if let Ok(Some(value)) = cache.get(key) {
154 let ttl = cache.ttl(key).ok().flatten();
156 for j in 0..i {
157 let _ = self.caches[j].set(key, value.clone(), ttl);
158 }
159 return Ok(Some(value));
160 }
161 }
162 Ok(None)
163 }
164
165 fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
166 for cache in &self.caches {
167 cache.set(key, value.clone(), ttl)?;
168 }
169 Ok(())
170 }
171
172 fn delete(&self, key: &str) -> Result<(), CacheError> {
173 for cache in &self.caches {
174 cache.delete(key)?;
175 }
176 Ok(())
177 }
178
179 fn clear(&self) -> Result<(), CacheError> {
180 for cache in &self.caches {
181 cache.clear()?;
182 }
183 Ok(())
184 }
185
186 fn exists(&self, key: &str) -> Result<bool, CacheError> {
187 for cache in &self.caches {
188 if cache.exists(key)? {
189 return Ok(true);
190 }
191 }
192 Ok(false)
193 }
194
195 fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError> {
196 for cache in &self.caches {
197 cache.expire(key, ttl)?;
198 }
199 Ok(())
200 }
201
202 fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError> {
203 if let Some(cache) = self.caches.first() {
204 cache.ttl(key)
205 } else {
206 Err(CacheError::NotFound("No caches configured".to_string()))
207 }
208 }
209}
210
211#[derive(Debug, Clone, Default)]
212pub struct CacheStats {
213 pub hits: u64,
214 pub misses: u64,
215 pub sets: u64,
216 pub deletes: u64,
217}
218
219pub fn read_through<F>(
234 cache: &dyn Cache,
235 key: &str,
236 ttl: Option<Duration>,
237 loader: F,
238) -> Result<Option<Vec<u8>>, CacheError>
239where
240 F: FnOnce() -> Result<Option<Vec<u8>>, CacheError>,
241{
242 if let Some(v) = cache.get(key)? {
244 return Ok(Some(v));
245 }
246 let value = loader()?;
248 if let Some(ref v) = value {
250 cache.set(key, v.clone(), ttl)?;
251 }
252 Ok(value)
253}
254
255pub async fn read_through_async<F, Fut>(
259 cache: &dyn Cache,
260 key: &str,
261 ttl: Option<Duration>,
262 loader: F,
263) -> Result<Option<Vec<u8>>, CacheError>
264where
265 F: FnOnce() -> Fut,
266 Fut: std::future::Future<Output = Result<Option<Vec<u8>>, CacheError>>,
267{
268 if let Some(v) = cache.get(key)? {
270 return Ok(Some(v));
271 }
272 let value = loader().await?;
274 if let Some(ref v) = value {
276 cache.set(key, v.clone(), ttl)?;
277 }
278 Ok(value)
279}
280
281pub fn write_through<F>(
292 cache: &dyn Cache,
293 key: &str,
294 value: Vec<u8>,
295 ttl: Option<Duration>,
296 writer: F,
297) -> Result<(), CacheError>
298where
299 F: FnOnce(&str, &[u8]) -> Result<(), CacheError>,
300{
301 writer(key, &value)?;
303 cache.set(key, value, ttl)?;
305 Ok(())
306}
307
308pub async fn write_through_async<F, Fut>(
312 cache: &dyn Cache,
313 key: &str,
314 value: Vec<u8>,
315 ttl: Option<Duration>,
316 writer: F,
317) -> Result<(), CacheError>
318where
319 F: FnOnce(&str, Vec<u8>) -> Fut,
320 Fut: std::future::Future<Output = Result<Vec<u8>, CacheError>>,
321{
322 let stored = writer(key, value).await?;
324 cache.set(key, stored, ttl)?;
326 Ok(())
327}
328
329pub fn write_around<F>(cache: &dyn Cache, key: &str, writer: F) -> Result<(), CacheError>
333where
334 F: FnOnce(&str) -> Result<(), CacheError>,
335{
336 writer(key)?;
337 cache.delete(key)?;
338 Ok(())
339}
340
341#[derive(Debug, Clone, PartialEq, Eq)]
348pub enum CacheLookup {
349 Found(Vec<u8>),
351 Miss,
353 NotFound,
355}
356
357pub struct NegativeCache<C: Cache> {
364 inner: C,
366 negatives: RwLock<HashMap<String, Instant>>,
368 negative_ttl: Duration,
370}
371
372impl<C: Cache> NegativeCache<C> {
373 pub fn new(inner: C) -> Self {
375 Self {
376 inner,
377 negatives: RwLock::new(HashMap::new()),
378 negative_ttl: Duration::from_secs(60),
379 }
380 }
381
382 pub fn with_negative_ttl(mut self, ttl: Duration) -> Self {
384 self.negative_ttl = ttl;
385 self
386 }
387
388 pub fn get_or_negative(&self, key: &str) -> Result<CacheLookup, CacheError> {
395 let now = Instant::now();
397 {
398 let neg = self.negatives.read()?;
399 if let Some(expires_at) = neg.get(key) {
400 if *expires_at > now {
401 return Ok(CacheLookup::NotFound);
402 }
403 }
404 }
405 match self.inner.get(key)? {
407 Some(v) => Ok(CacheLookup::Found(v)),
408 None => {
409 let mut neg = self.negatives.write()?;
411 neg.insert(key.to_string(), now + self.negative_ttl);
412 Ok(CacheLookup::Miss)
413 }
414 }
415 }
416
417 pub fn purge_expired(&self) -> Result<usize, CacheError> {
419 let now = Instant::now();
420 let mut neg = self.negatives.write()?;
421 let before = neg.len();
422 neg.retain(|_, expires_at| *expires_at > now);
423 Ok(before - neg.len())
424 }
425}
426
427impl<C: Cache> Cache for NegativeCache<C> {
428 fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
429 match self.get_or_negative(key)? {
430 CacheLookup::Found(v) => Ok(Some(v)),
431 CacheLookup::Miss | CacheLookup::NotFound => Ok(None),
432 }
433 }
434
435 fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<(), CacheError> {
436 {
438 let mut neg = self.negatives.write()?;
439 neg.remove(key);
440 }
441 self.inner.set(key, value, ttl)
442 }
443
444 fn delete(&self, key: &str) -> Result<(), CacheError> {
445 {
446 let mut neg = self.negatives.write()?;
447 neg.remove(key);
448 }
449 self.inner.delete(key)
450 }
451
452 fn clear(&self) -> Result<(), CacheError> {
453 {
454 let mut neg = self.negatives.write()?;
455 neg.clear();
456 }
457 self.inner.clear()
458 }
459
460 fn exists(&self, key: &str) -> Result<bool, CacheError> {
461 self.inner.exists(key)
462 }
463
464 fn expire(&self, key: &str, ttl: Duration) -> Result<(), CacheError> {
465 self.inner.expire(key, ttl)
466 }
467
468 fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError> {
469 self.inner.ttl(key)
470 }
471}
472
473#[cfg(test)]
474mod tests {
475 use super::*;
476
477 #[test]
478 fn test_memory_cache_set_get() {
479 let cache = MemoryCache::new();
480 cache.set("key1", b"value1".to_vec(), None).unwrap();
481 let val = cache.get("key1").unwrap();
482 assert_eq!(val, Some(b"value1".to_vec()));
483 }
484
485 #[test]
486 fn test_memory_cache_delete() {
487 let cache = MemoryCache::new();
488 cache.set("key1", b"value1".to_vec(), None).unwrap();
489 cache.delete("key1").unwrap();
490 let val = cache.get("key1").unwrap();
491 assert_eq!(val, None);
492 }
493
494 #[test]
495 fn test_memory_cache_exists() {
496 let cache = MemoryCache::new();
497 cache.set("key1", b"value1".to_vec(), None).unwrap();
498 let exists = cache.exists("key1").unwrap();
499 assert!(exists);
500 let exists2 = cache.exists("nonexistent").unwrap();
501 assert!(!exists2);
502 }
503
504 #[test]
505 fn test_memory_cache_clear() {
506 let cache = MemoryCache::new();
507 cache.set("key1", b"value1".to_vec(), None).unwrap();
508 cache.set("key2", b"value2".to_vec(), None).unwrap();
509 cache.clear().unwrap();
510 let val = cache.get("key1").unwrap();
511 assert_eq!(val, None);
512 }
513
514 #[test]
515 fn test_memory_cache_with_ttl() {
516 let cache = MemoryCache::with_ttl(Duration::from_secs(1));
517 cache.set("key1", b"value1".to_vec(), None).unwrap();
518 let val = cache.get("key1").unwrap();
519 assert!(val.is_some());
520 }
521
522 #[test]
523 fn test_cache_stats() {
524 let stats = CacheStats::default();
525 assert_eq!(stats.hits, 0);
526 assert_eq!(stats.misses, 0);
527 }
528
529 #[test]
530 fn test_multi_level_cache() {
531 let cache1 = MemoryCache::new();
532 let cache2 = MemoryCache::new();
533 let multi = MultiLevelCache::new()
534 .add_cache(Box::new(cache1))
535 .add_cache(Box::new(cache2));
536
537 multi.set("key1", b"value1".to_vec(), None).unwrap();
538 let val = multi.get("key1").unwrap();
539 assert_eq!(val, Some(b"value1".to_vec()));
540
541 multi.delete("key1").unwrap();
542 let val = multi.get("key1").unwrap();
543 assert_eq!(val, None);
544 }
545
546 #[test]
548 fn test_negative_cache_found() {
549 let inner = MemoryCache::new();
550 inner.set("key1", b"value1".to_vec(), None).unwrap();
551 let cache = NegativeCache::new(inner);
552 let result = cache.get_or_negative("key1").unwrap();
553 assert_eq!(result, CacheLookup::Found(b"value1".to_vec()));
554 }
555
556 #[test]
557 fn test_negative_cache_miss_then_not_found() {
558 let inner = MemoryCache::new();
559 let cache = NegativeCache::new(inner);
560 let result = cache.get_or_negative("missing").unwrap();
562 assert_eq!(result, CacheLookup::Miss);
563 let result = cache.get_or_negative("missing").unwrap();
565 assert_eq!(result, CacheLookup::NotFound);
566 }
567
568 #[test]
569 fn test_negative_cache_set_clears_negative() {
570 let inner = MemoryCache::new();
571 let cache = NegativeCache::new(inner);
572 cache.get_or_negative("key1").unwrap();
574 assert_eq!(
575 cache.get_or_negative("key1").unwrap(),
576 CacheLookup::NotFound
577 );
578 cache.set("key1", b"value1".to_vec(), None).unwrap();
580 assert_eq!(
581 cache.get_or_negative("key1").unwrap(),
582 CacheLookup::Found(b"value1".to_vec())
583 );
584 }
585
586 #[test]
587 fn test_negative_cache_delete_clears_negative() {
588 let inner = MemoryCache::new();
589 inner.set("key1", b"value1".to_vec(), None).unwrap();
590 let cache = NegativeCache::new(inner);
591 cache.delete("key1").unwrap();
593 let result = cache.get_or_negative("key1").unwrap();
594 assert_eq!(result, CacheLookup::Miss);
595 }
596
597 #[test]
598 fn test_negative_cache_ttl_expiry() {
599 let inner = MemoryCache::new();
600 let cache = NegativeCache::new(inner).with_negative_ttl(Duration::from_millis(50));
601 cache.get_or_negative("key1").unwrap();
603 assert_eq!(
604 cache.get_or_negative("key1").unwrap(),
605 CacheLookup::NotFound
606 );
607 std::thread::sleep(Duration::from_millis(60));
609 let result = cache.get_or_negative("key1").unwrap();
611 assert_eq!(result, CacheLookup::Miss);
612 }
613
614 #[test]
615 fn test_negative_cache_clear() {
616 let inner = MemoryCache::new();
617 let cache = NegativeCache::new(inner);
618 cache.get_or_negative("key1").unwrap();
619 cache.get_or_negative("key2").unwrap();
620 cache.clear().unwrap();
621 assert_eq!(cache.get_or_negative("key1").unwrap(), CacheLookup::Miss);
623 assert_eq!(cache.get_or_negative("key2").unwrap(), CacheLookup::Miss);
624 }
625
626 #[test]
627 fn test_negative_cache_purge_expired() {
628 let inner = MemoryCache::new();
629 let cache = NegativeCache::new(inner).with_negative_ttl(Duration::from_millis(50));
630 cache.get_or_negative("key1").unwrap();
631 cache.get_or_negative("key2").unwrap();
632 std::thread::sleep(Duration::from_millis(60));
633 let purged = cache.purge_expired().unwrap();
634 assert_eq!(purged, 2);
635 }
636
637 #[test]
638 fn test_negative_cache_as_cache_trait() {
639 let inner = MemoryCache::new();
640 let cache = NegativeCache::new(inner);
641 let val = cache.get("missing").unwrap();
643 assert_eq!(val, None);
644 let val = cache.get("missing").unwrap();
646 assert_eq!(val, None);
647 cache.set("key1", b"value1".to_vec(), None).unwrap();
649 let val = cache.get("key1").unwrap();
650 assert_eq!(val, Some(b"value1".to_vec()));
651 }
652}