rws_server/cache/
value.rs1use std::collections::{BTreeMap, HashMap};
6use std::future::Future;
7use std::sync::{Arc, Mutex};
8use std::time::{Duration, Instant};
9
10struct Entry<V> {
11 value: V,
12 expires: Instant,
13 seq: u64,
14}
15
16struct Inner<V> {
17 entries: HashMap<String, Entry<V>>,
18 order: BTreeMap<u64, String>,
20 next_seq: u64,
21 hits: u64,
22 misses: u64,
23}
24
25pub struct ValueCache<V> {
44 inner: Arc<Mutex<Inner<V>>>,
45 capacity: usize,
46}
47
48impl<V> Clone for ValueCache<V> {
49 fn clone(&self) -> Self {
50 ValueCache { inner: Arc::clone(&self.inner), capacity: self.capacity }
51 }
52}
53
54impl<V: Clone> ValueCache<V> {
55 pub fn new(capacity: usize) -> Self {
57 ValueCache {
58 inner: Arc::new(Mutex::new(Inner { entries: HashMap::new(), order: BTreeMap::new(), next_seq: 0, hits: 0, misses: 0 })),
59 capacity: capacity.max(1),
60 }
61 }
62
63 fn lock(&self) -> std::sync::MutexGuard<'_, Inner<V>> {
64 self.inner.lock().unwrap_or_else(|e| e.into_inner())
65 }
66
67 pub fn get(&self, key: &str) -> Option<V> {
69 let mut inner = self.lock();
70 let now = Instant::now();
71 let found = match inner.entries.get(key) {
72 Some(entry) if entry.expires > now => Some(entry.value.clone()),
73 Some(_) => {
74 if let Some(entry) = inner.entries.remove(key) {
75 inner.order.remove(&entry.seq);
76 }
77 None
78 }
79 None => None,
80 };
81 match found {
82 Some(value) => {
83 inner.hits += 1;
84 Some(value)
85 }
86 None => {
87 inner.misses += 1;
88 None
89 }
90 }
91 }
92
93 pub fn put(&self, key: &str, value: V, ttl: Duration) {
95 let mut inner = self.lock();
96 let now = Instant::now();
97 if let Some(old) = inner.entries.remove(key) {
98 inner.order.remove(&old.seq);
99 }
100 if inner.entries.len() >= self.capacity {
101 let expired: Vec<String> = inner.entries.iter().filter(|(_, e)| e.expires <= now).map(|(k, _)| k.clone()).collect();
102 for k in expired {
103 if let Some(e) = inner.entries.remove(&k) {
104 inner.order.remove(&e.seq);
105 }
106 }
107 }
108 while inner.entries.len() >= self.capacity {
109 let Some((&seq, _)) = inner.order.iter().next() else { break };
110 if let Some(oldest) = inner.order.remove(&seq) {
111 inner.entries.remove(&oldest);
112 }
113 }
114 let seq = inner.next_seq;
115 inner.next_seq += 1;
116 inner.order.insert(seq, key.to_string());
117 inner.entries.insert(key.to_string(), Entry { value, expires: now + ttl, seq });
118 }
119
120 pub fn fetch_or(&self, key: &str, ttl: Duration, compute: impl FnOnce() -> V) -> V {
122 if let Some(value) = self.get(key) {
123 return value;
124 }
125 let value = compute();
126 self.put(key, value.clone(), ttl);
127 value
128 }
129
130 pub fn try_fetch_or<E>(&self, key: &str, ttl: Duration, compute: impl FnOnce() -> Result<V, E>) -> Result<V, E> {
133 if let Some(value) = self.get(key) {
134 return Ok(value);
135 }
136 let value = compute()?;
137 self.put(key, value.clone(), ttl);
138 Ok(value)
139 }
140
141 pub async fn fetch_or_async<F, Fut>(&self, key: &str, ttl: Duration, compute: F) -> V
143 where
144 F: FnOnce() -> Fut,
145 Fut: Future<Output = V>,
146 {
147 if let Some(value) = self.get(key) {
148 return value;
149 }
150 let value = compute().await;
151 self.put(key, value.clone(), ttl);
152 value
153 }
154
155 pub async fn try_fetch_or_async<E, F, Fut>(&self, key: &str, ttl: Duration, compute: F) -> Result<V, E>
157 where
158 F: FnOnce() -> Fut,
159 Fut: Future<Output = Result<V, E>>,
160 {
161 if let Some(value) = self.get(key) {
162 return Ok(value);
163 }
164 let value = compute().await?;
165 self.put(key, value.clone(), ttl);
166 Ok(value)
167 }
168
169 pub fn invalidate(&self, key: &str) -> bool {
171 let mut inner = self.lock();
172 match inner.entries.remove(key) {
173 Some(entry) => {
174 inner.order.remove(&entry.seq);
175 true
176 }
177 None => false,
178 }
179 }
180
181 pub fn invalidate_prefix(&self, prefix: &str) -> usize {
183 let mut inner = self.lock();
184 let keys: Vec<String> = inner.entries.keys().filter(|k| k.starts_with(prefix)).cloned().collect();
185 for k in &keys {
186 if let Some(entry) = inner.entries.remove(k) {
187 inner.order.remove(&entry.seq);
188 }
189 }
190 keys.len()
191 }
192
193 pub fn clear(&self) {
194 let mut inner = self.lock();
195 inner.entries.clear();
196 inner.order.clear();
197 }
198
199 pub fn len(&self) -> usize {
201 self.lock().entries.len()
202 }
203
204 pub fn is_empty(&self) -> bool {
205 self.len() == 0
206 }
207
208 pub fn stats(&self) -> (u64, u64) {
210 let inner = self.lock();
211 (inner.hits, inner.misses)
212 }
213}
214
215#[cfg(test)]
216mod tests;