linera_views/
lru_prefix_cache.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! An LRU cache that supports prefix-search APIs.
5
6use std::collections::{btree_map::Entry, hash_map::RandomState, BTreeMap, BTreeSet};
7
8use linked_hash_map::LinkedHashMap;
9use serde::{Deserialize, Serialize};
10
11use crate::common::get_key_range_for_prefix;
12
13/// The parametrization of the cache.
14#[derive(Clone, Debug, Serialize, Deserialize)]
15pub struct StorageCacheConfig {
16    /// The maximum size of the cache, in bytes (keys size + value sizes).
17    pub max_cache_size: usize,
18    /// The maximum size of a value entry size, in bytes.
19    pub max_value_entry_size: usize,
20    /// The maximum size of a find-keys entry size, in bytes.
21    pub max_find_keys_entry_size: usize,
22    /// The maximum size of a find-key-values entry size, in bytes.
23    pub max_find_key_values_entry_size: usize,
24    /// The maximum number of entries in the cache.
25    pub max_cache_entries: usize,
26    /// The maximum size of cached values.
27    pub max_cache_value_size: usize,
28    /// The maximum size of cached `find_keys_by_prefix` results.
29    pub max_cache_find_keys_size: usize,
30    /// The maximum size of cached `find_key_values_by_prefix` results.
31    pub max_cache_find_key_values_size: usize,
32}
33
34#[derive(Eq, Hash, PartialEq, Debug)]
35enum CacheKey {
36    Value(Vec<u8>),
37    FindKeys(Vec<u8>),
38    FindKeyValues(Vec<u8>),
39}
40
41enum ValueEntry {
42    DoesNotExist,
43    Exists,
44    Value(Vec<u8>),
45}
46
47impl ValueEntry {
48    fn size(&self) -> usize {
49        match self {
50            ValueEntry::Value(vec) => vec.len(),
51            _ => 0,
52        }
53    }
54}
55
56struct FindKeysEntry(BTreeSet<Vec<u8>>);
57
58impl FindKeysEntry {
59    fn size(&self) -> usize {
60        self.0.iter().map(Vec::len).sum()
61    }
62
63    fn get_keys_by_prefix(&self, key_prefix: Vec<u8>) -> Vec<Vec<u8>> {
64        let prefix_len = key_prefix.len();
65        self.0
66            .range(get_key_range_for_prefix(key_prefix))
67            .map(|key| key[prefix_len..].to_vec())
68            .collect()
69    }
70
71    fn contains_key(&self, key: &[u8]) -> bool {
72        self.0.contains(key)
73    }
74
75    fn update_entry(&mut self, key: &[u8], is_some: bool) {
76        if is_some {
77            self.0.insert(key.to_vec());
78        } else {
79            self.0.remove(key);
80        }
81    }
82
83    fn delete_prefix(&mut self, key_prefix: &[u8]) {
84        let keys = self
85            .0
86            .range(get_key_range_for_prefix(key_prefix.to_vec()))
87            .cloned()
88            .collect::<Vec<_>>();
89        for key in keys {
90            self.0.remove(&key);
91        }
92    }
93}
94
95struct FindKeyValuesEntry(BTreeMap<Vec<u8>, Vec<u8>>);
96
97impl FindKeyValuesEntry {
98    fn size(&self) -> usize {
99        self.0
100            .iter()
101            .map(|(key, value)| key.len() + value.len())
102            .sum()
103    }
104
105    fn get_keys_by_prefix(&self, key_prefix: Vec<u8>) -> Vec<Vec<u8>> {
106        let prefix_len = key_prefix.len();
107        self.0
108            .range(get_key_range_for_prefix(key_prefix))
109            .map(|(key, _)| key[prefix_len..].to_vec())
110            .collect()
111    }
112
113    fn get_find_key_values(&self, key_prefix: &[u8]) -> Vec<(Vec<u8>, Vec<u8>)> {
114        let key_prefix = key_prefix.to_vec();
115        let prefix_len = key_prefix.len();
116        self.0
117            .range(get_key_range_for_prefix(key_prefix))
118            .map(|(key, value)| (key[prefix_len..].to_vec(), value.to_vec()))
119            .collect()
120    }
121
122    fn contains_key(&self, key: &[u8]) -> bool {
123        self.0.contains_key(key)
124    }
125
126    fn get_read_value(&self, key: &[u8]) -> Option<Vec<u8>> {
127        self.0.get(key).cloned()
128    }
129
130    fn update_entry(&mut self, key: &[u8], new_value: Option<Vec<u8>>) {
131        match new_value {
132            None => {
133                self.0.remove(key);
134            }
135            Some(new_value) => {
136                self.0.insert(key.to_vec(), new_value);
137            }
138        }
139    }
140
141    fn delete_prefix(&mut self, key_prefix: &[u8]) {
142        let keys = self
143            .0
144            .range(get_key_range_for_prefix(key_prefix.to_vec()))
145            .map(|(key, _)| key.clone())
146            .collect::<Vec<_>>();
147        for key in keys {
148            self.0.remove(&key);
149        }
150    }
151}
152
153/// Stores the data for simple `read_values` queries.
154///
155/// This data structure is inspired by the crate `lru-cache` but was modified to support
156/// range deletions.
157pub(crate) struct LruPrefixCache {
158    value_map: BTreeMap<Vec<u8>, ValueEntry>,
159    find_keys_map: BTreeMap<Vec<u8>, FindKeysEntry>,
160    find_key_values_map: BTreeMap<Vec<u8>, FindKeyValuesEntry>,
161    queue: LinkedHashMap<CacheKey, usize, RandomState>,
162    config: StorageCacheConfig,
163    total_size: usize,
164    total_value_size: usize,
165    total_find_keys_size: usize,
166    total_find_key_values_size: usize,
167    /// Whether we have exclusive R/W access to the keys under the root key of the store.
168    has_exclusive_access: bool,
169}
170
171impl LruPrefixCache {
172    /// Creates an `LruPrefixCache`.
173    pub(crate) fn new(config: StorageCacheConfig, has_exclusive_access: bool) -> Self {
174        Self {
175            value_map: BTreeMap::new(),
176            find_keys_map: BTreeMap::new(),
177            find_key_values_map: BTreeMap::new(),
178            queue: LinkedHashMap::new(),
179            config,
180            total_size: 0,
181            total_value_size: 0,
182            total_find_keys_size: 0,
183            total_find_key_values_size: 0,
184            has_exclusive_access,
185        }
186    }
187
188    /// Gets the `has_exclusive_access`.
189    pub(crate) fn has_exclusive_access(&self) -> bool {
190        self.has_exclusive_access
191    }
192
193    /// A used key needs to be put on top.
194    fn move_cache_key_on_top(&mut self, cache_key: CacheKey) {
195        let size = self
196            .queue
197            .remove(&cache_key)
198            .expect("cache_key should be present");
199        self.queue.insert(cache_key, size);
200    }
201
202    /// Update sizes by decreasing and increasing.
203    fn update_sizes(&mut self, cache_key: &CacheKey, old_size: usize, new_size: usize) {
204        use std::cmp::Ordering;
205        match new_size.cmp(&old_size) {
206            Ordering::Greater => {
207                let increase_size = new_size - old_size;
208                self.total_size += increase_size;
209                match cache_key {
210                    CacheKey::Value(_) => {
211                        self.total_value_size += increase_size;
212                    }
213                    CacheKey::FindKeys(_) => {
214                        self.total_find_keys_size += increase_size;
215                    }
216                    CacheKey::FindKeyValues(_) => {
217                        self.total_find_key_values_size += increase_size;
218                    }
219                }
220            }
221            Ordering::Less => {
222                let decrease_size = old_size - new_size;
223                self.total_size -= decrease_size;
224                match cache_key {
225                    CacheKey::Value(_) => {
226                        self.total_value_size -= decrease_size;
227                    }
228                    CacheKey::FindKeys(_) => {
229                        self.total_find_keys_size -= decrease_size;
230                    }
231                    CacheKey::FindKeyValues(_) => {
232                        self.total_find_key_values_size -= decrease_size;
233                    }
234                }
235            }
236            Ordering::Equal => {
237                // Nothing to be done
238            }
239        }
240    }
241
242    /// Increase the sizes of the keys.
243    fn increase_sizes(&mut self, cache_key: &CacheKey, size: usize) {
244        self.update_sizes(cache_key, 0, size);
245    }
246
247    /// Decrease the sizes of the keys.
248    fn decrease_sizes(&mut self, cache_key: &CacheKey, size: usize) {
249        self.update_sizes(cache_key, size, 0);
250    }
251
252    /// Removes the `CacheKey` from the maps.
253    fn remove_cache_key_from_map(&mut self, cache_key: &CacheKey) {
254        match cache_key {
255            CacheKey::Value(key) => {
256                assert!(self.value_map.remove(key).is_some());
257            }
258            CacheKey::FindKeys(key) => {
259                assert!(self.find_keys_map.remove(key).is_some());
260            }
261            CacheKey::FindKeyValues(key) => {
262                assert!(self.find_key_values_map.remove(key).is_some());
263            }
264        }
265    }
266
267    /// Remove an entry from the queue and update the sizes.
268    fn remove_cache_key(&mut self, cache_key: &CacheKey) {
269        let size = self
270            .queue
271            .remove(cache_key)
272            .expect("cache_key should be present");
273        self.decrease_sizes(cache_key, size);
274    }
275
276    /// Remove an entry from the queue if it exists.
277    fn remove_cache_key_if_exists(&mut self, cache_key: &CacheKey) {
278        let size = self.queue.remove(cache_key);
279        if let Some(size) = size {
280            self.decrease_sizes(cache_key, size);
281            self.remove_cache_key_from_map(cache_key);
282        }
283    }
284
285    /// Update the cache size to the new size without changing position.
286    fn update_cache_key_sizes(&mut self, cache_key: &CacheKey, new_size: usize) {
287        let size = self
288            .queue
289            .get_mut(cache_key)
290            .expect("cache_key should be present");
291        let old_size = *size;
292        *size = new_size;
293        self.update_sizes(cache_key, old_size, new_size);
294    }
295
296    /// Insert a cache_key into the queue and update sizes.
297    fn insert_cache_key(&mut self, cache_key: CacheKey, size: usize) {
298        self.increase_sizes(&cache_key, size);
299        assert!(self.queue.insert(cache_key, size).is_none());
300    }
301
302    /// If the FindKeys map contains a prefix that is a prefix of key in argument,
303    /// then returns it and the corresponding FindKeys. Otherwise `None`.
304    ///
305    /// The algorithm of this function is tested in `test_lower_bounds`.
306    /// However, due to its importance we provide here a proof of correctness.
307    /// What makes this functionality work is that the set of keys of the `find_keys_map`
308    /// is prefix free.
309    ///
310    /// Claim: `self.get_existing_find_keys_entry(key)` finds a prefix of key in `self.find_keys_map.keys()` iff such prefix exists.
311    ///
312    /// Note that when it exists, such a prefix is unique because `self.find_keys_map.keys()` is prefix-free.
313    ///
314    /// Proof: For the map `find_keys_map` in question, let us define `set` to be the `BTreeSet` of
315    /// the keys of the map.
316    /// Then define `S = { s in set | s <= key }` for the lexicographic ordering.
317    /// First of all the expression `self.find_keys_map.range(..=key.to_vec())` corresponds
318    /// to S and `self.find_keys_map.range(..=key.to_vec()).next_back()` is
319    /// * None if S is empty.
320    /// * Some(M) with M the maximum of S if S is non-empty.
321    ///
322    /// First, if `self.get_existing_find_keys_entry(key) == Some(stored_key)` then given the code,
323    /// clearly `stored_key` is a prefix of key.
324    ///
325    /// Conversely, let us assume that `self.find_keys_map.keys()` contains a certain prefix `p` of key.
326    /// Because in particular `p <= key`, we have `self.find_keys_map.range(..=key.to_vec()).next_back() == Some((stored_key, _))`
327    /// for some value `stored_key` such that `p <= stored_key <= key`.
328    ///
329    /// Next, let us prove that `p` is a prefix of `stored_key`. (This will entail `stored_key == p` due to
330    /// the prefix-free property of `self.find_keys_map`, therefore the algorithm's answer is correct.)
331    ///
332    /// By contradiction. Let `w` be the longest common prefix between `p` and `stored_key`. If `p = w p2` and
333    /// `stored_key = w s2` with `p2` non-empty, then `p <= stored_key` implies `s2 > p2`. But `p` is also a
334    /// prefix of `key` therefore `stored_key > key`, contradiction.
335    fn get_existing_find_keys_entry(&self, key: &[u8]) -> Option<(&Vec<u8>, &FindKeysEntry)> {
336        match self.find_keys_map.range(..=key.to_vec()).next_back() {
337            None => None,
338            Some((stored_key, value)) => {
339                if key.starts_with(stored_key) {
340                    Some((stored_key, value))
341                } else {
342                    None
343                }
344            }
345        }
346    }
347
348    /// Same as above but returns a mutable reference.
349    fn get_existing_keys_entry_mut(
350        &mut self,
351        key: &[u8],
352    ) -> Option<(&Vec<u8>, &mut FindKeysEntry)> {
353        match self.find_keys_map.range_mut(..=key.to_vec()).next_back() {
354            None => None,
355            Some((stored_key, value)) => {
356                if key.starts_with(stored_key) {
357                    Some((stored_key, value))
358                } else {
359                    None
360                }
361            }
362        }
363    }
364
365    /// If the FindKeyValues map contain a prefix that is a prefix of key in argument,
366    /// then returns it and the corresponding FindKeyValues. Otherwise `None`.
367    fn get_existing_find_key_values_entry(
368        &self,
369        key: &[u8],
370    ) -> Option<(&Vec<u8>, &FindKeyValuesEntry)> {
371        match self.find_key_values_map.range(..=key.to_vec()).next_back() {
372            None => None,
373            Some((stored_key, value)) => {
374                if key.starts_with(stored_key) {
375                    Some((stored_key, value))
376                } else {
377                    None
378                }
379            }
380        }
381    }
382
383    /// Same as above but returns a mutable reference.
384    fn get_existing_find_key_values_entry_mut(
385        &mut self,
386        key: &[u8],
387    ) -> Option<(&Vec<u8>, &mut FindKeyValuesEntry)> {
388        match self
389            .find_key_values_map
390            .range_mut(..=key.to_vec())
391            .next_back()
392        {
393            None => None,
394            Some((stored_key, value)) => {
395                if key.starts_with(stored_key) {
396                    Some((stored_key, value))
397                } else {
398                    None
399                }
400            }
401        }
402    }
403
404    /// Trim value cache so that it fits within bounds.
405    fn trim_value_cache(&mut self) {
406        let mut keys = Vec::new();
407        let mut control_size = self.total_value_size;
408        let mut iter = self.queue.iter();
409        loop {
410            let value = iter.next();
411            let Some((cache_key, size)) = value else {
412                break;
413            };
414            if control_size < self.config.max_cache_value_size {
415                break;
416            }
417            if let CacheKey::Value(key) = cache_key {
418                control_size -= size;
419                keys.push(key.to_vec());
420            }
421        }
422        for key in keys {
423            assert!(self.value_map.remove(&key).is_some());
424            let cache_key = CacheKey::Value(key);
425            self.remove_cache_key(&cache_key);
426        }
427    }
428
429    /// Trim `find_keys_by_prefix` cache so that it fits within bounds.
430    fn trim_find_keys_cache(&mut self) {
431        let mut prefixes = Vec::new();
432        let mut control_size = self.total_find_keys_size;
433        let mut iter = self.queue.iter();
434        loop {
435            let value = iter.next();
436            let Some((cache_key, size)) = value else {
437                break;
438            };
439            if control_size < self.config.max_cache_find_keys_size {
440                break;
441            }
442            if let CacheKey::FindKeys(prefix) = cache_key {
443                control_size -= size;
444                prefixes.push(prefix.to_vec());
445            }
446        }
447        for prefix in prefixes {
448            assert!(self.find_keys_map.remove(&prefix).is_some());
449            let cache_key = CacheKey::FindKeys(prefix);
450            self.remove_cache_key(&cache_key);
451        }
452    }
453
454    /// Trim `find_key_values_by_prefix` cache so that it fits within bounds.
455    fn trim_find_key_values_cache(&mut self) {
456        let mut prefixes = Vec::new();
457        let mut control_size = self.total_find_key_values_size;
458        let mut iter = self.queue.iter();
459        loop {
460            let value = iter.next();
461            let Some((cache_key, size)) = value else {
462                break;
463            };
464            if control_size < self.config.max_cache_find_key_values_size {
465                break;
466            }
467            if let CacheKey::FindKeyValues(prefix) = cache_key {
468                control_size -= size;
469                prefixes.push(prefix.to_vec());
470            }
471        }
472        for prefix in prefixes {
473            assert!(self.find_key_values_map.remove(&prefix).is_some());
474            let cache_key = CacheKey::FindKeyValues(prefix);
475            self.remove_cache_key(&cache_key);
476        }
477    }
478
479    /// Trim the cache so that it fits within the constraints.
480    fn trim_cache(&mut self) {
481        while self.total_size >= self.config.max_cache_size
482            || self.queue.len() >= self.config.max_cache_entries
483        {
484            let Some((cache_key, size)) = self.queue.pop_front() else {
485                break;
486            };
487            self.decrease_sizes(&cache_key, size);
488            self.remove_cache_key_from_map(&cache_key);
489        }
490    }
491
492    /// Inserts an entry into the cache.
493    fn insert_value(&mut self, key: &[u8], cache_entry: ValueEntry) {
494        if self.config.max_value_entry_size == 0 {
495            // If the maximum size of an entry is zero, then we do not insert
496            return;
497        }
498        let size = key.len() + cache_entry.size();
499        if (matches!(cache_entry, ValueEntry::DoesNotExist) && !self.has_exclusive_access)
500            || size > self.config.max_value_entry_size
501        {
502            if self.value_map.remove(key).is_some() {
503                let cache_key = CacheKey::Value(key.to_vec());
504                self.remove_cache_key(&cache_key);
505            };
506            return;
507        }
508        match self.value_map.entry(key.to_vec()) {
509            Entry::Occupied(mut entry) => {
510                entry.insert(cache_entry);
511                // Put it on first position for LRU with the new size
512                let cache_key = CacheKey::Value(key.to_vec());
513                self.remove_cache_key(&cache_key);
514                self.insert_cache_key(cache_key, size);
515            }
516            Entry::Vacant(entry) => {
517                entry.insert(cache_entry);
518                let cache_key = CacheKey::Value(key.to_vec());
519                self.insert_cache_key(cache_key, size);
520            }
521        }
522        self.trim_value_cache();
523        self.trim_cache();
524    }
525
526    /// Puts a key/value in the cache.
527    pub(crate) fn put_key_value(&mut self, key: &[u8], value: &[u8]) {
528        if self.has_exclusive_access {
529            let lower_bound = self.get_existing_keys_entry_mut(key);
530            if let Some((lower_bound, cache_entry)) = lower_bound {
531                let reduced_key = &key[lower_bound.len()..];
532                cache_entry.update_entry(reduced_key, true);
533                let cache_key = CacheKey::FindKeys(lower_bound.to_vec());
534                let new_size = lower_bound.len() + cache_entry.size();
535                self.update_cache_key_sizes(&cache_key, new_size);
536            }
537            match self.get_existing_find_key_values_entry_mut(key) {
538                Some((lower_bound, cache_entry)) => {
539                    let reduced_key = &key[lower_bound.len()..];
540                    cache_entry.update_entry(reduced_key, Some(value.to_vec()));
541                    let cache_key = CacheKey::FindKeyValues(lower_bound.to_vec());
542                    let new_size = lower_bound.len() + cache_entry.size();
543                    self.update_cache_key_sizes(&cache_key, new_size);
544                    let cache_key = CacheKey::Value(key.to_vec());
545                    self.remove_cache_key_if_exists(&cache_key);
546                }
547                None => {
548                    let cache_entry = ValueEntry::Value(value.to_vec());
549                    self.insert_value(key, cache_entry);
550                }
551            }
552        } else {
553            let cache_entry = ValueEntry::Value(value.to_vec());
554            self.insert_value(key, cache_entry);
555        }
556    }
557
558    /// Deletes a key from the cache.
559    pub(crate) fn delete_key(&mut self, key: &[u8]) {
560        if self.has_exclusive_access {
561            let lower_bound = self.get_existing_keys_entry_mut(key);
562            let mut matching = false; // If matching, no need to insert in the value cache
563            if let Some((lower_bound, cache_entry)) = lower_bound {
564                let reduced_key = &key[lower_bound.len()..];
565                cache_entry.update_entry(reduced_key, false);
566                let cache_key = CacheKey::FindKeys(lower_bound.to_vec());
567                let new_size = lower_bound.len() + cache_entry.size();
568                self.update_cache_key_sizes(&cache_key, new_size);
569                matching = true;
570            }
571            let lower_bound = self.get_existing_find_key_values_entry_mut(key);
572            if let Some((lower_bound, cache_entry)) = lower_bound {
573                let reduced_key = &key[lower_bound.len()..];
574                cache_entry.update_entry(reduced_key, None);
575                let cache_key = CacheKey::FindKeyValues(lower_bound.to_vec());
576                let new_size = lower_bound.len() + cache_entry.size();
577                self.update_cache_key_sizes(&cache_key, new_size);
578                matching = true;
579            }
580            if !matching {
581                let cache_entry = ValueEntry::DoesNotExist;
582                self.insert_value(key, cache_entry);
583            } else {
584                let cache_key = CacheKey::Value(key.to_vec());
585                self.remove_cache_key_if_exists(&cache_key);
586            }
587        } else {
588            let cache_key = CacheKey::Value(key.to_vec());
589            self.remove_cache_key_if_exists(&cache_key);
590        }
591    }
592
593    /// Inserts a read_value result into the cache.
594    pub(crate) fn insert_read_value(&mut self, key: &[u8], value: &Option<Vec<u8>>) {
595        // We do not check for the find-key-values to update. Because we would have
596        // matched if existing.
597        let cache_entry = match value {
598            None => ValueEntry::DoesNotExist,
599            Some(vec) => ValueEntry::Value(vec.to_vec()),
600        };
601        self.insert_value(key, cache_entry)
602    }
603
604    /// Inserts a contains_key result into the cache.
605    pub(crate) fn insert_contains_key(&mut self, key: &[u8], result: bool) {
606        // We do not check for the find-keys / find-key-values to update.
607        // Because we would have matched if existing.
608        let cache_entry = if result {
609            ValueEntry::Exists
610        } else {
611            ValueEntry::DoesNotExist
612        };
613        self.insert_value(key, cache_entry)
614    }
615
616    /// Inserts the result of `find_keys_by_prefix` in the cache.
617    pub(crate) fn insert_find_keys(&mut self, key_prefix: Vec<u8>, keys: &[Vec<u8>]) {
618        if self.config.max_find_keys_entry_size == 0 {
619            // zero max size, exit from the start
620            return;
621        }
622        let size = key_prefix.len() + keys.iter().map(Vec::len).sum::<usize>();
623        if size > self.config.max_find_keys_entry_size {
624            // The entry is too large, we do not insert it,
625            return;
626        }
627        let find_entry = FindKeysEntry(keys.iter().cloned().collect());
628        // Clearing up the FindKeys entries that are covered by the new FindKeys.
629        let keys = self
630            .find_keys_map
631            .range(get_key_range_for_prefix(key_prefix.clone()))
632            .map(|(x, _)| x.clone())
633            .collect::<Vec<_>>();
634        for key in keys {
635            assert!(self.find_keys_map.remove(&key).is_some());
636            let cache_key = CacheKey::FindKeys(key);
637            self.remove_cache_key(&cache_key);
638        }
639        // Clearing up the value entries as they are covered by the new FindKeys.
640        // That is the `Exists` and `DoesNotExist`. The Value entries are not covered by FindKeys.
641        let keys = self
642            .value_map
643            .range(get_key_range_for_prefix(key_prefix.clone()))
644            .filter_map(|(key, value)| match value {
645                ValueEntry::DoesNotExist => Some(key.to_vec()),
646                ValueEntry::Exists => Some(key.to_vec()),
647                ValueEntry::Value(_) => None,
648            })
649            .collect::<Vec<_>>();
650        for key in keys {
651            assert!(self.value_map.remove(&key).is_some());
652            let cache_key = CacheKey::Value(key);
653            self.remove_cache_key(&cache_key);
654        }
655        let cache_key = CacheKey::FindKeys(key_prefix.clone());
656        // The entry has to be missing otherwise, it would have been found
657        assert!(self.find_keys_map.insert(key_prefix, find_entry).is_none());
658        self.insert_cache_key(cache_key, size);
659        self.trim_find_keys_cache();
660        self.trim_cache();
661    }
662
663    /// Inserts the result of `find_key_values_by_prefix` in the cache.
664    pub(crate) fn insert_find_key_values(
665        &mut self,
666        key_prefix: Vec<u8>,
667        key_values: &[(Vec<u8>, Vec<u8>)],
668    ) {
669        if self.config.max_find_key_values_entry_size == 0 {
670            // Zero, maximum size, exit from the start
671            return;
672        }
673        let size = key_prefix.len()
674            + key_values
675                .iter()
676                .map(|(k, v)| k.len() + v.len())
677                .sum::<usize>();
678        if size > self.config.max_find_key_values_entry_size {
679            // The entry is too large, we do not insert it,
680            return;
681        }
682        let find_entry = FindKeyValuesEntry(
683            key_values
684                .iter()
685                .map(|(k, v)| (k.to_vec(), v.to_vec()))
686                .collect(),
687        );
688        // Clearing up the FindKeys entries that are covered by the new FindKeyValues.
689        let prefixes = self
690            .find_keys_map
691            .range(get_key_range_for_prefix(key_prefix.clone()))
692            .map(|(x, _)| x.clone())
693            .collect::<Vec<_>>();
694        for prefix in prefixes {
695            assert!(self.find_keys_map.remove(&prefix).is_some());
696            let cache_key = CacheKey::FindKeys(prefix);
697            self.remove_cache_key(&cache_key);
698        }
699        // Clearing up the FindKeyValues entries that are covered by the new FindKeyValues.
700        let prefixes = self
701            .find_key_values_map
702            .range(get_key_range_for_prefix(key_prefix.clone()))
703            .map(|(x, _)| x.clone())
704            .collect::<Vec<_>>();
705        for prefix in prefixes {
706            assert!(self.find_key_values_map.remove(&prefix).is_some());
707            let cache_key = CacheKey::FindKeyValues(prefix);
708            self.remove_cache_key(&cache_key);
709        }
710        // Clearing up the value entries as they are covered by the new FindKeyValues.
711        let keys = self
712            .value_map
713            .range(get_key_range_for_prefix(key_prefix.clone()))
714            .map(|(x, _)| x.clone())
715            .collect::<Vec<_>>();
716        for key in keys {
717            assert!(self.value_map.remove(&key).is_some());
718            let cache_key = CacheKey::Value(key);
719            self.remove_cache_key(&cache_key);
720        }
721        let cache_key = CacheKey::FindKeyValues(key_prefix.clone());
722        // The entry has to be missing otherwise, it would have been found
723        assert!(self
724            .find_key_values_map
725            .insert(key_prefix, find_entry)
726            .is_none());
727        self.insert_cache_key(cache_key, size);
728        self.trim_find_key_values_cache();
729        self.trim_cache();
730    }
731
732    /// Marks cached keys that match the prefix as deleted. Importantly, this does not
733    /// create new entries in the cache.
734    pub(crate) fn delete_prefix(&mut self, key_prefix: &[u8]) {
735        // When using delete_prefix, we do not insert `ValueEntry::DoesNotExist`
736        // and instead drop the entries from the value-cache
737        // This is because:
738        // * In non-exclusive access, this could be added by another user.
739        // * In exclusive access, we do this via the `FindKeyValues`.
740        let mut keys = Vec::new();
741        for (key, _) in self
742            .value_map
743            .range(get_key_range_for_prefix(key_prefix.to_vec()))
744        {
745            keys.push(key.to_vec());
746        }
747        for key in keys {
748            assert!(self.value_map.remove(&key).is_some());
749            let cache_key = CacheKey::Value(key);
750            self.remove_cache_key(&cache_key);
751        }
752        if self.has_exclusive_access {
753            // Remove the FindKeys that are covered by key_prefix.
754            let mut prefixes = Vec::new();
755            for (prefix, _) in self
756                .find_keys_map
757                .range(get_key_range_for_prefix(key_prefix.to_vec()))
758            {
759                prefixes.push(prefix.to_vec());
760            }
761            for prefix in prefixes {
762                assert!(self.find_keys_map.remove(&prefix).is_some());
763                let cache_key = CacheKey::FindKeys(prefix);
764                self.remove_cache_key(&cache_key);
765            }
766            // Remove the FindKeyValues that are covered by key_prefix.
767            let mut prefixes = Vec::new();
768            for (prefix, _) in self
769                .find_key_values_map
770                .range(get_key_range_for_prefix(key_prefix.to_vec()))
771            {
772                prefixes.push(prefix.to_vec());
773            }
774            for prefix in prefixes {
775                assert!(self.find_key_values_map.remove(&prefix).is_some());
776                let cache_key = CacheKey::FindKeyValues(prefix);
777                self.remove_cache_key(&cache_key);
778            }
779            // Finding a containing FindKeys. If existing update.
780            let lower_bound = self.get_existing_keys_entry_mut(key_prefix);
781            let result = if let Some((lower_bound, find_entry)) = lower_bound {
782                // Delete the keys in the entry
783                let key_prefix_red = &key_prefix[lower_bound.len()..];
784                find_entry.delete_prefix(key_prefix_red);
785                let new_cache_size = find_entry.size() + lower_bound.len();
786                Some((new_cache_size, lower_bound.clone()))
787            } else {
788                None
789            };
790            if let Some((new_cache_size, lower_bound)) = result {
791                // Update the size without changing the position.
792                let cache_key = CacheKey::FindKeys(lower_bound.clone());
793                self.update_cache_key_sizes(&cache_key, new_cache_size);
794            }
795            // Finding a containing FindKeyValues. If existing update, if not insert.
796            let lower_bound = self.get_existing_find_key_values_entry_mut(key_prefix);
797            let result = if let Some((lower_bound, find_entry)) = lower_bound {
798                // Delete the keys (or key/values) in the entry
799                let key_prefix_red = &key_prefix[lower_bound.len()..];
800                find_entry.delete_prefix(key_prefix_red);
801                let new_cache_size = find_entry.size() + lower_bound.len();
802                Some((new_cache_size, lower_bound.clone()))
803            } else {
804                None
805            };
806            if let Some((new_cache_size, lower_bound)) = result {
807                // Update the size without changing the position.
808                let cache_key = CacheKey::FindKeyValues(lower_bound.clone());
809                self.update_cache_key_sizes(&cache_key, new_cache_size);
810            } else {
811                // There is no lower bound. Therefore we can insert
812                // the deleted prefix as a FindKeyValues.
813                let size = key_prefix.len();
814                let cache_key = CacheKey::FindKeyValues(key_prefix.to_vec());
815                let find_key_values_entry = FindKeyValuesEntry(BTreeMap::new());
816                self.find_key_values_map
817                    .insert(key_prefix.to_vec(), find_key_values_entry);
818                self.insert_cache_key(cache_key, size);
819            }
820        }
821    }
822
823    /// Returns the cached value, or `Some(None)` if the entry does not exist in the
824    /// database. If `None` is returned, the entry might exist in the database but is
825    /// not in the cache.
826    pub(crate) fn query_read_value(&mut self, key: &[u8]) -> Option<Option<Vec<u8>>> {
827        // First, query the value map
828        let result = match self.value_map.get(key) {
829            None => None,
830            Some(entry) => match entry {
831                ValueEntry::DoesNotExist => Some(None),
832                ValueEntry::Exists => None,
833                ValueEntry::Value(vec) => Some(Some(vec.clone())),
834            },
835        };
836        if result.is_some() {
837            let cache_key = CacheKey::Value(key.to_vec());
838            self.move_cache_key_on_top(cache_key);
839            return result;
840        }
841        if self.has_exclusive_access {
842            // Now trying the FindKeyValues map.
843            let lower_bound = self.get_existing_find_key_values_entry(key);
844            let (lower_bound, result) = if let Some((lower_bound, find_entry)) = lower_bound {
845                let reduced_key = &key[lower_bound.len()..];
846                (lower_bound, find_entry.get_read_value(reduced_key))
847            } else {
848                return None;
849            };
850            let cache_key = CacheKey::FindKeyValues(lower_bound.clone());
851            self.move_cache_key_on_top(cache_key);
852            Some(result)
853        } else {
854            None
855        }
856    }
857
858    /// Returns `Some(true)` or `Some(false)` if we know that the entry does or does not
859    /// exist in the database. Returns `None` if that information is not in the cache.
860    pub(crate) fn query_contains_key(&mut self, key: &[u8]) -> Option<bool> {
861        // First try on the value_map
862        let result = self
863            .value_map
864            .get(key)
865            .map(|entry| !matches!(entry, ValueEntry::DoesNotExist));
866        if result.is_some() {
867            let cache_key = CacheKey::Value(key.to_vec());
868            self.move_cache_key_on_top(cache_key);
869            return result;
870        }
871        if self.has_exclusive_access {
872            // Now trying the FindKeys map.
873            let lower_bound = self.get_existing_find_keys_entry(key);
874            let result = if let Some((lower_bound, find_entry)) = lower_bound {
875                let reduced_key = &key[lower_bound.len()..];
876                Some((lower_bound, find_entry.contains_key(reduced_key)))
877            } else {
878                None
879            };
880            if let Some((lower_bound, result)) = result {
881                let cache_key = CacheKey::FindKeys(lower_bound.clone());
882                self.move_cache_key_on_top(cache_key);
883                return Some(result);
884            }
885            // Now trying the FindKeyValues map.
886            let lower_bound = self.get_existing_find_key_values_entry(key);
887            let (lower_bound, result) = if let Some((lower_bound, find_entry)) = lower_bound {
888                let reduced_key = &key[lower_bound.len()..];
889                (lower_bound, find_entry.contains_key(reduced_key))
890            } else {
891                return None;
892            };
893            let cache_key = CacheKey::FindKeyValues(lower_bound.clone());
894            self.move_cache_key_on_top(cache_key);
895            return Some(result);
896        }
897        result
898    }
899
900    /// Gets the find_keys entry from the key prefix. Returns `None` if absent from the cache.
901    pub(crate) fn query_find_keys(&mut self, key_prefix: &[u8]) -> Option<Vec<Vec<u8>>> {
902        // Trying first the FindKeys cache.
903        let result = match self.get_existing_find_keys_entry(key_prefix) {
904            None => None,
905            Some((lower_bound, cache_entry)) => {
906                let key_prefix_red = key_prefix[lower_bound.len()..].to_vec();
907                Some((lower_bound, cache_entry.get_keys_by_prefix(key_prefix_red)))
908            }
909        };
910        if let Some((lower_bound, keys)) = result {
911            let cache_key = CacheKey::FindKeys(lower_bound.clone());
912            self.move_cache_key_on_top(cache_key);
913            return Some(keys);
914        }
915        // Then with the FindKeyValues cache.
916        let (lower_bound, result) = match self.get_existing_find_key_values_entry(key_prefix) {
917            None => {
918                return None;
919            }
920            Some((lower_bound, cache_entry)) => {
921                let key_prefix_red = key_prefix[lower_bound.len()..].to_vec();
922                (lower_bound, cache_entry.get_keys_by_prefix(key_prefix_red))
923            }
924        };
925        let cache_key = CacheKey::FindKeyValues(lower_bound.clone());
926        self.move_cache_key_on_top(cache_key);
927        Some(result)
928    }
929
930    /// Gets the find key values entry from the key prefix. Returns `None` if absent from the cache.
931    pub(crate) fn query_find_key_values(
932        &mut self,
933        key_prefix: &[u8],
934    ) -> Option<Vec<(Vec<u8>, Vec<u8>)>> {
935        let (lower_bound, result) = match self.get_existing_find_key_values_entry(key_prefix) {
936            None => {
937                return None;
938            }
939            Some((lower_bound, cache_entry)) => {
940                let key_prefix_red = &key_prefix[lower_bound.len()..];
941                (lower_bound, cache_entry.get_find_key_values(key_prefix_red))
942            }
943        };
944        let cache_key = CacheKey::FindKeyValues(lower_bound.to_vec());
945        self.move_cache_key_on_top(cache_key);
946        Some(result)
947    }
948}
949
950#[cfg(test)]
951mod tests {
952    use std::collections::BTreeSet;
953
954    use rand::Rng;
955
956    use super::*;
957
958    fn check_prefix_free(set: BTreeSet<Vec<u8>>) {
959        let keys = set.into_iter().collect::<Vec<_>>();
960        let num_keys = keys.len();
961        println!("keys={keys:?}");
962        for i in 0..num_keys {
963            for j in 0..num_keys {
964                if i != j {
965                    let key1 = keys[i].clone();
966                    let key2 = keys[j].clone();
967                    println!("i={i} j={j} key1={key1:?} key2={key2:?}");
968                    assert!(!key1.starts_with(&key2));
969                }
970            }
971        }
972    }
973
974    fn check_intersection(keys: Vec<Vec<u8>>, prefixes: &BTreeSet<Vec<u8>>) {
975        for key in keys {
976            for prefix in prefixes {
977                assert!(!key.starts_with(prefix), "key matches a prefix");
978            }
979        }
980    }
981
982    impl LruPrefixCache {
983        fn check_coherence(&self) {
984            let value_map_set = self
985                .value_map
986                .keys()
987                .cloned()
988                .collect::<BTreeSet<Vec<u8>>>();
989            let find_keys_map_set = self
990                .find_keys_map
991                .keys()
992                .cloned()
993                .collect::<BTreeSet<Vec<u8>>>();
994            let find_key_values_map_set = self
995                .find_key_values_map
996                .keys()
997                .cloned()
998                .collect::<BTreeSet<Vec<u8>>>();
999            // Checking prefix-free ness of the find-keys-map / find-key-values-map
1000            check_prefix_free(find_keys_map_set.clone());
1001            check_prefix_free(find_key_values_map_set.clone());
1002            // Building the data set and sizes.
1003            // Also checking that the sizes are coherent.
1004            let mut value_queue_set = BTreeSet::new();
1005            let mut find_keys_queue_set = BTreeSet::new();
1006            let mut find_key_values_queue_set = BTreeSet::new();
1007            let mut total_size = 0;
1008            let mut total_value_size = 0;
1009            let mut total_find_keys_size = 0;
1010            let mut total_find_key_values_size = 0;
1011            for (cache_key, size) in &self.queue {
1012                let queue_size = *size;
1013                match cache_key {
1014                    CacheKey::Value(key) => {
1015                        let value = self.value_map.get(key).unwrap();
1016                        let map_size = key.len() + value.size();
1017                        assert_eq!(map_size, queue_size, "Incoherence in value size");
1018                        value_queue_set.insert(key.clone());
1019                        total_value_size += queue_size;
1020                    }
1021                    CacheKey::FindKeys(key) => {
1022                        let value = self.find_keys_map.get(key).unwrap();
1023                        let map_size = key.len() + value.size();
1024                        assert_eq!(map_size, queue_size, "Incoherence in find-keys size");
1025                        find_keys_queue_set.insert(key.clone());
1026                        total_find_keys_size += queue_size;
1027                    }
1028                    CacheKey::FindKeyValues(key) => {
1029                        let value = self.find_key_values_map.get(key).unwrap();
1030                        let map_size = key.len() + value.size();
1031                        assert_eq!(map_size, queue_size, "Incoherence in find-keys size");
1032                        find_key_values_queue_set.insert(key.clone());
1033                        total_find_key_values_size += queue_size;
1034                    }
1035                }
1036                total_size += queue_size;
1037            }
1038            // Checking that there is no overlap between the maps.
1039            let value_map_vect = self.value_map.keys().cloned().collect::<Vec<_>>();
1040            check_intersection(value_map_vect, &find_key_values_map_set);
1041            let value_existence_map_vect = self
1042                .value_map
1043                .iter()
1044                .filter_map(|(key, value)| match value {
1045                    ValueEntry::DoesNotExist => Some(key.to_vec()),
1046                    ValueEntry::Exists => Some(key.to_vec()),
1047                    ValueEntry::Value(_) => None,
1048                })
1049                .collect::<Vec<_>>();
1050            check_intersection(value_existence_map_vect, &find_keys_map_set);
1051            // Checking that the set of keys are coherent between the queues and the maps.
1052            assert_eq!(
1053                value_queue_set, value_map_set,
1054                "Incoherence in value_map keys"
1055            );
1056            assert_eq!(
1057                find_keys_queue_set, find_keys_map_set,
1058                "Incoherence in find_keys_map keys"
1059            );
1060            assert_eq!(
1061                find_key_values_queue_set, find_key_values_map_set,
1062                "Incoherence in find_key_values_map keys"
1063            );
1064            // Checking that the total sizes are coherent.
1065            assert_eq!(total_size, self.total_size, "The total_size are incoherent");
1066            assert_eq!(
1067                total_value_size, self.total_value_size,
1068                "The total_value_size are incoherent"
1069            );
1070            assert_eq!(
1071                total_find_keys_size, self.total_find_keys_size,
1072                "The total_find_keys_size are incoherent"
1073            );
1074            assert_eq!(
1075                total_find_key_values_size, self.total_find_key_values_size,
1076                "The total_find_key_values_size are incoherent"
1077            );
1078            // Checking that the size are within the allowed bounds.
1079            if self.config.max_cache_size > 0 {
1080                assert!(
1081                    total_size < self.config.max_cache_size,
1082                    "The total_size is too large"
1083                );
1084            } else {
1085                assert!(total_size == 0, "The total_size should be 0");
1086            }
1087            if self.config.max_cache_value_size > 0 {
1088                assert!(
1089                    total_value_size < self.config.max_cache_value_size,
1090                    "The total_value_size is too large"
1091                );
1092            } else {
1093                assert!(total_value_size == 0, "The total_value_size should be 0");
1094            }
1095            if self.config.max_cache_find_keys_size > 0 {
1096                assert!(
1097                    total_find_keys_size < self.config.max_cache_find_keys_size,
1098                    "The total_value_size is too large"
1099                );
1100            } else {
1101                assert!(
1102                    total_find_keys_size == 0,
1103                    "The total_find_keys_size should be 0"
1104                );
1105            }
1106            if self.config.max_cache_find_key_values_size > 0 {
1107                assert!(
1108                    total_find_key_values_size < self.config.max_cache_find_key_values_size,
1109                    "The total_find_key_values_size is too large"
1110                );
1111            } else {
1112                assert!(
1113                    total_find_key_values_size == 0,
1114                    "The total_find_key_values_size should be 0"
1115                );
1116            }
1117        }
1118    }
1119
1120    fn create_test_cache(has_exclusive_access: bool) -> LruPrefixCache {
1121        let config = StorageCacheConfig {
1122            max_cache_size: 1000,
1123            max_value_entry_size: 50,
1124            max_find_keys_entry_size: 100,
1125            max_find_key_values_entry_size: 200,
1126            max_cache_entries: 10,
1127            max_cache_value_size: 500,
1128            max_cache_find_keys_size: 500,
1129            max_cache_find_key_values_size: 500,
1130        };
1131        LruPrefixCache::new(config, has_exclusive_access)
1132    }
1133
1134    #[test]
1135    fn test_new_cache_creation() {
1136        let cache = create_test_cache(true);
1137        assert_eq!(cache.total_size, 0);
1138        assert_eq!(cache.total_value_size, 0);
1139        assert_eq!(cache.total_find_keys_size, 0);
1140        assert_eq!(cache.total_find_key_values_size, 0);
1141        assert!(cache.has_exclusive_access);
1142        assert!(cache.value_map.is_empty());
1143        assert!(cache.find_keys_map.is_empty());
1144        assert!(cache.find_key_values_map.is_empty());
1145        assert!(cache.queue.is_empty());
1146    }
1147
1148    #[test]
1149    fn test_insert_and_query_read_value() {
1150        let mut cache = create_test_cache(true);
1151        let key = vec![1, 2, 3];
1152        let value = vec![4, 5, 6];
1153
1154        // Insert a value
1155        cache.insert_read_value(&key, &Some(value.clone()));
1156        cache.check_coherence();
1157
1158        // Query the value
1159        let result = cache.query_read_value(&key);
1160        assert_eq!(result, Some(Some(value)));
1161
1162        // Query non-existent key in the cache
1163        let result = cache.query_read_value(&[9, 9, 9]);
1164        assert_eq!(result, None);
1165    }
1166
1167    #[test]
1168    fn test_insert_and_query_contains_key() {
1169        let mut cache = create_test_cache(true);
1170        let key = vec![1, 2, 3];
1171
1172        // Insert a key that exists
1173        cache.insert_contains_key(&key, true);
1174        cache.check_coherence();
1175
1176        // Query the key
1177        let result = cache.query_contains_key(&key);
1178        assert_eq!(result, Some(true));
1179
1180        // Insert a key that doesn't exist
1181        let key2 = vec![4, 5, 6];
1182        cache.insert_contains_key(&key2, false);
1183
1184        let result = cache.query_contains_key(&key2);
1185        assert_eq!(result, Some(false));
1186    }
1187
1188    #[test]
1189    fn test_insert_and_query_find_keys() {
1190        let mut cache = create_test_cache(true);
1191        let prefix = vec![1, 2];
1192        let keys = vec![vec![3], vec![4], vec![5]];
1193
1194        // Insert find_keys entry
1195        cache.insert_find_keys(prefix.clone(), &keys);
1196        cache.check_coherence();
1197
1198        // Query with exact prefix
1199        let result = cache.query_find_keys(&prefix);
1200        assert_eq!(result, Some(keys.clone()));
1201
1202        // Query with longer prefix that should find the suffix
1203        let longer_prefix = vec![1, 2, 3];
1204        let result = cache.query_find_keys(&longer_prefix);
1205        assert_eq!(result, Some(vec![vec![]])); // Should return empty vec since [1,2,3] matches exactly
1206
1207        // Query with non-matching prefix
1208        let result = cache.query_find_keys(&[9, 9]);
1209        assert_eq!(result, None);
1210    }
1211
1212    #[test]
1213    fn test_insert_and_query_find_key_values() {
1214        let mut cache = create_test_cache(true);
1215        let prefix = vec![1, 2];
1216        let key_values = vec![(vec![3], vec![10]), (vec![4], vec![20])];
1217
1218        // Insert find_key_values entry
1219        cache.insert_find_key_values(prefix.clone(), &key_values);
1220        cache.check_coherence();
1221
1222        // Query with exact prefix
1223        let result = cache.query_find_key_values(&prefix);
1224        assert_eq!(result, Some(key_values.clone()));
1225
1226        // Query with non-matching prefix
1227        let result = cache.query_find_key_values(&[9, 9]);
1228        assert_eq!(result, None);
1229    }
1230
1231    #[test]
1232    fn test_lru_eviction_by_cache_size() {
1233        let mut cache = create_test_cache(true);
1234
1235        // Fill cache beyond max_cache_size
1236        for i in 0..20 {
1237            let key = vec![i];
1238            let value = vec![0; 100]; // Large value to trigger size-based eviction
1239            cache.insert_read_value(&key, &Some(value));
1240            cache.check_coherence();
1241        }
1242
1243        // Should have evicted some entries to stay within limits
1244        assert!(cache.total_size <= cache.config.max_cache_size);
1245        assert!(cache.queue.len() <= cache.config.max_cache_entries);
1246    }
1247
1248    #[test]
1249    fn test_lru_eviction_by_entry_count() {
1250        let mut cache = create_test_cache(true);
1251
1252        // Fill cache beyond max_cache_entries
1253        for i in 0..15 {
1254            let key = vec![i];
1255            let value = vec![i]; // Small values
1256            cache.insert_read_value(&key, &Some(value));
1257            cache.check_coherence();
1258        }
1259
1260        // Should have evicted entries to stay within max_cache_entries
1261        assert!(cache.queue.len() <= cache.config.max_cache_entries);
1262    }
1263
1264    #[test]
1265    fn test_cache_entry_promotion() {
1266        let mut cache = create_test_cache(true);
1267        let key1 = vec![1];
1268        let key2 = vec![2];
1269        let key3 = vec![3];
1270        let value = vec![42];
1271
1272        // Insert two entries
1273        cache.insert_read_value(&key1, &Some(value.clone()));
1274        cache.check_coherence();
1275        cache.insert_read_value(&key2, &Some(value.clone()));
1276        cache.check_coherence();
1277
1278        // Access key1 to promote it
1279        assert_eq!(Some(Some(value)), cache.query_read_value(&key1));
1280
1281        // Access key3 to promote it
1282        assert_eq!(None, cache.query_read_value(&key3));
1283
1284        // The queue should have key1 at the end (most recently used)
1285        let queue_keys = cache.queue.keys().collect::<Vec<_>>();
1286        assert_eq!(queue_keys[queue_keys.len() - 1], &CacheKey::Value(key1));
1287    }
1288
1289    #[test]
1290    fn test_update_find_entry_mut() {
1291        let mut cache = create_test_cache(true);
1292        let prefix = vec![1];
1293        let key = vec![1, 2];
1294        let original_keys = vec![vec![2], vec![3]];
1295
1296        // Insert find_keys entry
1297        cache.insert_find_keys(prefix.clone(), &original_keys);
1298        cache.check_coherence();
1299
1300        // Update an entry
1301        cache.put_key_value(&key, &[42]);
1302        cache.check_coherence();
1303
1304        // The find_keys entry should now contain the updated key
1305        let result = cache.query_find_keys(&prefix);
1306        assert!(result.is_some());
1307        let keys = result.unwrap();
1308        assert!(keys.contains(&vec![2]));
1309    }
1310
1311    #[test]
1312    fn test_delete_prefix_with_exclusive_access() {
1313        let mut cache = create_test_cache(true);
1314        let prefix = vec![1];
1315        let key1 = vec![1, 2];
1316        let key2 = vec![1, 3];
1317        let key3 = vec![2, 4]; // Should not be affected
1318        let value = vec![42];
1319
1320        // Insert some values
1321        cache.insert_read_value(&key1, &Some(value.clone()));
1322        cache.check_coherence();
1323        cache.insert_read_value(&key2, &Some(value.clone()));
1324        cache.check_coherence();
1325        cache.insert_read_value(&key3, &Some(value.clone()));
1326        cache.check_coherence();
1327
1328        // Delete prefix [1]
1329        cache.delete_prefix(&prefix);
1330        cache.check_coherence();
1331
1332        // Keys with prefix [1] should be marked as DoesNotExist
1333        let result1 = cache.query_read_value(&key1);
1334        assert_eq!(result1, Some(None));
1335
1336        let result2 = cache.query_read_value(&key2);
1337        assert_eq!(result2, Some(None));
1338
1339        // Key with different prefix should be unaffected
1340        let result3 = cache.query_read_value(&key3);
1341        assert_eq!(result3, Some(Some(value)));
1342    }
1343
1344    #[test]
1345    fn test_value_entry_size_limits() {
1346        let mut cache = create_test_cache(true);
1347        let key = vec![1];
1348        let large_value = vec![0; cache.config.max_value_entry_size + 1];
1349
1350        // Insert value larger than max_value_entry_size
1351        // This is because the entry size is the key size + the value size
1352        cache.insert_read_value(&key, &Some(large_value));
1353        cache.check_coherence();
1354
1355        // Should not be cached
1356        let result = cache.query_read_value(&key);
1357        assert_eq!(result, None);
1358    }
1359
1360    #[test]
1361    fn test_findkeys_entry_size_limits() {
1362        let mut cache = create_test_cache(true);
1363        let key_prefix = vec![1];
1364        let mut keys = Vec::new();
1365        for i in 0..cache.config.max_find_keys_entry_size {
1366            keys.push(vec![i as u8]);
1367        }
1368        let size = keys.iter().map(Vec::len).sum::<usize>();
1369        assert_eq!(cache.config.max_find_keys_entry_size, size);
1370        // Insert value larger than max_entry_size
1371        // This is because the entry size is the key size + the value size
1372        cache.insert_find_keys(key_prefix.clone(), &keys);
1373        cache.check_coherence();
1374
1375        // Should not be cached
1376        let result = cache.query_find_keys(&key_prefix);
1377        assert_eq!(result, None);
1378    }
1379
1380    #[test]
1381    fn test_findkeyvalues_entry_size_limits() {
1382        let mut cache = create_test_cache(true);
1383        let key_prefix = vec![1];
1384        let mut key_values = Vec::new();
1385        for i in 0..cache.config.max_find_key_values_entry_size / 2 {
1386            key_values.push((vec![i as u8], vec![i as u8]));
1387        }
1388        let size = key_values
1389            .iter()
1390            .map(|(k, v)| k.len() + v.len())
1391            .sum::<usize>();
1392        assert_eq!(cache.config.max_find_key_values_entry_size, size);
1393
1394        // Insert value larger than max_entry_size
1395        cache.insert_find_key_values(key_prefix.clone(), &key_values);
1396        cache.check_coherence();
1397
1398        // Should not be cached
1399        let result = cache.query_find_key_values(&key_prefix);
1400        assert_eq!(result, None);
1401    }
1402
1403    #[test]
1404    fn test_does_not_exist_entry_without_exclusive_access() {
1405        let mut cache = create_test_cache(false);
1406        let key = vec![1];
1407
1408        // Insert DoesNotExist entry without exclusive access
1409        cache.insert_read_value(&key, &None);
1410        cache.check_coherence();
1411
1412        // Should not be cached due to lack of exclusive access
1413        let result = cache.query_read_value(&key);
1414        assert_eq!(result, None);
1415    }
1416
1417    #[test]
1418    fn test_find_keys_entry_operations() {
1419        let mut find_entry = FindKeysEntry(BTreeSet::new());
1420        let key1 = vec![1, 2];
1421        let key2 = vec![1, 3];
1422        let key3 = vec![1, 3, 4];
1423
1424        // Add keys
1425        find_entry.update_entry(&key1, true);
1426        find_entry.update_entry(&key2, true);
1427
1428        // Test contains_key
1429        assert!(find_entry.contains_key(&key1));
1430        assert!(find_entry.contains_key(&key2));
1431        assert!(!find_entry.contains_key(&key3));
1432        assert!(!find_entry.contains_key(&[9, 9]));
1433
1434        // Test get_keys_by_prefix
1435        let keys = find_entry.get_keys_by_prefix(vec![1]);
1436        assert_eq!(keys.len(), 2);
1437        assert!(keys.contains(&vec![2]));
1438        assert!(keys.contains(&vec![3]));
1439
1440        // Remove a key
1441        find_entry.update_entry(&key1, false);
1442        assert!(!find_entry.contains_key(&key1));
1443        assert!(find_entry.contains_key(&key2));
1444    }
1445
1446    #[test]
1447    fn test_find_key_values_entry_operations() {
1448        let mut find_entry = FindKeyValuesEntry(BTreeMap::new());
1449        let key1 = vec![1, 2];
1450        let key2 = vec![1, 3];
1451        let value1 = vec![42];
1452        let value2 = vec![43];
1453
1454        // Add key-value pairs
1455        find_entry.update_entry(&key1, Some(value1.clone()));
1456        find_entry.update_entry(&key2, Some(value2.clone()));
1457
1458        // Test contains_key
1459        assert!(find_entry.contains_key(&key1));
1460        assert!(find_entry.contains_key(&key2));
1461
1462        // Test get_read_value
1463        assert_eq!(find_entry.get_read_value(&key1), Some(value1.clone()));
1464        assert_eq!(find_entry.get_read_value(&key2), Some(value2.clone()));
1465
1466        // Test get_find_key_values with prefix
1467        let key_values = find_entry.get_find_key_values(&[1]);
1468        assert_eq!(key_values.len(), 2);
1469        assert!(key_values.contains(&(vec![2], value1.clone())));
1470        assert!(key_values.contains(&(vec![3], value2.clone())));
1471
1472        // Remove a key
1473        find_entry.update_entry(&key1, None);
1474        assert!(!find_entry.contains_key(&key1));
1475        assert_eq!(find_entry.get_read_value(&key1), None);
1476    }
1477
1478    #[test]
1479    fn test_cache_size_tracking() {
1480        let mut cache = create_test_cache(true);
1481        let initial_size = cache.total_size;
1482        let initial_value_size = cache.total_value_size;
1483
1484        let key = vec![1, 2, 3];
1485        let value = vec![4, 5, 6];
1486        cache.insert_read_value(&key, &Some(value.clone()));
1487        cache.check_coherence();
1488
1489        // Size should increase
1490        assert!(cache.total_size > initial_size);
1491        assert!(cache.total_value_size > initial_value_size);
1492
1493        let value_size_with_entry = cache.total_value_size;
1494
1495        // Insert DoesNotExist entry (None value)
1496        cache.insert_read_value(&key, &None);
1497        cache.check_coherence();
1498
1499        // Value size should be less than when we had a real value,
1500        // since DoesNotExist entries have size 0 for the value part
1501        assert!(cache.total_value_size < value_size_with_entry);
1502    }
1503
1504    #[test]
1505    fn test_trim_value_cache() {
1506        let mut cache = LruPrefixCache::new(
1507            StorageCacheConfig {
1508                max_cache_size: 10000,
1509                max_value_entry_size: 500,
1510                max_find_keys_entry_size: 1000,
1511                max_find_key_values_entry_size: 2000,
1512                max_cache_entries: 100,
1513                max_cache_value_size: 50, // Small limit to trigger trimming
1514                max_cache_find_keys_size: 1000,
1515                max_cache_find_key_values_size: 1000,
1516            },
1517            true,
1518        );
1519
1520        // Insert multiple values to exceed max_cache_value_size
1521        for i in 0..10 {
1522            let key = vec![i];
1523            let value = vec![0; 20]; // Each entry ~20 bytes
1524            cache.insert_read_value(&key, &Some(value));
1525            cache.check_coherence();
1526        }
1527
1528        // Should have trimmed to stay within value cache limit
1529        assert!(cache.total_value_size <= cache.config.max_cache_value_size);
1530    }
1531
1532    fn has_a_prefix_slow_method(prefixes: &BTreeSet<Vec<u8>>, key: &[u8]) -> bool {
1533        for prefix in prefixes {
1534            if key.starts_with(prefix) {
1535                return true;
1536            }
1537        }
1538        false
1539    }
1540
1541    fn has_a_prefix_fast_method(prefixes: &BTreeSet<Vec<u8>>, key: &[u8]) -> bool {
1542        match prefixes.range(..=key.to_vec()).next_back() {
1543            None => false,
1544            Some(prefix) => key.starts_with(prefix),
1545        }
1546    }
1547
1548    fn has_a_prefix(prefixes: &BTreeSet<Vec<u8>>, key: &[u8]) -> bool {
1549        let test1 = has_a_prefix_slow_method(prefixes, key);
1550        let test2 = has_a_prefix_fast_method(prefixes, key);
1551        assert_eq!(
1552            test1, test2,
1553            "The methods for testing prefix return different results"
1554        );
1555        test1
1556    }
1557
1558    fn get_prefix<R: Rng>(rng: &mut R, max_len: usize, entry_size: usize) -> Vec<u8> {
1559        let len = rng.gen_range(1..=max_len);
1560        let mut prefix = Vec::new();
1561        for _ in 0..len {
1562            let entry = rng.gen_range(0..entry_size);
1563            prefix.push(entry as u8);
1564        }
1565        prefix
1566    }
1567
1568    fn insert_into_prefix_set(prefixes: &mut BTreeSet<Vec<u8>>, new_prefix: Vec<u8>) {
1569        if has_a_prefix(prefixes, &new_prefix) {
1570            return;
1571        }
1572        let removed_keys1 = prefixes
1573            .range(get_key_range_for_prefix(new_prefix.clone()))
1574            .cloned()
1575            .collect::<BTreeSet<Vec<u8>>>();
1576        let mut removed_keys2 = BTreeSet::new();
1577        for prefix in prefixes.clone() {
1578            if prefix.starts_with(&new_prefix) {
1579                removed_keys2.insert(prefix);
1580            }
1581        }
1582        assert_eq!(
1583            removed_keys1, removed_keys2,
1584            "Inconsistent result of the computation of the intervals"
1585        );
1586        for prefix in removed_keys2 {
1587            prefixes.remove(&prefix);
1588        }
1589        prefixes.insert(new_prefix);
1590    }
1591
1592    fn test_prefix_free_set(max_len: usize, num_gen: usize, key_size: usize) {
1593        let mut rng = crate::random::make_deterministic_rng();
1594        let mut prefixes = BTreeSet::new();
1595        for _ in 0..num_gen {
1596            let new_prefix = get_prefix(&mut rng, max_len, key_size);
1597            insert_into_prefix_set(&mut prefixes, new_prefix);
1598        }
1599    }
1600
1601    // The functions `get_existing_find_{keys,key_values}_entry(_mut)`
1602    // need to be tested. The following test does some random tests
1603    // on the generated prefix free sets. Two methods are used and
1604    // their consistency are checked.
1605    #[test]
1606    fn test_lower_bounds() {
1607        test_prefix_free_set(10, 500, 2);
1608        test_prefix_free_set(6, 500, 3);
1609        test_prefix_free_set(5, 500, 4);
1610    }
1611
1612    #[test]
1613    fn test_delete_key_operations() {
1614        let mut cache = create_test_cache(true);
1615        let key1 = vec![1, 2, 3];
1616        let key2 = vec![1, 2, 4];
1617        let key3 = vec![2, 3, 4];
1618        let value = vec![42, 43, 44];
1619
1620        // Insert some values
1621        cache.put_key_value(&key1, &value);
1622        cache.check_coherence();
1623        cache.put_key_value(&key2, &value);
1624        cache.check_coherence();
1625        cache.put_key_value(&key3, &value);
1626        cache.check_coherence();
1627
1628        // Verify values are present
1629        assert_eq!(cache.query_read_value(&key1), Some(Some(value.clone())));
1630        assert_eq!(cache.query_read_value(&key2), Some(Some(value.clone())));
1631        assert_eq!(cache.query_read_value(&key3), Some(Some(value.clone())));
1632
1633        // Delete key1
1634        cache.delete_key(&key1);
1635        cache.check_coherence();
1636
1637        // Check that key1 is now marked as DoesNotExist
1638        assert_eq!(cache.query_read_value(&key1), Some(None));
1639        // Other keys should remain unchanged
1640        assert_eq!(cache.query_read_value(&key2), Some(Some(value.clone())));
1641        assert_eq!(cache.query_read_value(&key3), Some(Some(value.clone())));
1642
1643        // Delete key2
1644        cache.delete_key(&key2);
1645        cache.check_coherence();
1646
1647        // Check that key2 is now marked as DoesNotExist
1648        assert_eq!(cache.query_read_value(&key2), Some(None));
1649        // key3 should remain unchanged
1650        assert_eq!(cache.query_read_value(&key3), Some(Some(value)));
1651    }
1652
1653    #[test]
1654    fn test_find_key_values_entry_delete_prefix() {
1655        let mut find_entry = FindKeyValuesEntry(BTreeMap::new());
1656
1657        // Add some key-value pairs
1658        let key1 = vec![1, 2, 3];
1659        let key2 = vec![1, 2, 4];
1660        let key3 = vec![1, 3, 5];
1661        let key4 = vec![2, 4, 6];
1662        let value = vec![42];
1663
1664        find_entry.update_entry(&key1, Some(value.clone()));
1665        find_entry.update_entry(&key2, Some(value.clone()));
1666        find_entry.update_entry(&key3, Some(value.clone()));
1667        find_entry.update_entry(&key4, Some(value.clone()));
1668
1669        // Verify all keys are present
1670        assert!(find_entry.contains_key(&key1));
1671        assert!(find_entry.contains_key(&key2));
1672        assert!(find_entry.contains_key(&key3));
1673        assert!(find_entry.contains_key(&key4));
1674
1675        // Delete prefix [1, 2] - should remove key1 and key2
1676        find_entry.delete_prefix(&[1, 2]);
1677
1678        // Check that keys with prefix [1, 2] are removed
1679        assert!(!find_entry.contains_key(&key1));
1680        assert!(!find_entry.contains_key(&key2));
1681        // Keys with different prefixes should remain
1682        assert!(find_entry.contains_key(&key3));
1683        assert!(find_entry.contains_key(&key4));
1684
1685        // Delete prefix [1] - should remove key3
1686        find_entry.delete_prefix(&[1]);
1687
1688        // Check that key3 is now removed
1689        assert!(!find_entry.contains_key(&key3));
1690        // key4 with different prefix should remain
1691        assert!(find_entry.contains_key(&key4));
1692    }
1693
1694    #[test]
1695    fn test_trim_value_cache_removes_entries() {
1696        let mut cache = LruPrefixCache::new(
1697            StorageCacheConfig {
1698                max_cache_size: 10000,
1699                max_value_entry_size: 500,
1700                max_find_keys_entry_size: 1000,
1701                max_find_key_values_entry_size: 2000,
1702                max_cache_entries: 100,
1703                max_cache_value_size: 30, // Very small limit to force removal
1704                max_cache_find_keys_size: 1000,
1705                max_cache_find_key_values_size: 1000,
1706            },
1707            true,
1708        );
1709
1710        // Insert multiple values that exceed the max_cache_value_size
1711        let mut inserted_keys = Vec::new();
1712        for i in 0..6 {
1713            let key = vec![i];
1714            let value = vec![0; 10]; // Each entry ~10 bytes + key = ~11 bytes
1715            cache.insert_read_value(&key, &Some(value));
1716            cache.check_coherence();
1717            inserted_keys.push(key);
1718        }
1719
1720        // After trimming, total value size should be within limit
1721        assert!(cache.total_value_size <= cache.config.max_cache_value_size);
1722
1723        // Some entries should have been removed (LRU eviction)
1724        let mut remaining_count = 0;
1725        for key in &inserted_keys {
1726            if cache.query_read_value(key).is_some() {
1727                remaining_count += 1;
1728            }
1729        }
1730
1731        // We should have fewer entries than we inserted due to trimming
1732        assert!(remaining_count < inserted_keys.len());
1733
1734        // The most recently inserted entries should still be present
1735        let last_key = &inserted_keys[inserted_keys.len() - 1];
1736        assert!(cache.query_read_value(last_key).is_some());
1737    }
1738
1739    #[test]
1740    fn test_max_value_entry_size_zero_early_termination() {
1741        let mut cache = LruPrefixCache::new(
1742            StorageCacheConfig {
1743                max_cache_size: 1000,
1744                max_value_entry_size: 0, // Zero size - should cause early termination
1745                max_find_keys_entry_size: 100,
1746                max_find_key_values_entry_size: 200,
1747                max_cache_entries: 10,
1748                max_cache_value_size: 500,
1749                max_cache_find_keys_size: 500,
1750                max_cache_find_key_values_size: 500,
1751            },
1752            true,
1753        );
1754
1755        let key1 = vec![1, 2, 3];
1756        let key2 = vec![4, 5, 6];
1757        let value = vec![42, 43, 44];
1758
1759        // Insert values - should be terminated early due to max_value_entry_size == 0
1760        cache.insert_read_value(&key1, &Some(value.clone()));
1761        cache.check_coherence();
1762        cache.insert_read_value(&key2, &None);
1763        cache.check_coherence();
1764
1765        // Values should not be cached due to early termination
1766        assert_eq!(cache.query_read_value(&key1), None);
1767        assert_eq!(cache.query_read_value(&key2), None);
1768
1769        // Cache should remain empty
1770        assert_eq!(cache.total_size, 0);
1771        assert_eq!(cache.total_value_size, 0);
1772        assert!(cache.value_map.is_empty());
1773        assert!(cache.queue.is_empty());
1774
1775        // Test put_key_value also respects the early termination
1776        cache.put_key_value(&key1, &value);
1777        cache.check_coherence();
1778
1779        assert_eq!(cache.query_read_value(&key1), None);
1780        assert_eq!(cache.total_size, 0);
1781
1782        // Test delete_key also respects the early termination
1783        cache.delete_key(&key1);
1784        cache.check_coherence();
1785
1786        assert_eq!(cache.query_read_value(&key1), None);
1787        assert_eq!(cache.total_size, 0);
1788    }
1789
1790    #[test]
1791    fn test_key_value_replacement_same_length() {
1792        let mut cache = create_test_cache(true);
1793        let key = vec![1, 2, 3];
1794        let value1 = vec![42, 43, 44]; // 3 bytes
1795        let value2 = vec![99, 98, 97]; // 3 bytes - same length as value1
1796
1797        // Insert initial value
1798        cache.put_key_value(&key, &value1);
1799        cache.check_coherence();
1800
1801        // Verify initial value is present
1802        assert_eq!(cache.query_read_value(&key), Some(Some(value1.clone())));
1803
1804        let initial_size = cache.total_size;
1805        let initial_value_size = cache.total_value_size;
1806
1807        // Replace with value of same length
1808        cache.put_key_value(&key, &value2);
1809        cache.check_coherence();
1810
1811        // Verify new value is present
1812        assert_eq!(cache.query_read_value(&key), Some(Some(value2.clone())));
1813
1814        // Size should remain the same since values have same length
1815        assert_eq!(cache.total_size, initial_size);
1816        assert_eq!(cache.total_value_size, initial_value_size);
1817
1818        // Cache should still contain exactly one entry
1819        assert_eq!(cache.value_map.len(), 1);
1820        assert_eq!(cache.queue.len(), 1);
1821
1822        // Test replacement with insert_read_value as well
1823        let value3 = vec![11, 22, 33]; // 3 bytes - same length
1824        cache.insert_read_value(&key, &Some(value3.clone()));
1825        cache.check_coherence();
1826
1827        // Verify replacement worked
1828        assert_eq!(cache.query_read_value(&key), Some(Some(value3)));
1829
1830        // Size should still be the same
1831        assert_eq!(cache.total_size, initial_size);
1832        assert_eq!(cache.total_value_size, initial_value_size);
1833    }
1834
1835    #[test]
1836    fn test_max_find_keys_entry_size_zero_early_termination() {
1837        let mut cache = LruPrefixCache::new(
1838            StorageCacheConfig {
1839                max_cache_size: 1000,
1840                max_value_entry_size: 100,
1841                max_find_keys_entry_size: 0, // Zero size - should cause early termination
1842                max_find_key_values_entry_size: 200,
1843                max_cache_entries: 10,
1844                max_cache_value_size: 500,
1845                max_cache_find_keys_size: 500,
1846                max_cache_find_key_values_size: 500,
1847            },
1848            true,
1849        );
1850
1851        let prefix = vec![1, 2];
1852        let keys = vec![vec![3], vec![4], vec![5]];
1853
1854        // Insert find_keys entry - should be terminated early due to max_find_keys_entry_size == 0
1855        cache.insert_find_keys(prefix.clone(), &keys);
1856        cache.check_coherence();
1857
1858        // Find keys should not be cached due to early termination
1859        assert_eq!(cache.query_find_keys(&prefix), None);
1860
1861        // Cache should remain empty for find_keys
1862        assert_eq!(cache.total_find_keys_size, 0);
1863        assert!(cache.find_keys_map.is_empty());
1864
1865        // Verify no find_keys entries in the queue
1866        for (cache_key, _) in &cache.queue {
1867            assert!(!matches!(cache_key, CacheKey::FindKeys(_)));
1868        }
1869
1870        // Test with different prefix and keys to ensure consistent behavior
1871        let prefix2 = vec![9];
1872        let keys2 = vec![vec![1]];
1873        cache.insert_find_keys(prefix2.clone(), &keys2);
1874        cache.check_coherence();
1875
1876        assert_eq!(cache.query_find_keys(&prefix2), None);
1877        assert_eq!(cache.total_find_keys_size, 0);
1878        assert!(cache.find_keys_map.is_empty());
1879    }
1880
1881    #[test]
1882    fn test_max_find_key_values_entry_size_zero_early_termination() {
1883        let mut cache = LruPrefixCache::new(
1884            StorageCacheConfig {
1885                max_cache_size: 1000,
1886                max_value_entry_size: 100,
1887                max_find_keys_entry_size: 100,
1888                max_find_key_values_entry_size: 0, // Zero size - should cause early termination
1889                max_cache_entries: 10,
1890                max_cache_value_size: 500,
1891                max_cache_find_keys_size: 500,
1892                max_cache_find_key_values_size: 500,
1893            },
1894            true,
1895        );
1896
1897        let prefix = vec![1, 2];
1898        let key_values = vec![(vec![3], vec![10]), (vec![4], vec![20])];
1899
1900        // Insert find_key_values entry - should be terminated early due to max_find_key_values_entry_size == 0
1901        cache.insert_find_key_values(prefix.clone(), &key_values);
1902        cache.check_coherence();
1903
1904        // Find key values should not be cached due to early termination
1905        assert_eq!(cache.query_find_key_values(&prefix), None);
1906
1907        // Cache should remain empty for find_key_values
1908        assert_eq!(cache.total_find_key_values_size, 0);
1909        assert!(cache.find_key_values_map.is_empty());
1910
1911        // Verify no find_key_values entries in the queue
1912        for (cache_key, _) in &cache.queue {
1913            assert!(!matches!(cache_key, CacheKey::FindKeyValues(_)));
1914        }
1915
1916        // Test with different data to ensure consistent behavior
1917        let prefix2 = vec![9];
1918        let key_values2 = vec![(vec![1], vec![100])];
1919        cache.insert_find_key_values(prefix2.clone(), &key_values2);
1920        cache.check_coherence();
1921
1922        assert_eq!(cache.query_find_key_values(&prefix2), None);
1923        assert_eq!(cache.total_find_key_values_size, 0);
1924        assert!(cache.find_key_values_map.is_empty());
1925    }
1926
1927    #[test]
1928    fn test_value_entry_exists_returns_none() {
1929        let mut cache = create_test_cache(true);
1930        let key = vec![1, 2, 3];
1931
1932        // Insert a ValueEntry::Exists (this happens when we cache that a key exists but not its value)
1933        cache.insert_contains_key(&key, true);
1934        cache.check_coherence();
1935
1936        // Verify that contains_key query returns Some(true)
1937        assert_eq!(cache.query_contains_key(&key), Some(true));
1938
1939        // When querying for the actual value with ValueEntry::Exists, it should return None
1940        // because we only know the key exists but don't have the actual value cached
1941        assert_eq!(cache.query_read_value(&key), None);
1942
1943        // Test with a key that doesn't exist
1944        let key2 = vec![4, 5, 6];
1945        cache.insert_contains_key(&key2, false);
1946        cache.check_coherence();
1947
1948        // This should return Some(false) for contains_key
1949        assert_eq!(cache.query_contains_key(&key2), Some(false));
1950
1951        // And Some(None) for read_value since we cached that it doesn't exist
1952        assert_eq!(cache.query_read_value(&key2), Some(None));
1953
1954        // Verify the cache state - we should have both entries
1955        assert_eq!(cache.value_map.len(), 2);
1956        assert_eq!(cache.queue.len(), 2);
1957
1958        // Both entries should be ValueEntry::Exists and ValueEntry::DoesNotExist respectively
1959        assert!(matches!(
1960            cache.value_map.get(&key),
1961            Some(ValueEntry::Exists)
1962        ));
1963        assert!(matches!(
1964            cache.value_map.get(&key2),
1965            Some(ValueEntry::DoesNotExist)
1966        ));
1967    }
1968
1969    #[test]
1970    fn test_find_keys_entry_delete_prefix_function() {
1971        let mut find_entry = FindKeysEntry(BTreeSet::new());
1972
1973        // Add some keys
1974        let key1 = vec![1, 2, 3];
1975        let key2 = vec![1, 2, 4];
1976        let key3 = vec![1, 3, 5];
1977        let key4 = vec![2, 4, 6];
1978
1979        find_entry.update_entry(&key1, true);
1980        find_entry.update_entry(&key2, true);
1981        find_entry.update_entry(&key3, true);
1982        find_entry.update_entry(&key4, true);
1983
1984        // Verify all keys are present
1985        assert!(find_entry.contains_key(&key1));
1986        assert!(find_entry.contains_key(&key2));
1987        assert!(find_entry.contains_key(&key3));
1988        assert!(find_entry.contains_key(&key4));
1989        assert_eq!(find_entry.0.len(), 4);
1990
1991        // Test delete_prefix function directly - delete prefix [1, 2]
1992        find_entry.delete_prefix(&[1, 2]);
1993
1994        // Check that keys with prefix [1, 2] are removed
1995        assert!(!find_entry.contains_key(&key1));
1996        assert!(!find_entry.contains_key(&key2));
1997        // Keys with different prefixes should remain
1998        assert!(find_entry.contains_key(&key3));
1999        assert!(find_entry.contains_key(&key4));
2000        assert_eq!(find_entry.0.len(), 2);
2001
2002        // Test delete_prefix with prefix [1] - should remove key3
2003        find_entry.delete_prefix(&[1]);
2004
2005        // Check that key3 is now removed
2006        assert!(!find_entry.contains_key(&key3));
2007        // key4 with different prefix should remain
2008        assert!(find_entry.contains_key(&key4));
2009        assert_eq!(find_entry.0.len(), 1);
2010
2011        // Test delete_prefix with empty prefix - should remove all remaining keys
2012        find_entry.delete_prefix(&[]);
2013
2014        // All keys should be removed
2015        assert!(!find_entry.contains_key(&key4));
2016        assert_eq!(find_entry.0.len(), 0);
2017    }
2018
2019    #[test]
2020    fn test_find_keys_size_decrease() {
2021        let mut cache = create_test_cache(true);
2022        let prefix = vec![1];
2023        let initial_keys = vec![vec![2, 3, 4], vec![3, 4, 5]]; // Larger keys
2024
2025        // Insert initial find_keys entry
2026        cache.insert_find_keys(prefix.clone(), &initial_keys);
2027        cache.check_coherence();
2028
2029        let initial_total_size = cache.total_size;
2030        let initial_find_keys_size = cache.total_find_keys_size;
2031
2032        // Now delete one of the keys, which should decrease the size
2033        let key_to_delete = vec![1, 2, 3, 4]; // This matches prefix + first key
2034        cache.delete_key(&key_to_delete);
2035        cache.check_coherence();
2036
2037        // The find_keys entry should have been updated and size decreased
2038        assert!(cache.total_size < initial_total_size);
2039        assert!(cache.total_find_keys_size < initial_find_keys_size);
2040
2041        // Verify the key was actually removed from the find_keys entry
2042        let result = cache.query_find_keys(&prefix);
2043        assert!(result.is_some());
2044        let keys = result.unwrap();
2045        assert!(keys.contains(&vec![3, 4, 5])); // Second key should still be there
2046        assert!(!keys.contains(&vec![2, 3, 4])); // First key should be gone
2047
2048        cache.check_coherence();
2049    }
2050
2051    #[test]
2052    fn test_trim_find_keys_cache_lru_eviction() {
2053        let mut cache = LruPrefixCache::new(
2054            StorageCacheConfig {
2055                max_cache_size: 10000,
2056                max_value_entry_size: 500,
2057                max_find_keys_entry_size: 1000,
2058                max_find_key_values_entry_size: 2000,
2059                max_cache_entries: 100,
2060                max_cache_value_size: 5000,
2061                max_cache_find_keys_size: 50, // Small limit to trigger trimming
2062                max_cache_find_key_values_size: 5000,
2063            },
2064            true,
2065        );
2066
2067        // Insert first find_keys entry
2068        let prefix1 = vec![1];
2069        let keys1 = vec![vec![2; 10], vec![3; 10]]; // ~20 bytes
2070        cache.insert_find_keys(prefix1.clone(), &keys1);
2071        cache.check_coherence();
2072
2073        // Insert second find_keys entry
2074        let prefix2 = vec![2];
2075        let keys2 = vec![vec![4; 10], vec![5; 10]]; // ~20 bytes
2076        cache.insert_find_keys(prefix2.clone(), &keys2);
2077        cache.check_coherence();
2078
2079        // Both entries should be present at this point
2080        assert!(cache.query_find_keys(&prefix1).is_some());
2081        assert!(cache.query_find_keys(&prefix2).is_some());
2082
2083        // Insert third find_keys entry that should trigger trimming
2084        let prefix3 = vec![3];
2085        let keys3 = vec![vec![6; 10], vec![7; 10]]; // ~20 bytes
2086        cache.insert_find_keys(prefix3.clone(), &keys3);
2087        cache.check_coherence();
2088
2089        // The cache should have trimmed to stay within max_cache_find_keys_size
2090        assert!(cache.total_find_keys_size <= cache.config.max_cache_find_keys_size);
2091
2092        // The least recently used entry (prefix1) should have been evicted
2093        assert_eq!(cache.query_find_keys(&prefix1), None);
2094
2095        // The more recent entries should still be present
2096        assert!(cache.query_find_keys(&prefix2).is_some());
2097        assert!(cache.query_find_keys(&prefix3).is_some());
2098
2099        // Verify we have fewer find_keys entries than we inserted
2100        assert!(cache.find_keys_map.len() < 3);
2101    }
2102
2103    #[test]
2104    fn test_find_keys_removal_from_map() {
2105        let mut cache = LruPrefixCache::new(
2106            StorageCacheConfig {
2107                max_cache_size: 100, // Small cache to trigger eviction
2108                max_value_entry_size: 50,
2109                max_find_keys_entry_size: 1000,
2110                max_find_key_values_entry_size: 2000,
2111                max_cache_entries: 3, // Very small to force eviction
2112                max_cache_value_size: 500,
2113                max_cache_find_keys_size: 500,
2114                max_cache_find_key_values_size: 500,
2115            },
2116            true,
2117        );
2118
2119        let prefix1 = vec![1];
2120        let prefix2 = vec![2];
2121        let prefix3 = vec![3];
2122        let keys = vec![vec![1], vec![2]];
2123
2124        // Insert find_keys entries to fill the cache
2125        cache.insert_find_keys(prefix1.clone(), &keys);
2126        cache.check_coherence();
2127        cache.insert_find_keys(prefix2.clone(), &keys);
2128        cache.check_coherence();
2129
2130        // Verify both entries are present
2131        assert!(cache.find_keys_map.contains_key(&prefix1));
2132        assert!(cache.find_keys_map.contains_key(&prefix2));
2133
2134        // Insert third entry that should trigger eviction and call remove_cache_key_from_map for FindKeys
2135        cache.insert_find_keys(prefix3.clone(), &keys);
2136        cache.check_coherence();
2137
2138        // The first entry should have been evicted
2139        assert!(!cache.find_keys_map.contains_key(&prefix1));
2140        // The newer entries should still be present
2141        assert!(cache.find_keys_map.contains_key(&prefix2));
2142        assert!(cache.find_keys_map.contains_key(&prefix3));
2143
2144        // Verify cache constraints are maintained
2145        assert!(cache.queue.len() <= cache.config.max_cache_entries);
2146    }
2147
2148    #[test]
2149    fn test_find_key_values_removal_from_map() {
2150        let mut cache = LruPrefixCache::new(
2151            StorageCacheConfig {
2152                max_cache_size: 100, // Small cache to trigger eviction
2153                max_value_entry_size: 50,
2154                max_find_keys_entry_size: 1000,
2155                max_find_key_values_entry_size: 2000,
2156                max_cache_entries: 3, // Very small to force eviction
2157                max_cache_value_size: 500,
2158                max_cache_find_keys_size: 500,
2159                max_cache_find_key_values_size: 500,
2160            },
2161            true,
2162        );
2163
2164        let prefix1 = vec![1];
2165        let prefix2 = vec![2];
2166        let prefix3 = vec![3];
2167        let key_values = vec![(vec![1], vec![10]), (vec![2], vec![20])];
2168
2169        // Insert find_key_values entries to fill the cache
2170        cache.insert_find_key_values(prefix1.clone(), &key_values);
2171        cache.check_coherence();
2172        cache.insert_find_key_values(prefix2.clone(), &key_values);
2173        cache.check_coherence();
2174
2175        // Verify both entries are present
2176        assert!(cache.find_key_values_map.contains_key(&prefix1));
2177        assert!(cache.find_key_values_map.contains_key(&prefix2));
2178
2179        // Insert third entry that should trigger eviction and call remove_cache_key_from_map for FindKeyValues
2180        cache.insert_find_key_values(prefix3.clone(), &key_values);
2181        cache.check_coherence();
2182
2183        // The first entry should have been evicted
2184        assert!(!cache.find_key_values_map.contains_key(&prefix1));
2185        // The newer entries should still be present
2186        assert!(cache.find_key_values_map.contains_key(&prefix2));
2187        assert!(cache.find_key_values_map.contains_key(&prefix3));
2188
2189        // Verify cache constraints are maintained
2190        assert!(cache.queue.len() <= cache.config.max_cache_entries);
2191    }
2192
2193    #[test]
2194    fn test_contains_key_failing_without_exclusive_access() {
2195        let mut cache = create_test_cache(false); // has_exclusive_access = false
2196        let key = vec![1, 2, 3];
2197
2198        // With has_exclusive_access = false, query_contains_key should only check value_map
2199        // Since the key is not in value_map, it should return None
2200        let result = cache.query_contains_key(&key);
2201        assert_eq!(result, None);
2202
2203        // Verify that only value_map is checked by inserting directly into value_map
2204        cache.insert_contains_key(&key, true);
2205        cache.check_coherence();
2206
2207        // Now it should return Some(true) because it's found in value_map
2208        let result = cache.query_contains_key(&key);
2209        assert_eq!(result, Some(true));
2210    }
2211
2212    #[test]
2213    fn test_contains_key_found_in_find_key_values() {
2214        let mut cache = create_test_cache(true); // has_exclusive_access = true
2215        let prefix = vec![1, 2];
2216        let key = vec![1, 2, 3, 4];
2217        let key_values = vec![(vec![3, 4], vec![100]), (vec![5, 6], vec![200])];
2218
2219        // Insert a FindKeyValues entry that contains the key we'll query
2220        cache.insert_find_key_values(prefix.clone(), &key_values);
2221        cache.check_coherence();
2222
2223        // Query for the key - this should find it in FindKeyValues (lines 852-854)
2224        let result = cache.query_contains_key(&key);
2225        assert_eq!(result, Some(true));
2226
2227        // Test with a key that doesn't exist in the FindKeyValues
2228        let non_existent_key = vec![1, 2, 7, 8];
2229        let result = cache.query_contains_key(&non_existent_key);
2230        assert_eq!(result, Some(false)); // Found the prefix but key doesn't exist in the entry
2231
2232        // Test with a key that doesn't match any prefix
2233        let unmatched_key = vec![9, 9, 9];
2234        let result = cache.query_contains_key(&unmatched_key);
2235        assert_eq!(result, None); // No matching prefix found
2236    }
2237
2238    #[test]
2239    fn test_find_keys_removal_when_inserting_broader_find_keys() {
2240        let mut cache = create_test_cache(true);
2241
2242        // Insert another FindKeys entry with a more specific prefix
2243        let specific_prefix = vec![1, 2, 3, 4];
2244        let keys2 = vec![vec![6], vec![7]];
2245        cache.insert_find_keys(specific_prefix.clone(), &keys2);
2246        cache.check_coherence();
2247
2248        // Insert a FindKeys entry with a specific prefix
2249        let narrow_prefix = vec![1, 2, 3];
2250        let keys1 = vec![vec![4, 6], vec![4, 7]];
2251        cache.insert_find_keys(narrow_prefix.clone(), &keys1);
2252        cache.check_coherence();
2253    }
2254
2255    #[test]
2256    fn test_overlapping_find_key_values_removes_find_keys_and_find_key_values() {
2257        let mut cache = create_test_cache(true);
2258
2259        // Insert a FindKeys entry
2260        let find_keys_prefix = vec![1, 2, 3];
2261        let keys = vec![vec![4, 6], vec![4, 7], vec![5]];
2262        cache.insert_find_keys(find_keys_prefix.clone(), &keys);
2263        cache.check_coherence();
2264
2265        // Insert a FindKeyValues entry with a different but overlapping prefix
2266        let find_key_values_prefix = vec![1, 2, 3, 4];
2267        let key_values1 = vec![(vec![6], vec![10]), (vec![7], vec![20])];
2268        cache.insert_find_key_values(find_key_values_prefix.clone(), &key_values1);
2269        cache.check_coherence();
2270
2271        // Inserts a Value
2272        cache.put_key_value(&[1, 2, 8, 9], &[254]);
2273        cache.check_coherence();
2274
2275        // Now insert a broader FindKeyValues entry that overlaps with both previous entries
2276        let broad_prefix = vec![1, 2];
2277        let key_values2 = vec![
2278            (vec![3, 4, 6], vec![10]),
2279            (vec![3, 4, 7], vec![20]),
2280            (vec![3, 5], vec![34]),
2281            (vec![8, 9], vec![254]),
2282        ];
2283        cache.insert_find_key_values(broad_prefix.clone(), &key_values2);
2284        cache.check_coherence();
2285
2286        // The broader FindKeyValues should have removed the overlapping FindKeys entry.
2287        assert!(!cache.find_keys_map.contains_key(&find_keys_prefix));
2288
2289        // The broader FindKeyValues should have removed the overlapping FindKeyValues entry.
2290        assert!(!cache
2291            .find_key_values_map
2292            .contains_key(&find_key_values_prefix));
2293
2294        // The new broad FindKeyValues entry should exist
2295        assert!(cache.find_key_values_map.contains_key(&broad_prefix));
2296
2297        // Verify the new entry has the expected key-values
2298        let key_values = cache.query_find_key_values(&broad_prefix).unwrap();
2299        assert!(key_values.contains(&(vec![3, 4, 6], vec![10])));
2300        assert!(key_values.contains(&(vec![3, 4, 7], vec![20])));
2301        assert!(key_values.contains(&(vec![8, 9], vec![254])));
2302
2303        // Test that we can still query for keys under the broad prefix
2304        let query_result = cache.query_contains_key(&[1, 2, 3, 1]);
2305        assert_eq!(query_result, Some(false)); // Should find it in the new FindKeyValues entry
2306    }
2307
2308    #[test]
2309    fn test_delete_prefix_removes_entire_find_keys_entry() {
2310        let mut cache = create_test_cache(true); // has_exclusive_access = true
2311
2312        // Insert a FindKeys entry
2313        let prefix = vec![1, 2, 3];
2314        let keys = vec![vec![4], vec![5], vec![6]];
2315        cache.insert_find_keys(prefix.clone(), &keys);
2316        cache.check_coherence();
2317
2318        // Verify the FindKeys entry exists
2319        assert!(cache.find_keys_map.contains_key(&prefix));
2320        let result = cache.query_find_keys(&prefix);
2321        assert!(result.is_some());
2322
2323        // Delete a prefix that covers the entire FindKeys entry
2324        let delete_prefix = vec![1, 2]; // This covers [1, 2, 3]
2325        cache.delete_prefix(&delete_prefix);
2326        cache.check_coherence();
2327
2328        // Verify the entry is no longer queryable
2329        let result = cache.query_find_keys(&prefix);
2330        assert_eq!(result, Some(vec![]));
2331
2332        // Verify the queue no longer contains the FindKeys entry
2333        for (cache_key, _) in &cache.queue {
2334            assert!(!matches!(cache_key, CacheKey::FindKeys(key) if key == &prefix));
2335        }
2336    }
2337
2338    #[test]
2339    fn test_delete_prefix_removes_keys_within_find_keys_entry() {
2340        let mut cache = create_test_cache(true); // has_exclusive_access = true
2341
2342        // Insert a FindKeys entry with a broader prefix
2343        let find_keys_prefix = vec![1];
2344        let keys = vec![vec![2, 3, 4], vec![2, 3, 5], vec![2, 4, 6], vec![3, 7, 8]];
2345        cache.insert_find_keys(find_keys_prefix.clone(), &keys);
2346        cache.check_coherence();
2347
2348        // Verify the FindKeys entry exists and contains all keys
2349        assert!(cache.find_keys_map.contains_key(&find_keys_prefix));
2350        let initial_keys = cache.query_find_keys(&find_keys_prefix).unwrap();
2351        assert!(initial_keys.contains(&vec![2, 3, 4]));
2352        assert!(initial_keys.contains(&vec![2, 3, 5]));
2353        assert!(initial_keys.contains(&vec![2, 4, 6]));
2354        assert!(initial_keys.contains(&vec![3, 7, 8]));
2355
2356        let initial_size = cache.total_find_keys_size;
2357
2358        // Delete a prefix that only affects some keys within the FindKeys entry
2359        let delete_prefix = vec![1, 2, 3]; // This should only affect keys [2,3,4] and [2,3,5]
2360        cache.delete_prefix(&delete_prefix);
2361        cache.check_coherence();
2362
2363        // The FindKeys entry should still exist but with fewer keys
2364        assert!(cache.find_keys_map.contains_key(&find_keys_prefix));
2365
2366        // Verify that only the keys with prefix [2,3] were removed
2367        let remaining_keys = cache.query_find_keys(&find_keys_prefix).unwrap();
2368        assert!(!remaining_keys.contains(&vec![2, 3, 4])); // Should be removed
2369        assert!(!remaining_keys.contains(&vec![2, 3, 5])); // Should be removed
2370        assert!(remaining_keys.contains(&vec![2, 4, 6])); // Should remain
2371        assert!(remaining_keys.contains(&vec![3, 7, 8])); // Should remain
2372
2373        // The cache size should have decreased due to the removed keys
2374        assert!(cache.total_find_keys_size < initial_size);
2375
2376        // Test another delete that removes more keys
2377        let delete_prefix2 = vec![1, 2]; // This should affect key [2,4,6]
2378        cache.delete_prefix(&delete_prefix2);
2379        cache.check_coherence();
2380
2381        // Check the remaining keys
2382        let final_keys = cache.query_find_keys(&find_keys_prefix).unwrap();
2383        assert!(!final_keys.contains(&vec![2, 4, 6])); // Should now be removed
2384        assert!(final_keys.contains(&vec![3, 7, 8])); // Should still remain
2385    }
2386
2387    #[test]
2388    fn test_put_key_value_without_find_key_values_match() {
2389        let mut cache = create_test_cache(false); // has_exclusive_access = true
2390        let key = vec![1, 2, 3, 4];
2391        let value = vec![100, 200];
2392
2393        // The value should be inserted without accessing the FindKeys / FindKeyValues.
2394        cache.put_key_value(&key, &value);
2395        cache.check_coherence();
2396
2397        // Testing the reading of value.
2398        assert_eq!(cache.query_read_value(&key), Some(Some(value.clone())));
2399        assert!(cache.value_map.contains_key(&key));
2400    }
2401
2402    #[test]
2403    fn test_delete_key_without_exclusive_access() {
2404        let mut cache = create_test_cache(false); // has_exclusive_access = false
2405        let key = vec![1, 2, 3];
2406        let value = vec![42, 43, 44];
2407
2408        // Insert a value first
2409        cache.insert_read_value(&key, &Some(value.clone()));
2410        cache.check_coherence();
2411
2412        // Verify the value is cached
2413        assert_eq!(cache.query_read_value(&key), Some(Some(value)));
2414        assert!(cache.value_map.contains_key(&key));
2415
2416        // Delete the key without exclusive access. So, do not use the
2417        // FindKeys/FindKeyValues.
2418        cache.delete_key(&key);
2419        cache.check_coherence();
2420
2421        // The entry should be removed from the cache.
2422        assert!(!cache.value_map.contains_key(&key));
2423        assert_eq!(cache.query_read_value(&key), None);
2424
2425        // Verify the queue no longer contains the entry
2426        for (cache_key, _) in &cache.queue {
2427            assert!(!matches!(cache_key, CacheKey::Value(k) if k == &key));
2428        }
2429
2430        // Test deleting a key that doesn't exist
2431        let non_existent_key = vec![9, 9, 9];
2432        cache.delete_key(&non_existent_key); // Should not crash
2433        cache.check_coherence();
2434    }
2435
2436    #[test]
2437    fn test_line_502_insert_then_delete_without_exclusive_access() {
2438        let mut cache = create_test_cache(false); // has_exclusive_access = false
2439        let key = vec![1, 2, 3, 4];
2440        let value = vec![100, 200, 201];
2441
2442        // First insert a value entry
2443        cache.insert_read_value(&key, &Some(value.clone()));
2444        cache.check_coherence();
2445
2446        // Verify the value is cached
2447        assert_eq!(cache.query_read_value(&key), Some(Some(value)));
2448        assert!(cache.value_map.contains_key(&key));
2449
2450        // Now insert a DoesNotExist entry (simulating a delete) without exclusive access
2451        // This should trigger line 502: removal due to !has_exclusive_access
2452        cache.insert_read_value(&key, &None);
2453        cache.check_coherence();
2454
2455        // The entry should be completely removed from the cache (line 502)
2456        assert!(!cache.value_map.contains_key(&key));
2457        assert_eq!(cache.query_read_value(&key), None);
2458
2459        // Verify the cache key is removed from the queue
2460        let queue_contains_key = cache
2461            .queue
2462            .iter()
2463            .any(|(cache_key, _)| matches!(cache_key, CacheKey::Value(k) if k == &key));
2464        assert!(!queue_contains_key);
2465    }
2466
2467    #[test]
2468    fn test_does_not_exist_removal_during_insert_find_keys() {
2469        let mut cache = create_test_cache(true); // has_exclusive_access = true
2470        let prefix = vec![1, 2];
2471        let key1 = vec![1, 2, 3];
2472        let key2 = vec![1, 2, 4];
2473        let key3 = vec![1, 2, 5];
2474
2475        // Insert DoesNotExist entries for keys that will be covered by the FindKeys
2476        cache.insert_read_value(&key1, &None); // Creates DoesNotExist entry
2477        cache.insert_read_value(&key2, &None); // Creates DoesNotExist entry
2478        cache.insert_read_value(&key3, &Some(vec![100])); // Creates Value entry (should not be removed)
2479        cache.check_coherence();
2480
2481        // Verify the DoesNotExist entries are cached
2482        assert_eq!(cache.query_read_value(&key1), Some(None));
2483        assert_eq!(cache.query_read_value(&key2), Some(None));
2484        assert_eq!(cache.query_read_value(&key3), Some(Some(vec![100])));
2485        assert!(cache.value_map.contains_key(&key1));
2486        assert!(cache.value_map.contains_key(&key2));
2487        assert!(cache.value_map.contains_key(&key3));
2488
2489        // Insert a FindKeys entry that covers the prefix - this should trigger line 640
2490        // Line 640 filters DoesNotExist entries for removal, but not Value entries
2491        let find_keys_result = vec![key1.clone(), key2.clone(), key3.clone()];
2492        cache.insert_find_keys(prefix.clone(), &find_keys_result);
2493        cache.check_coherence();
2494
2495        // After insert_find_keys, the DoesNotExist entries should be removed (line 640)
2496        // but the Value entry should remain (line 642 returns None for Value entries)
2497        assert_eq!(cache.query_read_value(&key1), None); // DoesNotExist removed
2498        assert_eq!(cache.query_read_value(&key2), None); // DoesNotExist removed
2499        assert_eq!(cache.query_read_value(&key3), Some(Some(vec![100]))); // Value entry kept
2500        assert!(!cache.value_map.contains_key(&key1));
2501        assert!(!cache.value_map.contains_key(&key2));
2502        assert!(cache.value_map.contains_key(&key3)); // Value entry remains
2503
2504        // Verify the FindKeys entry was created
2505        assert_eq!(cache.query_find_keys(&prefix), Some(find_keys_result));
2506    }
2507
2508    #[test]
2509    fn test_trim_value_cache_complete_iteration() {
2510        let mut cache = create_test_cache(true);
2511
2512        // Insert some value entries to populate the cache
2513        let key1 = vec![1, 2, 3];
2514        let key2 = vec![4, 5, 6];
2515        let value1 = vec![100, 200];
2516        let value2 = vec![203, 177];
2517
2518        cache.insert_read_value(&key1, &Some(value1));
2519        cache.insert_read_value(&key2, &Some(value2));
2520        cache.check_coherence();
2521
2522        // Set cache size to 0 to force trimming but ensure queue is not empty
2523        cache.config.max_cache_value_size = 0;
2524
2525        // Call trim_value_cache - this should iterate through entire queue
2526        // and hit line 411 (break when iter.next() returns None)
2527        cache.trim_value_cache();
2528        cache.check_coherence();
2529
2530        // All value entries should be removed since max_cache_value_size = 0
2531        assert!(!cache.value_map.contains_key(&key1));
2532        assert!(!cache.value_map.contains_key(&key2));
2533    }
2534
2535    #[test]
2536    fn test_trim_find_keys_cache_complete_iteration() {
2537        let mut cache = create_test_cache(true);
2538
2539        // Insert some FindKeys entries to populate the cache
2540        let prefix1 = vec![1, 2];
2541        let prefix2 = vec![3, 4];
2542        let keys1 = vec![vec![1, 2, 3], vec![1, 2, 4]];
2543        let keys2 = vec![vec![3, 4, 5], vec![3, 4, 6]];
2544
2545        cache.insert_find_keys(prefix1, &keys1);
2546        cache.insert_find_keys(prefix2, &keys2);
2547        cache.check_coherence();
2548
2549        // Set cache size to 0 to force trimming but ensure queue is not empty
2550        cache.config.max_cache_find_keys_size = 0;
2551
2552        // Call trim_find_keys_cache - this should iterate through entire queue
2553        // and hit line 436 (break when iter.next() returns None)
2554        cache.trim_find_keys_cache();
2555        cache.check_coherence();
2556
2557        // All FindKeys entries should be removed since max_cache_find_keys_size = 0
2558        assert!(cache.find_keys_map.is_empty());
2559    }
2560
2561    #[test]
2562    fn test_trim_find_key_values_cache_complete_iteration() {
2563        let mut cache = create_test_cache(true);
2564
2565        // Insert some FindKeyValues entries to populate the cache
2566        let prefix1 = vec![1, 2];
2567        let prefix2 = vec![3, 4];
2568        let key_values1 = vec![(vec![1, 2, 3], vec![100]), (vec![1, 2, 4], vec![200])];
2569        let key_values2 = vec![(vec![3, 4, 5], vec![203]), (vec![3, 4, 6], vec![177])];
2570
2571        cache.insert_find_key_values(prefix1, &key_values1);
2572        cache.insert_find_key_values(prefix2, &key_values2);
2573        cache.check_coherence();
2574
2575        // Set cache size to 0 to force trimming but ensure queue is not empty
2576        cache.config.max_cache_find_key_values_size = 0;
2577
2578        // Call trim_find_key_values_cache - this should iterate through entire queue
2579        // and hit line 461 (break when iter.next() returns None)
2580        cache.trim_find_key_values_cache();
2581        cache.check_coherence();
2582
2583        // All FindKeyValues entries should be removed since max_cache_find_key_values_size = 0
2584        assert!(cache.find_key_values_map.is_empty());
2585    }
2586
2587    #[test]
2588    fn test_trim_cache_breaks_on_empty_queue() {
2589        let mut cache = LruPrefixCache::new(
2590            StorageCacheConfig {
2591                max_cache_size: 10000,       // to make irrelevant
2592                max_value_entry_size: 10000, // to make irrelevant
2593                max_find_keys_entry_size: 10000,
2594                max_find_key_values_entry_size: 10000,
2595                max_cache_entries: 10,
2596                max_cache_value_size: 500,
2597                max_cache_find_keys_size: 500,
2598                max_cache_find_key_values_size: 500,
2599            },
2600            true,
2601        );
2602
2603        // Insert some entries to populate the cache
2604        for i in 0..10 {
2605            let key = vec![1, 2, i];
2606            let value = vec![100 + i];
2607            cache.insert_read_value(&key, &Some(value));
2608            cache.check_coherence();
2609        }
2610
2611        // Manually manipulate total_size so that the cache gets emptied.
2612        cache.config.max_cache_size = 0;
2613
2614        // Inserting something that triggers the whole cache being emptied.
2615        let key = vec![1, 2];
2616        let value = vec![100];
2617        cache.insert_read_value(&key, &Some(value));
2618        cache.check_coherence();
2619    }
2620}