Skip to main content

miden_node_utils/
lru_cache.rs

1use std::hash::Hash;
2use std::num::NonZeroUsize;
3use std::sync::{Arc, Mutex, MutexGuard};
4
5use lru::LruCache as InnerCache;
6use tracing::instrument;
7
8/// A newtype wrapper around an LRU cache. Ensures that the cache lock is not held across
9/// await points.
10#[derive(Clone)]
11pub struct LruCache<K, V>(Arc<Mutex<InnerCache<K, V>>>);
12
13impl<K, V> LruCache<K, V>
14where
15    K: Hash + Eq,
16    V: Clone,
17{
18    /// Creates a new cache with the given capacity.
19    pub fn new(capacity: NonZeroUsize) -> Self {
20        Self(Arc::new(Mutex::new(InnerCache::new(capacity))))
21    }
22
23    /// Retrieves a value from the cache.
24    pub fn get(&self, key: &K) -> Option<V> {
25        self.lock().get(key).cloned()
26    }
27
28    /// Puts a value into the cache.
29    pub fn put(&self, key: K, value: V) {
30        self.lock().put(key, value);
31    }
32
33    /// Retrieves multiple values from the cache while holding the cache lock once.
34    pub fn get_many<'a>(&self, keys: impl IntoIterator<Item = &'a K>) -> Vec<Option<V>>
35    where
36        K: 'a,
37    {
38        let mut cache = self.lock();
39        keys.into_iter().map(|key| cache.get(key).cloned()).collect()
40    }
41
42    /// Puts multiple values into the cache while holding the cache lock once.
43    pub fn put_many(&self, entries: impl IntoIterator<Item = (K, V)>) {
44        let mut cache = self.lock();
45        for (key, value) in entries {
46            cache.put(key, value);
47        }
48    }
49
50    /// Clears all entries from the cache.
51    pub fn clear(&self) {
52        self.lock().clear();
53    }
54
55    #[instrument(name = "lru.lock", skip_all)]
56    fn lock(&self) -> MutexGuard<'_, InnerCache<K, V>> {
57        // SAFETY: The mutex is only held for the duration of the get/put operation
58        // where panics are possible only if we're running out of memory, in which
59        // case the entire process is likely to be unstable anyway.
60        self.0.lock().expect("LRU cache mutex poisoned")
61    }
62}