Skip to main content

backbone_cache/
traits.rs

1//! Cache trait definitions
2
3use async_trait::async_trait;
4use crate::CacheResult;
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8/// Cache entry metadata
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct CacheEntry<T> {
11    /// Cached data
12    pub data: T,
13
14    /// Creation timestamp
15    pub created_at: DateTime<Utc>,
16
17    /// Expiration timestamp (None for no expiration)
18    pub expires_at: Option<DateTime<Utc>>,
19
20    /// Number of times this entry was accessed
21    pub access_count: u64,
22
23    /// Last access timestamp
24    pub last_accessed: Option<DateTime<Utc>>,
25}
26
27impl<T> CacheEntry<T> {
28    /// Create new cache entry
29    pub fn new(data: T, ttl_seconds: Option<u64>) -> Self {
30        let now = Utc::now();
31        let expires_at = ttl_seconds.map(|ttl| now + chrono::Duration::seconds(ttl as i64));
32
33        Self {
34            data,
35            created_at: now,
36            expires_at,
37            access_count: 0,
38            last_accessed: None,
39        }
40    }
41
42    /// Check if entry is expired
43    pub fn is_expired(&self) -> bool {
44        self.expires_at
45            .map(|expires_at| Utc::now() > expires_at)
46            .unwrap_or(false)
47    }
48
49    /// Mark entry as accessed
50    pub fn mark_accessed(&mut self) {
51        self.access_count += 1;
52        self.last_accessed = Some(Utc::now());
53    }
54}
55
56/// Generic cache trait
57#[async_trait]
58pub trait Cache: Send + Sync {
59    /// Store value in cache
60    async fn set<T>(&self, key: &str, value: &T, ttl_seconds: Option<u64>) -> CacheResult<()>
61    where
62        T: Serialize + Send + Sync;
63
64    /// Get value from cache
65    async fn get<T>(&self, key: &str) -> CacheResult<Option<T>>
66    where
67        T: for<'de> Deserialize<'de> + Send + Sync;
68
69    /// Delete value from cache
70    async fn delete(&self, key: &str) -> CacheResult<bool>;
71
72    /// Check if key exists in cache
73    async fn exists(&self, key: &str) -> CacheResult<bool>;
74
75    /// Set TTL for existing key
76    async fn expire(&self, key: &str, ttl_seconds: u64) -> CacheResult<bool>;
77
78    /// Get TTL for key (None if key doesn't exist or has no expiration)
79    async fn ttl(&self, key: &str) -> CacheResult<Option<u64>>;
80
81    /// Clear all cache entries
82    async fn clear(&self) -> CacheResult<()>;
83
84    /// Get cache statistics
85    async fn stats(&self) -> CacheResult<CacheStats>;
86
87    /// Get multiple values from cache
88    async fn mget<T>(&self, keys: Vec<String>) -> CacheResult<Vec<(String, Option<T>)>>
89    where
90        T: for<'de> Deserialize<'de> + Send + Sync;
91
92    /// Set multiple values in cache
93    async fn mset<T>(&self, entries: Vec<(String, T, Option<u64>)>) -> CacheResult<()>
94    where
95        T: Serialize + Send + Sync;
96
97    /// Delete multiple keys from cache
98    async fn mdelete(&self, keys: Vec<String>) -> CacheResult<u64>;
99}
100
101/// Cache statistics
102#[derive(Debug, Clone)]
103pub struct CacheStats {
104    /// Total number of entries in cache
105    pub total_entries: u64,
106
107    /// Number of entries currently expired but not yet cleaned up
108    pub expired_entries: u64,
109
110    /// Total cache size in bytes (if available)
111    pub memory_usage: Option<u64>,
112
113    /// Hit rate (0.0 to 1.0)
114    pub hit_rate: f64,
115
116    /// Number of successful get operations
117    pub hits: u64,
118
119    /// Number of failed get operations (misses)
120    pub misses: u64,
121
122    /// Number of set operations
123    pub sets: u64,
124
125    /// Number of delete operations
126    pub deletes: u64,
127}
128
129impl Default for CacheStats {
130    fn default() -> Self {
131        Self {
132            total_entries: 0,
133            expired_entries: 0,
134            memory_usage: None,
135            hit_rate: 0.0,
136            hits: 0,
137            misses: 0,
138            sets: 0,
139            deletes: 0,
140        }
141    }
142}
143
144impl CacheStats {
145    /// Update hit rate based on hits and misses
146    pub fn update_hit_rate(&mut self) {
147        let total_requests = self.hits + self.misses;
148        if total_requests == 0 {
149            return;
150        }
151        self.hit_rate = self.hits as f64 / total_requests as f64;
152    }
153
154    /// Record a cache hit
155    pub fn record_hit(&mut self) {
156        self.hits += 1;
157        self.update_hit_rate();
158    }
159
160    /// Record a cache miss
161    pub fn record_miss(&mut self) {
162        self.misses += 1;
163        self.update_hit_rate();
164    }
165
166    /// Record a cache set
167    pub fn record_set(&mut self) {
168        self.sets += 1;
169    }
170
171    /// Record a cache delete
172    pub fn record_delete(&mut self) {
173        self.deletes += 1;
174    }
175}