Skip to content

Commit dd09af1

Browse files
authored
Backing improvements (#12)
* Backing improvements this change is breaking existing CacheBacking implementations * Support setting meta structs for set operations * Implement meta-supplier in loader function
1 parent 0122517 commit dd09af1

File tree

5 files changed

+389
-127
lines changed

5 files changed

+389
-127
lines changed

cache-loader-async-macros/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn test_with_features(item: proc_macro::TokenStream) -> proc_macro::TokenStr
8181
let result = quote! {
8282
#[tokio::test]
8383
async fn #fn_ident_default() {
84-
let #ident: LoadingCache<#key_type, #value_type, #error_type> = LoadingCache::new(move |key: #key_type| {
84+
let #ident: LoadingCache<#key_type, #value_type, #error_type, HashMapBacking<_, _>> = LoadingCache::new(move |key: #key_type| {
8585
async move #loader
8686
});
8787

@@ -91,7 +91,7 @@ pub fn test_with_features(item: proc_macro::TokenStream) -> proc_macro::TokenStr
9191
#[cfg(feature = "lru-cache")]
9292
#[tokio::test]
9393
async fn #fn_ident_lru() {
94-
let #ident: LoadingCache<#key_type, #value_type, #error_type> = LoadingCache::with_backing(LruCacheBacking::new(100), move |key: #key_type| {
94+
let #ident: LoadingCache<#key_type, #value_type, #error_type, LruCacheBacking<_, _>> = LoadingCache::with_backing(LruCacheBacking::new(100), move |key: #key_type| {
9595
async move #loader
9696
});
9797

@@ -101,7 +101,7 @@ pub fn test_with_features(item: proc_macro::TokenStream) -> proc_macro::TokenStr
101101
#[cfg(feature = "ttl-cache")]
102102
#[tokio::test]
103103
async fn #fn_ident_ttl() {
104-
let #ident: LoadingCache<#key_type, #value_type, #error_type> = LoadingCache::with_backing(TtlCacheBacking::new(Duration::from_secs(3)), move |key: #key_type| {
104+
let #ident: LoadingCache<#key_type, #value_type, #error_type, TtlCacheBacking<_, _>> = LoadingCache::with_backing(TtlCacheBacking::new(Duration::from_secs(3)), move |key: #key_type| {
105105
async move #loader
106106
});
107107

src/backing.rs

Lines changed: 116 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use std::hash::Hash;
44
use lru::LruCache;
55
#[cfg(feature = "ttl-cache")]
66
use std::collections::VecDeque;
7+
use std::fmt::Debug;
8+
use thiserror::Error;
79
#[cfg(feature = "ttl-cache")]
810
use std::ops::Add;
911
#[cfg(feature = "ttl-cache")]
@@ -12,15 +14,26 @@ use tokio::time::{Instant, Duration};
1214
pub trait CacheBacking<K, V>
1315
where K: Eq + Hash + Sized + Clone + Send,
1416
V: Sized + Clone + Send {
15-
fn get_mut(&mut self, key: &K) -> Option<&mut V>;
16-
fn get(&mut self, key: &K) -> Option<&V>;
17-
fn set(&mut self, key: K, value: V) -> Option<V>;
18-
fn remove(&mut self, key: &K) -> Option<V>;
19-
fn contains_key(&self, key: &K) -> bool;
20-
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send + 'static>);
21-
fn clear(&mut self);
17+
type Meta: Clone + Send;
18+
19+
fn get_mut(&mut self, key: &K) -> Result<Option<&mut V>, BackingError>;
20+
fn get(&mut self, key: &K) -> Result<Option<&V>, BackingError>;
21+
fn set(&mut self, key: K, value: V, meta: Option<Self::Meta>) -> Result<Option<V>, BackingError>;
22+
fn remove(&mut self, key: &K) -> Result<Option<V>, BackingError>;
23+
fn contains_key(&self, key: &K) -> Result<bool, BackingError>;
24+
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send + 'static>) -> Result<(), BackingError>;
25+
fn clear(&mut self) -> Result<(), BackingError>;
2226
}
2327

28+
#[derive(Debug, Clone, Error)]
29+
pub enum BackingError {
30+
#[error(transparent)]
31+
TtlError(#[from] TtlError),
32+
}
33+
34+
#[derive(Copy, Clone, Debug, Default)]
35+
pub struct NoMeta {}
36+
2437
#[cfg(feature = "lru-cache")]
2538
pub struct LruCacheBacking<K, V> {
2639
lru: LruCache<K, V>,
@@ -31,27 +44,29 @@ impl<
3144
K: Eq + Hash + Sized + Clone + Send,
3245
V: Sized + Clone + Send
3346
> CacheBacking<K, V> for LruCacheBacking<K, V> {
34-
fn get_mut(&mut self, key: &K) -> Option<&mut V> {
35-
self.lru.get_mut(key)
47+
type Meta = NoMeta;
48+
49+
fn get_mut(&mut self, key: &K) -> Result<Option<&mut V>, BackingError> {
50+
Ok(self.lru.get_mut(key))
3651
}
3752

38-
fn get(&mut self, key: &K) -> Option<&V> {
39-
self.lru.get(key)
53+
fn get(&mut self, key: &K) -> Result<Option<&V>, BackingError> {
54+
Ok(self.lru.get(key))
4055
}
4156

42-
fn set(&mut self, key: K, value: V) -> Option<V> {
43-
self.lru.put(key, value)
57+
fn set(&mut self, key: K, value: V, _meta: Option<Self::Meta>) -> Result<Option<V>, BackingError> {
58+
Ok(self.lru.put(key, value))
4459
}
4560

46-
fn remove(&mut self, key: &K) -> Option<V> {
47-
self.lru.pop(key)
61+
fn remove(&mut self, key: &K) -> Result<Option<V>, BackingError> {
62+
Ok(self.lru.pop(key))
4863
}
4964

50-
fn contains_key(&self, key: &K) -> bool {
51-
self.lru.contains(&key.clone())
65+
fn contains_key(&self, key: &K) -> Result<bool, BackingError> {
66+
Ok(self.lru.contains(&key.clone()))
5267
}
5368

54-
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send>) {
69+
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send>) -> Result<(), BackingError> {
5570
let keys = self.lru.iter()
5671
.filter_map(|(key, value)| {
5772
if predicate((key, value)) {
@@ -65,10 +80,12 @@ impl<
6580
for key in keys.into_iter() {
6681
self.lru.pop(&key);
6782
}
83+
Ok(())
6884
}
6985

70-
fn clear(&mut self) {
86+
fn clear(&mut self) -> Result<(), BackingError> {
7187
self.lru.clear();
88+
Ok(())
7289
}
7390
}
7491

@@ -114,51 +131,71 @@ impl<K> From<(K, Instant)> for TTlEntry<K> {
114131
}
115132
}
116133

134+
#[derive(Debug, Clone, Error)]
135+
pub enum TtlError {
136+
#[error("The expiry for key not found")]
137+
ExpiryNotFound,
138+
#[error("No key for expiry matched key")]
139+
ExpiryKeyNotFound,
140+
}
141+
142+
#[cfg(feature = "ttl-cache")]
143+
#[derive(Debug, Copy, Clone)]
144+
pub struct TtlMeta {
145+
pub ttl: Duration,
146+
}
147+
148+
#[cfg(feature = "ttl-cache")]
149+
impl From<Duration> for TtlMeta {
150+
fn from(ttl: Duration) -> Self {
151+
Self { ttl }
152+
}
153+
}
154+
117155
#[cfg(feature = "ttl-cache")]
118156
impl<
119157
K: Eq + Hash + Sized + Clone + Send,
120158
V: Sized + Clone + Send
121159
> CacheBacking<K, V> for TtlCacheBacking<K, V> {
122-
fn get_mut(&mut self, key: &K) -> Option<&mut V> {
160+
type Meta = TtlMeta;
161+
162+
fn get_mut(&mut self, key: &K) -> Result<Option<&mut V>, BackingError> {
123163
self.remove_old();
124-
self.map.get_mut(key)
125-
.map(|(value, _)| value)
164+
Ok(self.map.get_mut(key)
165+
.map(|(value, _)| value))
126166
}
127167

128-
fn get(&mut self, key: &K) -> Option<&V> {
168+
fn get(&mut self, key: &K) -> Result<Option<&V>, BackingError> {
129169
self.remove_old();
130-
self.map.get(key)
131-
.map(|(value, _)| value)
170+
Ok(self.map.get(key)
171+
.map(|(value, _)| value))
132172
}
133173

134-
fn set(&mut self, key: K, value: V) -> Option<V> {
174+
fn set(&mut self, key: K, value: V, meta: Option<Self::Meta>) -> Result<Option<V>, BackingError> {
135175
self.remove_old();
136-
let expiry = Instant::now().add(self.ttl);
137-
let result = self.replace(key.clone(), value, expiry);
138-
match self.expiry_queue.binary_search_by_key(&expiry, |entry| entry.expiry) {
139-
Ok(found) => {
140-
self.expiry_queue.insert(found + 1, (key, expiry).into());
141-
}
142-
Err(idx) => {
143-
self.expiry_queue.insert(idx, (key, expiry).into());
144-
}
145-
}
146-
result
176+
let ttl = if let Some(meta) = meta {
177+
meta.ttl
178+
} else {
179+
self.ttl
180+
};
181+
let expiry = Instant::now().add(ttl);
182+
let result = self.replace(key.clone(), value, expiry)?;
183+
Ok(result)
147184
}
148185

149-
fn remove(&mut self, key: &K) -> Option<V> {
186+
fn remove(&mut self, key: &K) -> Result<Option<V>, BackingError> {
150187
self.remove_old();
151-
self.remove_key(key)
188+
Ok(self.remove_key(key)?)
152189
}
153190

154-
fn contains_key(&self, key: &K) -> bool {
191+
fn contains_key(&self, key: &K) -> Result<bool, BackingError> {
155192
// we cant clean old keys on this, since the self ref is not mutable :(
156-
self.map.get(key)
193+
Ok(self.map.get(key)
157194
.filter(|(_, expiry)| Instant::now().lt(expiry))
158-
.is_some()
195+
.is_some())
159196
}
160197

161-
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send>) {
198+
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send>) -> Result<(), BackingError> {
162199
let keys = self.map.iter()
163200
.filter_map(|(key, (value, _))| {
164201
if predicate((key, value)) {
@@ -174,11 +211,13 @@ impl<
174211
// optimize looping through expiry_queue multiple times?
175212
self.expiry_queue.retain(|entry| entry.key.ne(&key))
176213
}
214+
Ok(())
177215
}
178216

179-
fn clear(&mut self) {
217+
fn clear(&mut self) -> Result<(), BackingError> {
180218
self.expiry_queue.clear();
181219
self.map.clear();
220+
Ok(())
182221
}
183222
}
184223

@@ -203,34 +242,43 @@ impl<K: Eq + Hash + Sized + Clone + Send, V: Sized + Clone + Send> TtlCacheBacki
203242
}
204243
}
205244

206-
fn replace(&mut self, key: K, value: V, expiry: Instant) -> Option<V> {
245+
fn replace(&mut self, key: K, value: V, expiry: Instant) -> Result<Option<V>, TtlError> {
207246
let entry = self.map.insert(key.clone(), (value, expiry));
208-
self.cleanup_expiry(entry, &key)
247+
let res = self.cleanup_expiry(entry, &key);
248+
match self.expiry_queue.binary_search_by_key(&expiry, |entry| entry.expiry) {
249+
Ok(found) => {
250+
self.expiry_queue.insert(found + 1, (key, expiry).into());
251+
}
252+
Err(idx) => {
253+
self.expiry_queue.insert(idx, (key, expiry).into());
254+
}
255+
}
256+
res
209257
}
210258

211-
fn remove_key(&mut self, key: &K) -> Option<V> {
259+
fn remove_key(&mut self, key: &K) -> Result<Option<V>, TtlError> {
212260
let entry = self.map.remove(key);
213261
self.cleanup_expiry(entry, key)
214262
}
215263

216-
fn cleanup_expiry(&mut self, entry: Option<(V, Instant)>, key: &K) -> Option<V> {
264+
fn cleanup_expiry(&mut self, entry: Option<(V, Instant)>, key: &K) -> Result<Option<V>, TtlError> {
217265
if let Some((value, old_expiry)) = entry {
218266
match self.expiry_queue.binary_search_by_key(&old_expiry, |entry| entry.expiry) {
219267
Ok(found) => {
220268
let index = self.expiry_index_on_key_eq(found, &old_expiry, key);
221269
if let Some(index) = index {
222270
self.expiry_queue.remove(index);
223271
} else {
224-
// expiry not found (key)???
272+
return Err(TtlError::ExpiryKeyNotFound);
225273
}
226274
}
227275
Err(_) => {
228-
// expiry not found???
276+
return Err(TtlError::ExpiryNotFound);
229277
}
230278
}
231-
Some(value)
279+
Ok(Some(value))
232280
} else {
233-
None
281+
Ok(None)
234282
}
235283
}
236284

@@ -274,32 +322,36 @@ impl<
274322
K: Eq + Hash + Sized + Clone + Send,
275323
V: Sized + Clone + Send
276324
> CacheBacking<K, V> for HashMapBacking<K, V> {
277-
fn get_mut(&mut self, key: &K) -> Option<&mut V> {
278-
self.map.get_mut(key)
325+
type Meta = NoMeta;
326+
327+
fn get_mut(&mut self, key: &K) -> Result<Option<&mut V>, BackingError> {
328+
Ok(self.map.get_mut(key))
279329
}
280330

281-
fn get(&mut self, key: &K) -> Option<&V> {
282-
self.map.get(key)
331+
fn get(&mut self, key: &K) -> Result<Option<&V>, BackingError> {
332+
Ok(self.map.get(key))
283333
}
284334

285-
fn set(&mut self, key: K, value: V) -> Option<V> {
286-
self.map.insert(key, value)
335+
fn set(&mut self, key: K, value: V, _meta: Option<Self::Meta>) -> Result<Option<V>, BackingError> {
336+
Ok(self.map.insert(key, value))
287337
}
288338

289-
fn remove(&mut self, key: &K) -> Option<V> {
290-
self.map.remove(key)
339+
fn remove(&mut self, key: &K) -> Result<Option<V>, BackingError> {
340+
Ok(self.map.remove(key))
291341
}
292342

293-
fn contains_key(&self, key: &K) -> bool {
294-
self.map.contains_key(key)
343+
fn contains_key(&self, key: &K) -> Result<bool, BackingError> {
344+
Ok(self.map.contains_key(key))
295345
}
296346

297-
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send>) {
347+
fn remove_if(&mut self, predicate: Box<dyn Fn((&K, &V)) -> bool + Send>) -> Result<(), BackingError> {
298348
self.map.retain(|k, v| !predicate((k, v)));
349+
Ok(())
299350
}
300351

301-
fn clear(&mut self) {
352+
fn clear(&mut self) -> Result<(), BackingError> {
302353
self.map.clear();
354+
Ok(())
303355
}
304356
}
305357

0 commit comments

Comments
 (0)