massa_module_cache/
lru_cache.rs

1use massa_hash::Hash;
2use massa_models::prehash::BuildHashMapper;
3use schnellru::{ByLength, LruMap};
4use tracing::debug;
5
6use crate::types::ModuleInfo;
7
8/// `LruMap` specialization for `PreHashed` keys
9pub type PreHashLruMap<K, V> = LruMap<K, V, ByLength, BuildHashMapper<K>>;
10
11/// RAM stored LRU cache.
12/// The LRU caching scheme is to remove the least recently used module when the cache is full.
13///
14/// It is composed of:
15/// * key: raw bytecode (which is hashed on insertion in LruMap)
16/// * value.0: corresponding compiled module
17/// * value.1: instance initialization cost
18pub(crate) struct LRUCache {
19    pub cache: PreHashLruMap<Hash, ModuleInfo>,
20}
21
22impl LRUCache {
23    /// Create a new `LRUCache` with the given size
24    pub fn new(cache_size: u32) -> Self {
25        LRUCache {
26            cache: LruMap::with_hasher(ByLength::new(cache_size), BuildHashMapper::default()),
27        }
28    }
29
30    pub fn reset(&mut self) {
31        self.cache.clear();
32    }
33
34    /// If the module is contained in the cache:
35    /// * retrieve a copy of it
36    /// * move it up in the LRU cache
37    pub fn get(&mut self, hash: Hash) -> Option<ModuleInfo> {
38        self.cache.get(&hash).cloned()
39    }
40
41    /// Save a module in the LRU cache
42    pub fn insert(&mut self, hash: Hash, module_info: ModuleInfo) {
43        self.cache.insert(hash, module_info);
44        debug!("(LRU insert) length is: {}", self.cache.len());
45    }
46
47    /// Set the initialization cost of a LRU cached module
48    pub fn set_init_cost(&mut self, hash: Hash, init_cost: u64) {
49        if let Some(content) = self.cache.get(&hash) {
50            match content {
51                ModuleInfo::Module(module) => {
52                    *content = ModuleInfo::ModuleAndDelta((module.clone(), init_cost))
53                }
54                ModuleInfo::ModuleAndDelta((_module, delta)) => *delta = init_cost,
55                ModuleInfo::Invalid(err_msg) => {
56                    debug!(
57                        "tried to set the init cost of an invalid module. Invalidity reason: {}",
58                        err_msg
59                    );
60                }
61            }
62        }
63    }
64
65    /// Set a module as invalid
66    pub fn set_invalid(&mut self, hash: Hash, err_msg: String) {
67        if let Some(content) = self.cache.get(&hash) {
68            *content = ModuleInfo::Invalid(err_msg);
69        }
70    }
71}