Skip to content

Commit bd281a7

Browse files
committed
moved cache functionality to module
Signed-off-by: wadeking98 <[email protected]>
1 parent c54dc01 commit bd281a7

File tree

4 files changed

+166
-165
lines changed

4 files changed

+166
-165
lines changed

indy-vdr-proxy/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use hyper_tls::HttpsConnector;
3636
#[cfg(unix)]
3737
use hyper_unix_connector::UnixConnector;
3838

39-
use indy_vdr::pool::cache::{Cache, MemCacheStorageTTL};
39+
use indy_vdr::pool::cache::{memcache::MemCacheStorageTTL, Cache};
4040
#[cfg(feature = "tls")]
4141
use rustls_pemfile::{certs, pkcs8_private_keys};
4242
#[cfg(feature = "tls")]
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use std::{
2+
collections::{BTreeMap, HashMap},
3+
hash::Hash,
4+
};
5+
/// A hashmap that also maintains a BTreeMap of keys ordered by a given value
6+
/// This is useful for structures that need fast O(1) lookups, but also need to evict the oldest or least recently used entries
7+
pub(crate) struct OrderedHashMap<K, O, V>((HashMap<K, (O, V)>, BTreeMap<O, Vec<K>>));
8+
9+
impl<K, O, V> OrderedHashMap<K, O, V> {
10+
pub(crate) fn new() -> Self {
11+
Self((HashMap::new(), BTreeMap::new()))
12+
}
13+
}
14+
15+
impl<K: Hash + Eq + Clone, O: Ord + Copy, V> OrderedHashMap<K, O, V> {
16+
pub fn len(&self) -> usize {
17+
let (lookup, _) = &self.0;
18+
lookup.len()
19+
}
20+
pub fn get(&self, key: &K) -> Option<&(O, V)> {
21+
let (lookup, _) = &self.0;
22+
lookup.get(key)
23+
}
24+
fn get_key_value(
25+
&self,
26+
selector: Box<dyn Fn(&BTreeMap<O, Vec<K>>) -> Option<(&O, &Vec<K>)>>,
27+
) -> Option<(&K, &O, &V)> {
28+
let (lookup, ordered_lookup) = &self.0;
29+
selector(ordered_lookup).and_then(|(_, keys)| {
30+
keys.first()
31+
.and_then(|key| lookup.get(key).and_then(|(o, v)| Some((key, o, v))))
32+
})
33+
}
34+
/// gets the entry with the lowest order value
35+
pub fn get_first_key_value(&self) -> Option<(&K, &O, &V)> {
36+
self.get_key_value(Box::new(|ordered_lookup| ordered_lookup.first_key_value()))
37+
}
38+
/// gets the entry with the highest order value
39+
pub fn get_last_key_value(&self) -> Option<(&K, &O, &V)> {
40+
self.get_key_value(Box::new(|ordered_lookup| ordered_lookup.last_key_value()))
41+
}
42+
/// re-orders the entry with the given key
43+
pub fn re_order(&mut self, key: &K, new_order: O) {
44+
let (lookup, order_lookup) = &mut self.0;
45+
if let Some((old_order, _)) = lookup.get(key) {
46+
// remove entry in btree
47+
match order_lookup.get_mut(old_order) {
48+
Some(keys) => {
49+
keys.retain(|k| k != key);
50+
if keys.len() == 0 {
51+
order_lookup.remove(old_order);
52+
}
53+
}
54+
None => {}
55+
}
56+
}
57+
order_lookup
58+
.entry(new_order)
59+
.or_insert(vec![])
60+
.push(key.clone());
61+
lookup.get_mut(key).map(|(o, _)| *o = new_order);
62+
}
63+
/// inserts a new entry with the given key and value and order
64+
pub fn insert(&mut self, key: K, value: V, order: O) -> Option<V> {
65+
let (lookup, order_lookup) = &mut self.0;
66+
67+
if let Some((old_order, _)) = lookup.get(&key) {
68+
// remove entry in btree
69+
match order_lookup.get_mut(old_order) {
70+
Some(keys) => {
71+
keys.retain(|k| k != &key);
72+
if keys.len() == 0 {
73+
order_lookup.remove(old_order);
74+
}
75+
}
76+
None => {}
77+
}
78+
}
79+
order_lookup
80+
.entry(order)
81+
.or_insert(vec![])
82+
.push(key.clone());
83+
lookup
84+
.insert(key, (order, value))
85+
.and_then(|(_, v)| Some(v))
86+
}
87+
/// removes the entry with the given key
88+
pub fn remove(&mut self, key: &K) -> Option<(O, V)> {
89+
let (lookup, order_lookup) = &mut self.0;
90+
lookup.remove(key).and_then(|(order, v)| {
91+
match order_lookup.get_mut(&order) {
92+
Some(keys) => {
93+
keys.retain(|k| k != key);
94+
if keys.len() == 0 {
95+
order_lookup.remove(&order);
96+
}
97+
}
98+
None => {}
99+
}
100+
Some((order, v))
101+
})
102+
}
103+
/// removes the entry with the lowest order value
104+
pub fn remove_first(&mut self) -> Option<(K, O, V)> {
105+
let first_key = self.get_first_key_value().map(|(k, _, _)| k.clone());
106+
if let Some(first_key) = first_key {
107+
self.remove(&first_key)
108+
.map(|(order, v)| (first_key, order, v))
109+
} else {
110+
None
111+
}
112+
}
113+
}
Lines changed: 7 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,163 +1,8 @@
1+
use super::helpers::OrderedHashMap;
2+
use super::CacheStorage;
3+
use async_lock::Mutex;
14
use async_trait::async_trait;
2-
use std::{
3-
collections::{BTreeMap, HashMap},
4-
fmt::Debug,
5-
hash::Hash,
6-
sync::Arc,
7-
time::SystemTime,
8-
};
9-
10-
use async_lock::{Mutex, RwLock};
11-
12-
#[async_trait]
13-
pub trait CacheStorage<K, V>: Send + Sync + 'static {
14-
async fn get(&self, key: &K) -> Option<V>;
15-
16-
async fn remove(&mut self, key: &K) -> Option<V>;
17-
18-
async fn insert(&mut self, key: K, value: V) -> Option<V>;
19-
}
20-
21-
pub struct Cache<K, V> {
22-
storage: Arc<RwLock<dyn CacheStorage<K, V>>>,
23-
}
24-
25-
impl<K: 'static, V: 'static> Cache<K, V> {
26-
pub fn new(storage: impl CacheStorage<K, V>) -> Self {
27-
Self {
28-
storage: Arc::new(RwLock::new(storage)),
29-
}
30-
}
31-
pub async fn get(&mut self, key: &K) -> Option<V> {
32-
self.storage.read().await.get(key).await
33-
}
34-
pub async fn remove(&mut self, key: &K) -> Option<V> {
35-
self.storage.write().await.remove(key).await
36-
}
37-
pub async fn insert(&mut self, key: K, value: V) -> Option<V> {
38-
self.storage.write().await.insert(key, value).await
39-
}
40-
}
41-
42-
// need to implement Clone manually because Mutex<dyn CacheStorage> doesn't implement Clone
43-
impl<K, V> Clone for Cache<K, V> {
44-
fn clone(&self) -> Self {
45-
Self {
46-
storage: self.storage.clone(),
47-
}
48-
}
49-
}
50-
51-
/// A hashmap that also maintains a BTreeMap of keys ordered by a given value
52-
/// This is useful for structures that need fast O(1) lookups, but also need to evict the oldest or least recently used entries
53-
struct OrderedHashMap<K, O, V>((HashMap<K, (O, V)>, BTreeMap<O, Vec<K>>));
54-
55-
impl<K, O, V> OrderedHashMap<K, O, V> {
56-
fn new() -> Self {
57-
Self((HashMap::new(), BTreeMap::new()))
58-
}
59-
}
60-
61-
impl<K: Hash + Eq + Clone, O: Ord + Copy, V> OrderedHashMap<K, O, V> {
62-
fn len(&self) -> usize {
63-
let (lookup, _) = &self.0;
64-
lookup.len()
65-
}
66-
fn get(&self, key: &K) -> Option<&(O, V)> {
67-
let (lookup, _) = &self.0;
68-
lookup.get(key)
69-
}
70-
fn get_key_value(
71-
&self,
72-
selector: Box<dyn Fn(&BTreeMap<O, Vec<K>>) -> Option<(&O, &Vec<K>)>>,
73-
) -> Option<(&K, &O, &V)> {
74-
let (lookup, ordered_lookup) = &self.0;
75-
selector(ordered_lookup).and_then(|(_, keys)| {
76-
keys.first()
77-
.and_then(|key| lookup.get(key).and_then(|(o, v)| Some((key, o, v))))
78-
})
79-
}
80-
/// gets the entry with the lowest order value
81-
fn get_first_key_value(&self) -> Option<(&K, &O, &V)> {
82-
self.get_key_value(Box::new(|ordered_lookup| ordered_lookup.first_key_value()))
83-
}
84-
/// gets the entry with the highest order value
85-
fn get_last_key_value(&self) -> Option<(&K, &O, &V)> {
86-
self.get_key_value(Box::new(|ordered_lookup| ordered_lookup.last_key_value()))
87-
}
88-
/// re-orders the entry with the given key
89-
fn re_order(&mut self, key: &K, new_order: O) {
90-
let (lookup, order_lookup) = &mut self.0;
91-
if let Some((old_order, _)) = lookup.get(key) {
92-
// remove entry in btree
93-
match order_lookup.get_mut(old_order) {
94-
Some(keys) => {
95-
keys.retain(|k| k != key);
96-
if keys.len() == 0 {
97-
order_lookup.remove(old_order);
98-
}
99-
}
100-
None => {}
101-
}
102-
}
103-
order_lookup
104-
.entry(new_order)
105-
.or_insert(vec![])
106-
.push(key.clone());
107-
lookup.get_mut(key).map(|(o, _)| *o = new_order);
108-
}
109-
/// inserts a new entry with the given key and value and order
110-
fn insert(&mut self, key: K, value: V, order: O) -> Option<V> {
111-
let (lookup, order_lookup) = &mut self.0;
112-
113-
if let Some((old_order, _)) = lookup.get(&key) {
114-
// remove entry in btree
115-
match order_lookup.get_mut(old_order) {
116-
Some(keys) => {
117-
keys.retain(|k| k != &key);
118-
if keys.len() == 0 {
119-
order_lookup.remove(old_order);
120-
}
121-
}
122-
None => {}
123-
}
124-
}
125-
order_lookup
126-
.entry(order)
127-
.or_insert(vec![])
128-
.push(key.clone());
129-
lookup
130-
.insert(key, (order, value))
131-
.and_then(|(_, v)| Some(v))
132-
}
133-
/// removes the entry with the given key
134-
fn remove(&mut self, key: &K) -> Option<(O, V)> {
135-
let (lookup, order_lookup) = &mut self.0;
136-
lookup.remove(key).and_then(|(order, v)| {
137-
match order_lookup.get_mut(&order) {
138-
Some(keys) => {
139-
keys.retain(|k| k != key);
140-
if keys.len() == 0 {
141-
order_lookup.remove(&order);
142-
}
143-
}
144-
None => {}
145-
}
146-
Some((order, v))
147-
})
148-
}
149-
/// removes the entry with the lowest order value
150-
fn remove_first(&mut self) -> Option<(K, O, V)> {
151-
let first_key = self.get_first_key_value().map(|(k, _, _)| k.clone());
152-
if let Some(first_key) = first_key {
153-
self.remove(&first_key)
154-
.map(|(order, v)| (first_key, order, v))
155-
} else {
156-
None
157-
}
158-
}
159-
}
160-
5+
use std::{hash::Hash, sync::Arc, time::SystemTime};
1616
/// A simple in-memory cache that uses timestamps to expire entries. Once the cache fills up, the oldest entry is evicted.
1627
/// Uses a hashmap for lookups and a BTreeMap for ordering by age
1638
pub struct MemCacheStorageTTL<K, V> {
@@ -180,7 +25,7 @@ impl<K, V> MemCacheStorageTTL<K, V> {
18025
}
18126

18227
#[async_trait]
183-
impl<K: Hash + Eq + Send + Sync + 'static + Clone + Debug, V: Clone + Send + Sync + 'static>
28+
impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Clone + Send + Sync + 'static>
18429
CacheStorage<K, V> for MemCacheStorageTTL<K, V>
18530
{
18631
async fn get(&self, key: &K) -> Option<V> {
@@ -294,12 +139,12 @@ mod tests {
294139

295140
use std::thread;
296141

142+
use super::*;
143+
use crate::pool::cache::Cache;
297144
use futures_executor::block_on;
298145

299146
#[rstest]
300147
fn test_cache_lru() {
301-
use super::*;
302-
303148
let mut cache = Cache::new(MemCacheStorageLRU::new(2));
304149
block_on(async {
305150
cache.insert("key".to_string(), "value".to_string()).await;
@@ -325,8 +170,6 @@ mod tests {
325170

326171
#[rstest]
327172
fn test_cache_ttl() {
328-
use super::*;
329-
330173
let mut cache = Cache::new(MemCacheStorageTTL::new(2, 5));
331174
block_on(async {
332175
cache.insert("key".to_string(), "value".to_string()).await;

libindy_vdr/src/pool/cache/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use async_lock::RwLock;
2+
use async_trait::async_trait;
3+
use std::sync::Arc;
4+
5+
mod helpers;
6+
pub mod memcache;
7+
8+
#[async_trait]
9+
pub trait CacheStorage<K, V>: Send + Sync + 'static {
10+
async fn get(&self, key: &K) -> Option<V>;
11+
12+
async fn remove(&mut self, key: &K) -> Option<V>;
13+
14+
async fn insert(&mut self, key: K, value: V) -> Option<V>;
15+
}
16+
17+
pub struct Cache<K, V> {
18+
storage: Arc<RwLock<dyn CacheStorage<K, V>>>,
19+
}
20+
21+
impl<K: 'static, V: 'static> Cache<K, V> {
22+
pub fn new(storage: impl CacheStorage<K, V>) -> Self {
23+
Self {
24+
storage: Arc::new(RwLock::new(storage)),
25+
}
26+
}
27+
pub async fn get(&mut self, key: &K) -> Option<V> {
28+
self.storage.read().await.get(key).await
29+
}
30+
pub async fn remove(&mut self, key: &K) -> Option<V> {
31+
self.storage.write().await.remove(key).await
32+
}
33+
pub async fn insert(&mut self, key: K, value: V) -> Option<V> {
34+
self.storage.write().await.insert(key, value).await
35+
}
36+
}
37+
38+
// need to implement Clone manually because Mutex<dyn CacheStorage> doesn't implement Clone
39+
impl<K, V> Clone for Cache<K, V> {
40+
fn clone(&self) -> Self {
41+
Self {
42+
storage: self.storage.clone(),
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)