1use crate::*;
2use std::{
3 collections::HashMap,
4 sync::{Arc, Mutex, MutexGuard},
5};
6use tokio::sync::broadcast;
7use web_time::Instant;
8
9#[derive(Clone, Debug)]
10pub struct MemoryOptions {
11 pub max_keys: usize,
14 pub max_topics: usize,
15 pub limits: Limits,
16}
17impl Default for MemoryOptions {
18 fn default() -> Self {
19 Self {
20 max_keys: 100_000,
21 max_topics: 256,
22 limits: Limits::default(),
23 }
24 }
25}
26struct Timed<T> {
27 value: T,
28 expires: Instant,
29}
30#[derive(Default)]
31struct State {
32 values: HashMap<String, Timed<Entry>>,
33 counters: HashMap<String, Timed<Counter>>,
34 permits: HashMap<String, HashMap<Version, Instant>>,
35 topics: HashMap<String, broadcast::Sender<Vec<u8>>>,
36}
37impl State {
38 fn keys(&self) -> usize {
39 self.values.len() + self.counters.len() + self.permits.len()
40 }
41 fn purge(&mut self, now: Instant) -> usize {
42 let before = self.keys();
43 self.values.retain(|_, v| v.expires > now);
44 self.counters.retain(|_, v| v.expires > now);
45 self.permits.retain(|_, holders| {
46 holders.retain(|_, expires| *expires > now);
47 !holders.is_empty()
48 });
49 self.topics.retain(|_, sender| sender.receiver_count() > 0);
50 before - self.keys()
51 }
52 fn room(&mut self, max: usize, now: Instant) -> Result<()> {
65 if self.keys() < max {
66 return Ok(());
67 }
68 self.purge(now);
69 let batch = (max / 8).max(1);
70 if self.keys() >= max {
71 evict_soonest(&mut self.values, batch);
72 }
73 if self.keys() >= max {
74 evict_soonest(&mut self.counters, batch);
75 }
76 if self.keys() >= max {
77 return Err(CacheError::Capacity);
78 }
79 Ok(())
80 }
81 fn expire_key(&mut self, key: &str, now: Instant) {
82 if self.values.get(key).is_some_and(|v| v.expires <= now) {
83 self.values.remove(key);
84 }
85 if self.counters.get(key).is_some_and(|v| v.expires <= now) {
86 self.counters.remove(key);
87 }
88 if let Some(holders) = self.permits.get_mut(key) {
89 holders.retain(|_, expires| *expires > now);
90 if holders.is_empty() {
91 self.permits.remove(key);
92 }
93 }
94 }
95}
96fn evict_soonest<T>(map: &mut HashMap<String, Timed<T>>, count: usize) {
98 if map.len() <= count {
99 map.clear();
100 return;
101 }
102 let mut expiries: Vec<Instant> = map.values().map(|v| v.expires).collect();
103 let (_, cutoff, _) = expiries.select_nth_unstable(count - 1);
104 let cutoff = *cutoff;
105 map.retain(|_, v| v.expires > cutoff);
106}
107struct Inner {
108 options: MemoryOptions,
109 state: Mutex<State>,
110}
111#[derive(Clone)]
113pub struct MemoryCache(Arc<Inner>);
114impl Default for MemoryCache {
115 fn default() -> Self {
116 Self::new(MemoryOptions::default()).expect("valid defaults")
117 }
118}
119impl MemoryCache {
120 pub fn new(options: MemoryOptions) -> Result<Self> {
121 options.limits.validate()?;
122 if options.max_keys == 0 || options.max_topics == 0 {
123 return Err(CacheError::Invalid("memory capacities must be positive"));
124 }
125 Ok(Self(Arc::new(Inner {
126 options,
127 state: Mutex::new(State::default()),
128 })))
129 }
130 fn state(&self) -> Result<MutexGuard<'_, State>> {
131 self.0.state.lock().map_err(|_| CacheError::Poisoned)
132 }
133 pub fn purge_expired(&self) -> Result<usize> {
135 Ok(self.state()?.purge(Instant::now()))
136 }
137 fn expiry(ttl: Duration) -> Result<Instant> {
138 Instant::now()
139 .checked_add(Duration::from_millis(ttl_ms(ttl)?))
140 .ok_or(CacheError::Invalid("TTL exceeds clock range"))
141 }
142}
143#[async_trait::async_trait]
144impl Cache for MemoryCache {
145 async fn get(&self, key: &str) -> Result<Option<Entry>> {
146 self.0.options.limits.key(key)?;
147 let mut state = self.state()?;
148 state.expire_key(key, Instant::now());
149 Ok(state.values.get(key).map(|v| v.value.clone()))
150 }
151 async fn get_many(&self, keys: &[String]) -> Result<Vec<Option<Entry>>> {
152 for key in keys {
153 self.0.options.limits.key(key)?;
154 }
155 let now = Instant::now();
156 let mut state = self.state()?;
157 Ok(keys
158 .iter()
159 .map(|key| {
160 state.expire_key(key, now);
161 state.values.get(key.as_str()).map(|v| v.value.clone())
162 })
163 .collect())
164 }
165 async fn put(&self, key: &str, value: Vec<u8>, ttl: Duration) -> Result<Version> {
166 self.0.options.limits.key(key)?;
167 self.0.options.limits.value(&value)?;
168 let expires = Self::expiry(ttl)?;
169 let version = Version::fresh()?;
170 let mut state = self.state()?;
171 state.expire_key(key, Instant::now());
172 if !state.values.contains_key(key) {
173 state.room(self.0.options.max_keys, Instant::now())?;
174 }
175 state.values.insert(
176 key.into(),
177 Timed {
178 value: Entry { value, version },
179 expires,
180 },
181 );
182 Ok(version)
183 }
184 async fn delete(&self, key: &str) -> Result<bool> {
185 self.0.options.limits.key(key)?;
186 let mut state = self.state()?;
187 state.expire_key(key, Instant::now());
188 Ok(state.values.remove(key).is_some())
189 }
190 async fn compare_exchange(
191 &self,
192 key: &str,
193 expected: Option<Version>,
194 replacement: Option<Replacement>,
195 ) -> Result<CasOutcome> {
196 self.0.options.limits.key(key)?;
197 let next = replacement
198 .map(|r| -> Result<_> {
199 self.0.options.limits.value(&r.value)?;
200 Ok(Timed {
201 value: Entry {
202 value: r.value,
203 version: Version::fresh()?,
204 },
205 expires: Self::expiry(r.ttl)?,
206 })
207 })
208 .transpose()?;
209 let mut state = self.state()?;
210 state.expire_key(key, Instant::now());
211 if state.values.get(key).map(|v| v.value.version) != expected {
212 return Ok(CasOutcome::Conflict);
213 }
214 let version = next.as_ref().map(|v| v.value.version);
215 if let Some(next) = next {
216 if !state.values.contains_key(key) {
217 state.room(self.0.options.max_keys, Instant::now())?;
218 }
219 state.values.insert(key.into(), next);
220 } else {
221 state.values.remove(key);
222 }
223 Ok(CasOutcome::Applied(version))
224 }
225 async fn counter(&self, key: &str) -> Result<Option<Counter>> {
226 self.0.options.limits.key(key)?;
227 let mut state = self.state()?;
228 state.expire_key(key, Instant::now());
229 Ok(state.counters.get(key).map(|v| v.value))
230 }
231 async fn increment(
232 &self,
233 key: &str,
234 amount: u64,
235 limit: u64,
236 ttl: Duration,
237 ) -> Result<IncrementOutcome> {
238 self.0.options.limits.key(key)?;
239 counter_args(amount, limit)?;
240 let expires = Self::expiry(ttl)?;
241 let mut state = self.state()?;
242 state.expire_key(key, Instant::now());
243 let current = state.counters.get(key).map_or(0, |v| v.value.value);
244 if amount > limit.saturating_sub(current) {
245 return Ok(IncrementOutcome::Limited { current });
246 }
247 if let Some(entry) = state.counters.get_mut(key) {
248 entry.value.value += amount;
249 return Ok(IncrementOutcome::Applied(entry.value));
250 }
251 state.room(self.0.options.max_keys, Instant::now())?;
252 let counter = Counter {
253 value: amount,
254 generation: Version::fresh()?,
255 };
256 state.counters.insert(
257 key.into(),
258 Timed {
259 value: counter,
260 expires,
261 },
262 );
263 Ok(IncrementOutcome::Applied(counter))
264 }
265 async fn decrement(
266 &self,
267 key: &str,
268 generation: Version,
269 amount: u64,
270 ) -> Result<Option<Counter>> {
271 self.0.options.limits.key(key)?;
272 counter_args(amount, i64::MAX as u64)?;
273 let mut state = self.state()?;
274 state.expire_key(key, Instant::now());
275 let Some(entry) = state
276 .counters
277 .get_mut(key)
278 .filter(|v| v.value.generation == generation)
279 else {
280 return Ok(None);
281 };
282 if entry.value.value < amount {
283 return Err(CacheError::Underflow);
284 }
285 entry.value.value -= amount;
286 Ok(Some(entry.value))
287 }
288 async fn acquire_permit(
289 &self,
290 key: &str,
291 limit: u32,
292 ttl: Duration,
293 ) -> Result<Option<Version>> {
294 self.0.options.limits.key(key)?;
295 self.0.options.limits.permits(limit)?;
296 let expires = Self::expiry(ttl)?;
297 let mut state = self.state()?;
298 state.expire_key(key, Instant::now());
299 if state
300 .permits
301 .get(key)
302 .is_some_and(|v| v.len() >= limit as usize)
303 {
304 return Ok(None);
305 }
306 if !state.permits.contains_key(key) {
307 state.room(self.0.options.max_keys, Instant::now())?;
308 }
309 let owner = Version::fresh()?;
310 state
311 .permits
312 .entry(key.into())
313 .or_default()
314 .insert(owner, expires);
315 Ok(Some(owner))
316 }
317 async fn renew_permit(&self, key: &str, owner: Version, ttl: Duration) -> Result<bool> {
318 self.0.options.limits.key(key)?;
319 let expires = Self::expiry(ttl)?;
320 let mut state = self.state()?;
321 state.expire_key(key, Instant::now());
322 let Some(deadline) = state.permits.get_mut(key).and_then(|v| v.get_mut(&owner)) else {
323 return Ok(false);
324 };
325 *deadline = expires;
326 Ok(true)
327 }
328 async fn release_permit(&self, key: &str, owner: Version) -> Result<bool> {
329 self.0.options.limits.key(key)?;
330 let mut state = self.state()?;
331 state.expire_key(key, Instant::now());
332 let released = state
333 .permits
334 .get_mut(key)
335 .is_some_and(|v| v.remove(&owner).is_some());
336 if state.permits.get(key).is_some_and(HashMap::is_empty) {
337 state.permits.remove(key);
338 }
339 Ok(released)
340 }
341 async fn publish(&self, topic: &str, payload: Vec<u8>) -> Result<()> {
342 self.0.options.limits.key(topic)?;
343 self.0.options.limits.value(&payload)?;
344 if let Some(sender) = self.state()?.topics.get(topic) {
345 let _ = sender.send(payload);
346 }
347 Ok(())
348 }
349 async fn subscribe(&self, topic: &str) -> Result<Box<dyn Subscription>> {
350 self.0.options.limits.key(topic)?;
351 let mut state = self.state()?;
352 state.topics.retain(|_, sender| sender.receiver_count() > 0);
353 if !state.topics.contains_key(topic) && state.topics.len() >= self.0.options.max_topics {
354 return Err(CacheError::Capacity);
355 }
356 let sender = state
357 .topics
358 .entry(topic.into())
359 .or_insert_with(|| broadcast::channel(self.0.options.limits.notification_capacity).0);
360 Ok(Box::new(MemorySubscription {
361 receiver: sender.subscribe(),
362 initial: true,
363 }))
364 }
365}
366struct MemorySubscription {
367 receiver: broadcast::Receiver<Vec<u8>>,
368 initial: bool,
369}
370#[async_trait::async_trait]
371impl Subscription for MemorySubscription {
372 async fn recv(&mut self) -> Result<Notification> {
373 if self.initial {
374 self.initial = false;
375 return Ok(Notification::ResyncRequired);
376 }
377 match self.receiver.recv().await {
378 Ok(value) => Ok(Notification::Message(value)),
379 Err(broadcast::error::RecvError::Lagged(_)) => Ok(Notification::ResyncRequired),
380 Err(broadcast::error::RecvError::Closed) => Err(CacheError::Closed),
381 }
382 }
383}