il2_utils/cache/
mod.rs

1/*
2 * BSD 3-Clause License
3 *
4 * Copyright (c) 2019-2020, InterlockLedger Network
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice, this
11 *   list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright notice,
14 *   this list of conditions and the following disclaimer in the documentation
15 *   and/or other materials provided with the distribution.
16 *
17 * * Neither the name of the copyright holder nor the names of its
18 *   contributors may be used to endorse or promote products derived from
19 *   this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32//! This module implements a very simple associative cache that stores read-only
33//! entries associated to a key.
34use std::collections::HashMap;
35use std::hash::Hash;
36use std::sync::{Arc, RwLock};
37
38#[cfg(test)]
39mod tests;
40
41//=============================================================================
42// ValueCache
43//-----------------------------------------------------------------------------
44/// This trait is implemented by all value caches on this module. A value cache
45/// must be able to associate shared read-only values to a given key value.
46///
47/// It is up to the implementator of this trait to define how old values are
48/// prunned from the cache.
49///
50/// All methods of this trait are required to be thread safe.
51pub trait ValueCache<K: Eq + Hash + Copy + Sync, V: Send + Sync>: Send {
52    /// Gets the value from the cache if it exists.
53    ///
54    /// Arguments:
55    /// - `key`: The key to be found;
56    ///
57    /// Returns:
58    /// - `Some(v)`: The cached value. `v` is a new [`Arc`] that points to it.
59    /// - `None`: IF the entry is not in the cache;
60    fn get(&self, key: &K) -> Option<Arc<V>>;
61
62    /// Inserts the value into the cache. Reinserting a new value with the
63    /// same key will replace the existing value.
64    ///
65    /// Arguments:
66    /// - `key`: The key;
67    /// - `value`: A reference to an [`Arc`] that points to the value;
68    fn insert(&self, key: K, value: &Arc<V>);
69
70    /// Removes all entries from the cache.
71    fn clear(&self);
72
73    /// Returns the number of entries in the cache.
74    fn len(&self) -> usize;
75
76    /// Returns true if the cache is empty or false otherwise.
77    fn is_empty(&self) -> bool;
78}
79
80//=============================================================================
81// CacheEntry
82//-----------------------------------------------------------------------------
83/// This struct implements a SimpleCache entry. The value is shared by an
84/// [`Arc`] reference.
85struct SimpleCacheEntry<V: Send + Sync> {
86    value: Arc<V>,
87    counter: u64,
88}
89
90impl<V: Send + Sync> SimpleCacheEntry<V> {
91    /// Creates a new [`SimpleCacheEntry`].
92    ///
93    /// Arguments:
94    /// - `value`: The value;
95    /// - `counter`: The current counter;
96    ///
97    pub fn new(value: &Arc<V>, counter: u64) -> Self {
98        Self {
99            value: Arc::clone(value),
100            counter,
101        }
102    }
103
104    /// Returns a new [`Arc`] that points to the value.
105    pub fn get_value(&self) -> Arc<V> {
106        Arc::clone(&self.value)
107    }
108
109    /// Returns the current counter. This value can be used
110    /// to determine what entry is the oldest in this cache.
111    pub fn counter(&self) -> u64 {
112        self.counter
113    }
114
115    /// Sets the counter.
116    ///
117    /// Arguments:
118    /// - `counter`: The new counter;
119    pub fn set_counter(&mut self, counter: u64) {
120        self.counter = counter
121    }
122}
123
124//=============================================================================
125// CacheEngine
126//-----------------------------------------------------------------------------
127/// This trait is implemented by all value caches on this module. A value cache
128/// must be able to associate shared read-only values to a given key value.
129///
130/// It is up to the implementator of this trait to define how old values are
131/// prunned from the cache.
132///
133/// All methods of this trait are required to be thread safe.
134pub trait CacheEngine<K: Eq + Hash + Copy + Sync, V: Send + Sync>: Sync {
135    /// Gets the value from the cache if it exists.
136    ///
137    /// Arguments:
138    /// - `key`: The key to be found;
139    ///
140    /// Returns:
141    /// - `Some(v)`: The cached value. `v` is a new [`Arc`] that points to it.
142    /// - `None`: IF the entry is not in the cache;
143    fn get(&mut self, key: &K) -> Option<Arc<V>>;
144
145    /// Inserts the value into the cache.
146    ///
147    /// Arguments:
148    /// - `key`: The key;
149    /// - `value`: A reference to an [`Arc`] that points to the value;
150    fn insert(&mut self, key: K, value: &Arc<V>);
151
152    /// Removes all entries from the cache.
153    fn clear(&mut self);
154
155    /// Returns the number of entries in the cache.
156    fn len(&self) -> usize;
157
158    /// Returns true if the cache is empty or false otherwise.
159    fn is_empty(&self) -> bool;
160}
161
162//=============================================================================
163// SimpleCacheEngine
164//-----------------------------------------------------------------------------
165/// This struct implements the SimpleCacheEngine. It is the core of the
166/// [`SimpleCache`] implementation.
167///
168/// When it reaches its maximum capacity it will drop the oldest unused entries.
169///
170/// This struct is not thread safe and must have its concurrency protected by
171/// an external [`RwLock`] or other synchronization primitive.
172struct SimpleCacheEngine<K: Eq + Hash + Copy + Send + Sync, V: Send + Sync> {
173    map: HashMap<K, SimpleCacheEntry<V>>,
174    max_size: usize,
175    counter: u64,
176}
177
178impl<K: Eq + Hash + Copy + Send + Sync, V: Send + Sync> SimpleCacheEngine<K, V> {
179    /// Creates a new `SimpleCacheEngine` with a given capacity.
180    ///
181    /// Arguments:
182    /// - `max_size`: Maximum number of items in the cache;
183    pub fn new(max_size: usize) -> Self {
184        Self {
185            map: HashMap::new(),
186            max_size,
187            counter: 0,
188        }
189    }
190
191    /// Returns the next value of the internal counter.
192    fn next_counter(&mut self) -> u64 {
193        let ret = self.counter;
194        self.counter += 1;
195        ret
196    }
197
198    /// This method removes the entry with the smallest counter.
199    fn remove_oldest(&mut self) {
200        let mut key: Option<K> = None;
201        let mut oldest = u64::MAX;
202        for (k, v) in self.map.iter() {
203            if v.counter() < oldest {
204                key = Some(*k);
205                oldest = v.counter()
206            }
207        }
208        if let Some(k) = key {
209            self.map.remove(&k);
210        }
211    }
212}
213
214impl<K: Eq + Hash + Copy + Send + Sync, V: Send + Sync> CacheEngine<K, V>
215    for SimpleCacheEngine<K, V>
216{
217    fn get(&mut self, key: &K) -> Option<Arc<V>> {
218        let counter = self.next_counter();
219        let entry = match self.map.get_mut(key) {
220            Some(entry) => entry,
221            None => return None,
222        };
223        entry.set_counter(counter);
224        Some(entry.get_value())
225    }
226
227    fn insert(&mut self, key: K, value: &Arc<V>) {
228        let counter = self.next_counter();
229        self.map.insert(key, SimpleCacheEntry::new(value, counter));
230        if self.map.len() > self.max_size {
231            self.remove_oldest();
232        }
233    }
234
235    fn clear(&mut self) {
236        self.map.clear()
237    }
238
239    fn len(&self) -> usize {
240        self.map.len()
241    }
242
243    fn is_empty(&self) -> bool {
244        self.map.is_empty()
245    }
246}
247
248//=============================================================================
249// SimpleCache
250//-----------------------------------------------------------------------------
251/// This struct implements a simple value cache that holds up to a certain
252/// number of entries at a time.
253///
254/// When it reaches its maximum capacity it will drop the oldest unused entries.
255///
256/// All methods of this struct are thread-safe.
257pub struct SimpleCache<K: Eq + Hash + Copy + Send + Sync, V: Send + Sync> {
258    engine: RwLock<SimpleCacheEngine<K, V>>,
259}
260
261impl<K: Eq + Hash + Copy + Send + Sync, V: Send + Sync> SimpleCache<K, V> {
262    /// Creates a new SimpleCache with a given capacity.
263    ///
264    /// Arguments:
265    /// - `max_size`: Maximum number of items in the cache;
266    pub fn new(max_size: usize) -> Self {
267        Self {
268            engine: RwLock::new(SimpleCacheEngine::new(max_size)),
269        }
270    }
271}
272
273impl<K: Eq + Hash + Copy + Send + Sync, V: Send + Sync> ValueCache<K, V> for SimpleCache<K, V> {
274    fn get(&self, key: &K) -> Option<Arc<V>> {
275        let mut s = self.engine.write().unwrap();
276        s.get(key)
277    }
278
279    fn insert(&self, key: K, value: &Arc<V>) {
280        let mut s = self.engine.write().unwrap();
281        s.insert(key, value)
282    }
283
284    fn clear(&self) {
285        let mut s = self.engine.write().unwrap();
286        s.clear()
287    }
288
289    fn len(&self) -> usize {
290        let s = self.engine.read().unwrap();
291        s.len()
292    }
293
294    fn is_empty(&self) -> bool {
295        let s = self.engine.read().unwrap();
296        s.is_empty()
297    }
298}