1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
//! memory store module.
use std::borrow::Borrow;
use std::convert::Infallible;
use std::hash::Hash;
use std::sync::Arc;
use std::time::Duration;
use moka::future::Cache as MokaCache;
use moka::future::CacheBuilder as MokaCacheBuilder;
use moka::notification::RemovalCause;
use super::{CacheStore, CachedEntry};
/// A builder for [`MokaStore`].
pub struct Builder<K> {
inner: MokaCacheBuilder<K, CachedEntry, MokaCache<K, CachedEntry>>,
}
impl<K> Builder<K>
where
K: Hash + Eq + Send + Sync + Clone + 'static,
{
/// Sets the initial capacity (number of entries) of the cache.
pub fn initial_capacity(mut self, capacity: usize) -> Self {
self.inner = self.inner.initial_capacity(capacity);
self
}
/// Sets the max capacity of the cache.
pub fn max_capacity(mut self, capacity: u64) -> Self {
self.inner = self.inner.max_capacity(capacity);
self
}
/// Sets the time to idle of the cache.
///
/// A cached entry will be expired after the specified duration past from `get`
/// or `insert`.
///
/// # Panics
///
/// `CacheBuilder::build*` methods will panic if the given `duration` is longer
/// than 1000 years. This is done to protect against overflow when computing key
/// expiration.
pub fn time_to_idle(mut self, duration: Duration) -> Self {
self.inner = self.inner.time_to_idle(duration);
self
}
/// Sets the time to live of the cache.
///
/// A cached entry will be expired after the specified duration past from
/// `insert`.
///
/// # Panics
///
/// `CacheBuilder::build*` methods will panic if the given `duration` is longer
/// than 1000 years. This is done to protect against overflow when computing key
/// expiration.
pub fn time_to_live(mut self, duration: Duration) -> Self {
self.inner = self.inner.time_to_live(duration);
self
}
/// Sets the eviction listener closure to the cache.
///
/// # Panics
///
/// It is very important to make the listener closure not to panic. Otherwise,
/// the cache will stop calling the listener after a panic. This is an intended
/// behavior because the cache cannot know whether is memory safe or not to
/// call the panicked lister again.
pub fn eviction_listener(
mut self,
listener: impl Fn(Arc<K>, CachedEntry, RemovalCause) + Send + Sync + 'static,
) -> Self {
self.inner = self.inner.eviction_listener(listener);
self
}
/// Build a [`MokaStore`].
///
/// # Panics
///
/// Panics if configured with either `time_to_live` or `time_to_idle` higher than
/// 1000 years. This is done to protect against overflow when computing key
/// expiration.
pub fn build(self) -> MokaStore<K> {
MokaStore {
inner: self.inner.build(),
}
}
}
/// A simple in-memory store for rate limiter.
pub struct MokaStore<K> {
inner: MokaCache<K, CachedEntry>,
}
impl<K> MokaStore<K>
where
K: Hash + Eq + Send + Sync + Clone + 'static,
{
/// Create a new `MokaStore`.
pub fn new(max_capacity: u64) -> Self {
Self {
inner: MokaCache::new(max_capacity),
}
}
/// Returns a [`Builder`], which can builds a `MokaStore`
pub fn builder() -> Builder<K> {
Builder {
inner: MokaCache::builder(),
}
}
}
impl<K> CacheStore for MokaStore<K>
where
K: Hash + Eq + Send + Sync + Clone + 'static,
{
type Error = Infallible;
type Key = K;
async fn load_entry<Q>(&self, key: &Q) -> Option<CachedEntry>
where
Self::Key: Borrow<Q>,
Q: Hash + Eq + Sync,
{
self.inner.get(key).await
}
async fn save_entry(&self, key: Self::Key, entry: CachedEntry) -> Result<(), Self::Error> {
self.inner.insert(key, entry).await;
Ok(())
}
}