multi_tier_cache/backends/
dashmap_cache.rs1use std::sync::Arc;
7use std::time::{Duration, Instant};
8use anyhow::Result;
9use serde_json;
10use dashmap::DashMap;
11use std::sync::atomic::{AtomicU64, Ordering};
12
13#[derive(Debug, Clone)]
15struct CacheEntry {
16 value: serde_json::Value,
17 expires_at: Option<Instant>,
18}
19
20impl CacheEntry {
21 fn new(value: serde_json::Value, ttl: Duration) -> Self {
22 Self {
23 value,
24 expires_at: Some(Instant::now() + ttl),
25 }
26 }
27
28 fn is_expired(&self) -> bool {
29 match self.expires_at {
30 Some(expires_at) => Instant::now() > expires_at,
31 None => false,
32 }
33 }
34}
35
36pub struct DashMapCache {
73 map: Arc<DashMap<String, CacheEntry>>,
75 hits: Arc<AtomicU64>,
77 misses: Arc<AtomicU64>,
79 sets: Arc<AtomicU64>,
81}
82
83impl DashMapCache {
84 pub fn new() -> Self {
86 println!(" ๐บ๏ธ Initializing DashMap Cache...");
87 println!(" โ
DashMap Cache initialized (concurrent HashMap)");
88
89 Self {
90 map: Arc::new(DashMap::new()),
91 hits: Arc::new(AtomicU64::new(0)),
92 misses: Arc::new(AtomicU64::new(0)),
93 sets: Arc::new(AtomicU64::new(0)),
94 }
95 }
96
97 pub async fn get(&self, key: &str) -> Option<serde_json::Value> {
99 match self.map.get(key) {
100 Some(entry) => {
101 if entry.is_expired() {
102 drop(entry); self.map.remove(key);
105 self.misses.fetch_add(1, Ordering::Relaxed);
106 None
107 } else {
108 self.hits.fetch_add(1, Ordering::Relaxed);
109 Some(entry.value.clone())
110 }
111 }
112 None => {
113 self.misses.fetch_add(1, Ordering::Relaxed);
114 None
115 }
116 }
117 }
118
119 pub async fn set_with_ttl(&self, key: &str, value: serde_json::Value, ttl: Duration) -> Result<()> {
121 let entry = CacheEntry::new(value, ttl);
122 self.map.insert(key.to_string(), entry);
123 self.sets.fetch_add(1, Ordering::Relaxed);
124 println!("๐พ [DashMap] Cached '{}' with TTL {:?}", key, ttl);
125 Ok(())
126 }
127
128 pub async fn remove(&self, key: &str) -> Result<()> {
130 self.map.remove(key);
131 Ok(())
132 }
133
134 pub async fn health_check(&self) -> bool {
136 let test_key = "health_check_dashmap";
137 let test_value = serde_json::json!({"test": true});
138
139 match self.set_with_ttl(test_key, test_value.clone(), Duration::from_secs(60)).await {
140 Ok(_) => {
141 match self.get(test_key).await {
142 Some(retrieved) => {
143 let _ = self.remove(test_key).await;
144 retrieved == test_value
145 }
146 None => false
147 }
148 }
149 Err(_) => false
150 }
151 }
152
153 pub fn cleanup_expired(&self) -> usize {
158 let mut removed = 0;
159 self.map.retain(|_, entry| {
160 if entry.is_expired() {
161 removed += 1;
162 false } else {
164 true }
166 });
167 if removed > 0 {
168 println!("๐งน [DashMap] Cleaned up {} expired entries", removed);
169 }
170 removed
171 }
172
173 pub fn len(&self) -> usize {
175 self.map.len()
176 }
177
178 pub fn is_empty(&self) -> bool {
180 self.map.is_empty()
181 }
182}
183
184impl Default for DashMapCache {
185 fn default() -> Self {
186 Self::new()
187 }
188}
189
190use crate::traits::CacheBackend;
193use async_trait::async_trait;
194
195#[async_trait]
197impl CacheBackend for DashMapCache {
198 async fn get(&self, key: &str) -> Option<serde_json::Value> {
199 DashMapCache::get(self, key).await
200 }
201
202 async fn set_with_ttl(
203 &self,
204 key: &str,
205 value: serde_json::Value,
206 ttl: Duration,
207 ) -> Result<()> {
208 DashMapCache::set_with_ttl(self, key, value, ttl).await
209 }
210
211 async fn remove(&self, key: &str) -> Result<()> {
212 DashMapCache::remove(self, key).await
213 }
214
215 async fn health_check(&self) -> bool {
216 DashMapCache::health_check(self).await
217 }
218
219 fn name(&self) -> &str {
220 "DashMap"
221 }
222}