use futures::stream::Stream;
use lru::LruCache;
use std::borrow::Borrow;
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::Rev;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::time::{Duration, Instant};
use crate::lockable_map_impl::{Entry, EntryValue, LockableMapConfig};
use crate::utils::primary_arc::PrimaryArc;
use super::guard::Guard;
use super::limit::{AsyncLimit, SyncLimit};
use super::lockable_map_impl::LockableMapImpl;
use super::lockable_trait::Lockable;
use super::map_like::{GetOrInsertNoneResult, MapLike};
use super::utils::time::{RealTime, TimeProvider};
impl<K, V> MapLike<K, Entry<V>> for LruCache<K, Entry<V>>
where
K: Eq + PartialEq + Hash + Clone,
{
type ItemIter<'a>
= Rev<lru::Iter<'a, K, Entry<V>>>
where
K: 'a,
V: 'a;
fn new() -> Self {
Self::unbounded()
}
fn len(&self) -> usize {
self.iter().len()
}
fn get_or_insert_none(&mut self, key: &K) -> GetOrInsertNoneResult<Entry<V>> {
let mut was_inserted = false;
let entry = self.get_or_insert(key.clone(), || {
was_inserted = true;
PrimaryArc::new(Mutex::new(EntryValue { value: None }))
});
if was_inserted {
GetOrInsertNoneResult::Inserted(entry)
} else {
GetOrInsertNoneResult::Existing(entry)
}
}
fn get(&mut self, key: &K) -> Option<&Entry<V>> {
LruCache::get(self, key)
}
fn remove(&mut self, key: &K) -> Option<Entry<V>> {
self.pop(key)
}
fn iter(&self) -> Self::ItemIter<'_> {
LruCache::iter(self).rev()
}
}
pub struct LockableLruCacheConfig<Time>
where
Time: TimeProvider + Clone,
{
time_provider: Time,
}
impl<Time> Clone for LockableLruCacheConfig<Time>
where
Time: TimeProvider + Clone,
{
fn clone(&self) -> Self {
Self {
time_provider: self.time_provider.clone(),
}
}
}
impl<Time> LockableMapConfig for LockableLruCacheConfig<Time>
where
Time: TimeProvider + Clone,
{
type WrappedV<V> = CacheEntry<V>;
type MapImpl<K, V>
= LruCache<K, Entry<CacheEntry<V>>>
where
K: Eq + PartialEq + Hash + Clone;
fn borrow_value<V>(v: &CacheEntry<V>) -> &V {
&v.value
}
fn borrow_value_mut<V>(v: &mut CacheEntry<V>) -> &mut V {
&mut v.value
}
fn wrap_value<V>(&self, value: V) -> CacheEntry<V> {
CacheEntry {
value,
last_unlocked: self.time_provider.now(),
}
}
fn unwrap_value<V>(v: CacheEntry<V>) -> V {
v.value
}
fn on_unlock<V>(&self, v: Option<&mut CacheEntry<V>>) {
if let Some(v) = v {
v.last_unlocked = self.time_provider.now();
}
}
}
#[derive(Debug)]
pub struct CacheEntry<V> {
value: V,
last_unlocked: Instant,
}
#[derive(Debug)]
pub struct LockableLruCache<K, V, Time = RealTime>
where
K: Eq + PartialEq + Hash + Clone,
Time: TimeProvider + Default + Clone,
{
map_impl: LockableMapImpl<K, V, LockableLruCacheConfig<Time>>,
}
impl<K, V, Time> Lockable<K, V> for LockableLruCache<K, V, Time>
where
K: Eq + PartialEq + Hash + Clone,
Time: TimeProvider + Default + Clone,
{
type Guard<'a>
= Guard<
K,
V,
LockableLruCacheConfig<Time>,
&'a LockableMapImpl<K, V, LockableLruCacheConfig<Time>>,
>
where
K: 'a,
V: 'a,
Time: 'a;
type OwnedGuard = Guard<K, V, LockableLruCacheConfig<Time>, Arc<LockableLruCache<K, V, Time>>>;
type SyncLimit<'a, OnEvictFn, E>
= SyncLimit<
K,
V,
LockableLruCacheConfig<Time>,
&'a LockableMapImpl<K, V, LockableLruCacheConfig<Time>>,
E,
OnEvictFn,
>
where
OnEvictFn: FnMut(Vec<Self::Guard<'a>>) -> Result<(), E>,
K: 'a,
V: 'a,
Time: 'a;
type SyncLimitOwned<OnEvictFn, E>
= SyncLimit<
K,
V,
LockableLruCacheConfig<Time>,
Arc<LockableLruCache<K, V, Time>>,
E,
OnEvictFn,
>
where
OnEvictFn: FnMut(Vec<Self::OwnedGuard>) -> Result<(), E>;
type AsyncLimit<'a, OnEvictFn, E, F>
= AsyncLimit<
K,
V,
LockableLruCacheConfig<Time>,
&'a LockableMapImpl<K, V, LockableLruCacheConfig<Time>>,
E,
F,
OnEvictFn,
>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<Self::Guard<'a>>) -> F,
K: 'a,
V: 'a,
Time: 'a;
type AsyncLimitOwned<OnEvictFn, E, F>
= AsyncLimit<
K,
V,
LockableLruCacheConfig<Time>,
Arc<LockableLruCache<K, V, Time>>,
E,
F,
OnEvictFn,
>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<Self::OwnedGuard>) -> F;
}
impl<K, V, Time> LockableLruCache<K, V, Time>
where
K: Eq + PartialEq + Hash + Clone,
Time: TimeProvider + Default + Clone,
{
#[inline]
pub fn new() -> Self {
let time_provider = Time::default();
Self {
map_impl: LockableMapImpl::new(LockableLruCacheConfig { time_provider }),
}
}
#[inline]
pub fn num_entries_or_locked(&self) -> usize {
self.map_impl.num_entries_or_locked()
}
#[inline]
pub fn blocking_lock<'a, E, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimit<'a, OnEvictFn, E>,
) -> Result<<Self as Lockable<K, V>>::Guard<'a>, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> Result<(), E>,
{
LockableMapImpl::blocking_lock(&self.map_impl, key, limit)
}
#[inline]
pub fn blocking_lock_owned<E, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimitOwned<OnEvictFn, E>,
) -> Result<<Self as Lockable<K, V>>::OwnedGuard, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> Result<(), E>,
{
LockableMapImpl::blocking_lock(Arc::clone(self), key, limit)
}
#[inline]
pub fn try_lock<'a, E, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimit<'a, OnEvictFn, E>,
) -> Result<Option<<Self as Lockable<K, V>>::Guard<'a>>, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> Result<(), E>,
{
LockableMapImpl::try_lock(&self.map_impl, key, limit)
}
#[inline]
pub fn try_lock_owned<E, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimitOwned<OnEvictFn, E>,
) -> Result<Option<<Self as Lockable<K, V>>::OwnedGuard>, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> Result<(), E>,
{
LockableMapImpl::try_lock(Arc::clone(self), key, limit)
}
#[inline]
pub async fn try_lock_async<'a, E, F, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimit<'a, OnEvictFn, E, F>,
) -> Result<Option<<Self as Lockable<K, V>>::Guard<'a>>, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> F,
{
LockableMapImpl::try_lock_async(&self.map_impl, key, limit).await
}
#[inline]
pub async fn try_lock_owned_async<E, F, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimitOwned<OnEvictFn, E, F>,
) -> Result<Option<<Self as Lockable<K, V>>::OwnedGuard>, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> F,
{
LockableMapImpl::try_lock_async(Arc::clone(self), key, limit).await
}
#[inline]
pub async fn async_lock<'a, E, F, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimit<'a, OnEvictFn, E, F>,
) -> Result<<Self as Lockable<K, V>>::Guard<'a>, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> F,
{
LockableMapImpl::async_lock(&self.map_impl, key, limit).await
}
#[inline]
pub async fn async_lock_owned<E, F, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimitOwned<OnEvictFn, E, F>,
) -> Result<<Self as Lockable<K, V>>::OwnedGuard, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> F,
{
LockableMapImpl::async_lock(Arc::clone(self), key, limit).await
}
#[inline]
pub fn into_entries_unordered(self) -> impl Iterator<Item = (K, V)> {
self.map_impl
.into_entries_unordered()
.map(|(k, v)| (k, v.value))
}
#[inline]
pub fn keys_with_entries_or_locked(&self) -> Vec<K> {
self.map_impl.keys_with_entries_or_locked()
}
pub async fn lock_all_entries(
&self,
) -> impl Stream<Item = <Self as Lockable<K, V>>::Guard<'_>> {
LockableMapImpl::lock_all_entries(&self.map_impl).await
}
pub async fn lock_all_entries_owned(
self: &Arc<Self>,
) -> impl Stream<Item = <Self as Lockable<K, V>>::OwnedGuard> + use<K, V, Time> {
LockableMapImpl::lock_all_entries(Arc::clone(self)).await
}
pub fn lock_entries_unlocked_for_at_least(
&self,
duration: Duration,
) -> impl Iterator<Item = <Self as Lockable<K, V>>::Guard<'_>> {
Self::_lock_entries_unlocked_for_at_least(
&self.map_impl,
self.map_impl.config().time_provider.now(),
duration,
)
}
pub fn lock_entries_unlocked_for_at_least_owned(
self: &Arc<Self>,
duration: Duration,
) -> impl Iterator<Item = <Self as Lockable<K, V>>::OwnedGuard> + use<K, V, Time> {
Self::_lock_entries_unlocked_for_at_least(
Arc::clone(self),
self.map_impl.config().time_provider.now(),
duration,
)
}
fn _lock_entries_unlocked_for_at_least<
S: Borrow<LockableMapImpl<K, V, LockableLruCacheConfig<Time>>> + Clone,
>(
this: S,
now: Instant,
duration: Duration,
) -> impl Iterator<Item = Guard<K, V, LockableLruCacheConfig<Time>, S>> {
let cutoff = now - duration;
LockableMapImpl::lock_all_unlocked(this, &move |entry| {
let entry = entry.value_raw().expect("There must be a value, otherwise it cannot exist in the map as an 'unlocked' entry");
entry.last_unlocked <= cutoff
}).into_iter()
}
#[cfg(test)]
fn time_provider(&self) -> &Time {
&self.map_impl.config().time_provider
}
}
impl<K, V, Time> Default for LockableLruCache<K, V, Time>
where
K: Eq + PartialEq + Hash + Clone,
Time: TimeProvider + Default + Clone,
{
fn default() -> Self {
Self::new()
}
}
impl<K, V, Time> Borrow<LockableMapImpl<K, V, LockableLruCacheConfig<Time>>>
for Arc<LockableLruCache<K, V, Time>>
where
K: Eq + PartialEq + Hash + Clone,
Time: TimeProvider + Default + Clone,
{
fn borrow(&self) -> &LockableMapImpl<K, V, LockableLruCacheConfig<Time>> {
&self.map_impl
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::instantiate_lockable_tests;
use crate::utils::time::MockTime;
instantiate_lockable_tests!(LockableLruCache);
macro_rules! instantiate_lock_entries_unlocked_for_at_least_tests {
($create_map:expr, $lock_entries_unlocked_for_at_least:ident) => {
#[test]
fn zero_entries() {
let map = $create_map;
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
assert_eq!(Vec::<(i64, String)>::new(), old_enough);
}
#[tokio::test]
async fn one_entry_not_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
assert_eq!(Vec::<(i64, String)>::new(), old_enough);
}
#[tokio::test]
async fn one_entry_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.time_provider().advance_time(Duration::from_secs(1));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1"))],
old_enough,
);
}
#[tokio::test]
async fn one_entry_locked() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.time_provider().advance_time(Duration::from_secs(1));
let _guard = map.async_lock(1, AsyncLimit::no_limit()).await.unwrap();
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(vec![], old_enough);
}
#[tokio::test]
async fn two_entries_zero_old_enough_zero_locked() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
assert_eq!(Vec::<(i64, String)>::new(), old_enough);
}
#[tokio::test]
async fn two_entries_one_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.time_provider().advance_time(Duration::from_secs(1));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1"))],
old_enough,
);
}
#[tokio::test]
async fn two_entries_one_old_enough_and_locked() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.time_provider().advance_time(Duration::from_secs(1));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
let _guard = map.async_lock(1, AsyncLimit::no_limit()).await.unwrap();
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(vec![], old_enough);
}
#[tokio::test]
async fn two_entries_both_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.time_provider().advance_time(Duration::from_secs(1));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1")), (2, String::from("Value 2"))],
old_enough,
);
}
#[tokio::test]
async fn two_entries_both_old_enough_one_locked_1() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.time_provider().advance_time(Duration::from_secs(1));
let _guard = map.async_lock(1, AsyncLimit::no_limit()).await.unwrap();
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(2, String::from("Value 2"))],
old_enough,
);
}
#[tokio::test]
async fn two_entries_both_old_enough_one_locked_2() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.time_provider().advance_time(Duration::from_secs(1));
let _guard = map.async_lock(2, AsyncLimit::no_limit()).await.unwrap();
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1"))],
old_enough,
);
}
#[tokio::test]
async fn two_entries_both_old_enough_both_locked() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.time_provider().advance_time(Duration::from_secs(1));
let _guard1 = map.async_lock(1, AsyncLimit::no_limit()).await.unwrap();
let _guard2 = map.async_lock(2, AsyncLimit::no_limit()).await.unwrap();
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(vec![], old_enough);
}
#[tokio::test]
async fn three_entries_zero_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.async_lock(3, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 3"));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
assert_eq!(Vec::<(i64, String)>::new(), old_enough);
}
#[tokio::test]
async fn three_entries_one_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.time_provider().advance_time(Duration::from_secs(1));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.async_lock(3, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 3"));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1"))],
old_enough,
);
}
#[tokio::test]
async fn three_entries_two_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.time_provider().advance_time(Duration::from_secs(1));
map.async_lock(3, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 3"));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1")), (2, String::from("Value 2"))],
old_enough,
);
}
#[tokio::test]
async fn three_entries_three_old_enough() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.async_lock(3, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 3"));
map.time_provider().advance_time(Duration::from_secs(1));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![
(1, String::from("Value 1")),
(2, String::from("Value 2")),
(3, String::from("Value 3")),
],
old_enough,
);
}
#[tokio::test]
async fn locking_an_entry_makes_it_not_old_enough_anymore_1() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.async_lock(3, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 3"));
map.time_provider().advance_time(Duration::from_secs(1));
let guard = map.async_lock(1, AsyncLimit::no_limit()).await.unwrap();
std::mem::drop(guard);
map.time_provider().advance_time(Duration::from_millis(100));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(2, String::from("Value 2")), (3, String::from("Value 3"))],
old_enough,
);
}
#[tokio::test]
async fn locking_an_entry_makes_it_not_old_enough_anymore_2() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.async_lock(3, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 3"));
map.time_provider().advance_time(Duration::from_secs(1));
let guard = map.async_lock(2, AsyncLimit::no_limit()).await.unwrap();
std::mem::drop(guard);
map.time_provider().advance_time(Duration::from_millis(100));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1")), (3, String::from("Value 3"))],
old_enough,
);
}
#[tokio::test]
async fn locking_an_entry_makes_it_not_old_enough_anymore_3() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.async_lock(3, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 3"));
map.time_provider().advance_time(Duration::from_secs(1));
let guard = map.async_lock(3, AsyncLimit::no_limit()).await.unwrap();
std::mem::drop(guard);
map.time_provider().advance_time(Duration::from_millis(100));
let old_enough: Vec<(i64, String)> = map
.$lock_entries_unlocked_for_at_least(Duration::from_millis(500))
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1")), (2, String::from("Value 2"))],
old_enough,
);
}
#[tokio::test]
async fn can_lock_other_elements_while_iterator_is_running() {
let map = $create_map;
map.async_lock(1, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 1"));
map.time_provider().advance_time(Duration::from_secs(1));
map.async_lock(2, AsyncLimit::no_limit())
.await
.unwrap()
.insert(String::from("Value 2"));
map.time_provider().advance_time(Duration::from_millis(100));
let old_enough_iterator =
map.$lock_entries_unlocked_for_at_least(Duration::from_millis(500));
let guard = map.async_lock(2, AsyncLimit::no_limit()).await.unwrap();
std::mem::drop(guard);
let old_enough: Vec<(i64, String)> = old_enough_iterator
.map(|guard| (*guard.key(), guard.value().cloned().unwrap()))
.collect();
crate::tests::assert_vec_eq_unordered(
vec![(1, String::from("Value 1"))],
old_enough,
);
}
};
}
mod lock_entries_unlocked_for_at_least {
use super::*;
instantiate_lock_entries_unlocked_for_at_least_tests!(
LockableLruCache::<i64, String, MockTime>::new(),
lock_entries_unlocked_for_at_least
);
}
mod lock_entries_unlocked_for_at_least_owned {
use super::*;
instantiate_lock_entries_unlocked_for_at_least_tests!(
Arc::new(LockableLruCache::<i64, String, MockTime>::new()),
lock_entries_unlocked_for_at_least_owned
);
}
#[test]
fn test_default() {
let lockable_map: LockableLruCache<i64, String> = Default::default();
assert_eq!(0, lockable_map.num_entries_or_locked());
}
}