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}