Skip to main content

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    /// Removes an entry from the queue and updates 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    /// Removes 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    /// Inserts a cache key into the queue and updates 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    #![allow(clippy::cast_possible_truncation)]
953
954    use std::collections::BTreeSet;
955
956    use rand::Rng;
957
958    use super::*;
959
960    fn check_prefix_free(set: BTreeSet<Vec<u8>>) {
961        let keys = set.into_iter().collect::<Vec<_>>();
962        let num_keys = keys.len();
963        println!("keys={keys:?}");
964        for i in 0..num_keys {
965            for j in 0..num_keys {
966                if i != j {
967                    let key1 = keys[i].clone();
968                    let key2 = keys[j].clone();
969                    println!("i={i} j={j} key1={key1:?} key2={key2:?}");
970                    assert!(!key1.starts_with(&key2));
971                }
972            }
973        }
974    }
975
976    fn check_intersection(keys: Vec<Vec<u8>>, prefixes: &BTreeSet<Vec<u8>>) {
977        for key in keys {
978            for prefix in prefixes {
979                assert!(!key.starts_with(prefix), "key matches a prefix");
980            }
981        }
982    }
983
984    impl LruPrefixCache {
985        fn check_coherence(&self) {
986            let value_map_set = self
987                .value_map
988                .keys()
989                .cloned()
990                .collect::<BTreeSet<Vec<u8>>>();
991            let find_keys_map_set = self
992                .find_keys_map
993                .keys()
994                .cloned()
995                .collect::<BTreeSet<Vec<u8>>>();
996            let find_key_values_map_set = self
997                .find_key_values_map
998                .keys()
999                .cloned()
1000                .collect::<BTreeSet<Vec<u8>>>();
1001            // Checking prefix-free ness of the find-keys-map / find-key-values-map
1002            check_prefix_free(find_keys_map_set.clone());
1003            check_prefix_free(find_key_values_map_set.clone());
1004            // Building the data set and sizes.
1005            // Also checking that the sizes are coherent.
1006            let mut value_queue_set = BTreeSet::new();
1007            let mut find_keys_queue_set = BTreeSet::new();
1008            let mut find_key_values_queue_set = BTreeSet::new();
1009            let mut total_size = 0;
1010            let mut total_value_size = 0;
1011            let mut total_find_keys_size = 0;
1012            let mut total_find_key_values_size = 0;
1013            for (cache_key, size) in &self.queue {
1014                let queue_size = *size;
1015                match cache_key {
1016                    CacheKey::Value(key) => {
1017                        let value = self.value_map.get(key).unwrap();
1018                        let map_size = key.len() + value.size();
1019                        assert_eq!(map_size, queue_size, "Incoherence in value size");
1020                        value_queue_set.insert(key.clone());
1021                        total_value_size += queue_size;
1022                    }
1023                    CacheKey::FindKeys(key) => {
1024                        let value = self.find_keys_map.get(key).unwrap();
1025                        let map_size = key.len() + value.size();
1026                        assert_eq!(map_size, queue_size, "Incoherence in find-keys size");
1027                        find_keys_queue_set.insert(key.clone());
1028                        total_find_keys_size += queue_size;
1029                    }
1030                    CacheKey::FindKeyValues(key) => {
1031                        let value = self.find_key_values_map.get(key).unwrap();
1032                        let map_size = key.len() + value.size();
1033                        assert_eq!(map_size, queue_size, "Incoherence in find-keys size");
1034                        find_key_values_queue_set.insert(key.clone());
1035                        total_find_key_values_size += queue_size;
1036                    }
1037                }
1038                total_size += queue_size;
1039            }
1040            // Checking that there is no overlap between the maps.
1041            let value_map_vect = self.value_map.keys().cloned().collect::<Vec<_>>();
1042            check_intersection(value_map_vect, &find_key_values_map_set);
1043            let value_existence_map_vect = self
1044                .value_map
1045                .iter()
1046                .filter_map(|(key, value)| match value {
1047                    ValueEntry::DoesNotExist => Some(key.to_vec()),
1048                    ValueEntry::Exists => Some(key.to_vec()),
1049                    ValueEntry::Value(_) => None,
1050                })
1051                .collect::<Vec<_>>();
1052            check_intersection(value_existence_map_vect, &find_keys_map_set);
1053            // Checking that the set of keys are coherent between the queues and the maps.
1054            assert_eq!(
1055                value_queue_set, value_map_set,
1056                "Incoherence in value_map keys"
1057            );
1058            assert_eq!(
1059                find_keys_queue_set, find_keys_map_set,
1060                "Incoherence in find_keys_map keys"
1061            );
1062            assert_eq!(
1063                find_key_values_queue_set, find_key_values_map_set,
1064                "Incoherence in find_key_values_map keys"
1065            );
1066            // Checking that the total sizes are coherent.
1067            assert_eq!(total_size, self.total_size, "The total_size are incoherent");
1068            assert_eq!(
1069                total_value_size, self.total_value_size,
1070                "The total_value_size are incoherent"
1071            );
1072            assert_eq!(
1073                total_find_keys_size, self.total_find_keys_size,
1074                "The total_find_keys_size are incoherent"
1075            );
1076            assert_eq!(
1077                total_find_key_values_size, self.total_find_key_values_size,
1078                "The total_find_key_values_size are incoherent"
1079            );
1080            // Checking that the size are within the allowed bounds.
1081            if self.config.max_cache_size > 0 {
1082                assert!(
1083                    total_size < self.config.max_cache_size,
1084                    "The total_size is too large"
1085                );
1086            } else {
1087                assert!(total_size == 0, "The total_size should be 0");
1088            }
1089            if self.config.max_cache_value_size > 0 {
1090                assert!(
1091                    total_value_size < self.config.max_cache_value_size,
1092                    "The total_value_size is too large"
1093                );
1094            } else {
1095                assert!(total_value_size == 0, "The total_value_size should be 0");
1096            }
1097            if self.config.max_cache_find_keys_size > 0 {
1098                assert!(
1099                    total_find_keys_size < self.config.max_cache_find_keys_size,
1100                    "The total_value_size is too large"
1101                );
1102            } else {
1103                assert!(
1104                    total_find_keys_size == 0,
1105                    "The total_find_keys_size should be 0"
1106                );
1107            }
1108            if self.config.max_cache_find_key_values_size > 0 {
1109                assert!(
1110                    total_find_key_values_size < self.config.max_cache_find_key_values_size,
1111                    "The total_find_key_values_size is too large"
1112                );
1113            } else {
1114                assert!(
1115                    total_find_key_values_size == 0,
1116                    "The total_find_key_values_size should be 0"
1117                );
1118            }
1119        }
1120    }
1121
1122    fn create_test_cache(has_exclusive_access: bool) -> LruPrefixCache {
1123        let config = StorageCacheConfig {
1124            max_cache_size: 1000,
1125            max_value_entry_size: 50,
1126            max_find_keys_entry_size: 100,
1127            max_find_key_values_entry_size: 200,
1128            max_cache_entries: 10,
1129            max_cache_value_size: 500,
1130            max_cache_find_keys_size: 500,
1131            max_cache_find_key_values_size: 500,
1132        };
1133        LruPrefixCache::new(config, has_exclusive_access)
1134    }
1135
1136    #[test]
1137    fn test_new_cache_creation() {
1138        let cache = create_test_cache(true);
1139        assert_eq!(cache.total_size, 0);
1140        assert_eq!(cache.total_value_size, 0);
1141        assert_eq!(cache.total_find_keys_size, 0);
1142        assert_eq!(cache.total_find_key_values_size, 0);
1143        assert!(cache.has_exclusive_access);
1144        assert!(cache.value_map.is_empty());
1145        assert!(cache.find_keys_map.is_empty());
1146        assert!(cache.find_key_values_map.is_empty());
1147        assert!(cache.queue.is_empty());
1148    }
1149
1150    #[test]
1151    fn test_insert_and_query_read_value() {
1152        let mut cache = create_test_cache(true);
1153        let key = vec![1, 2, 3];
1154        let value = vec![4, 5, 6];
1155
1156        // Insert a value
1157        cache.insert_read_value(&key, &Some(value.clone()));
1158        cache.check_coherence();
1159
1160        // Query the value
1161        let result = cache.query_read_value(&key);
1162        assert_eq!(result, Some(Some(value)));
1163
1164        // Query non-existent key in the cache
1165        let result = cache.query_read_value(&[9, 9, 9]);
1166        assert_eq!(result, None);
1167    }
1168
1169    #[test]
1170    fn test_insert_and_query_contains_key() {
1171        let mut cache = create_test_cache(true);
1172        let key = vec![1, 2, 3];
1173
1174        // Insert a key that exists
1175        cache.insert_contains_key(&key, true);
1176        cache.check_coherence();
1177
1178        // Query the key
1179        let result = cache.query_contains_key(&key);
1180        assert_eq!(result, Some(true));
1181
1182        // Insert a key that doesn't exist
1183        let key2 = vec![4, 5, 6];
1184        cache.insert_contains_key(&key2, false);
1185
1186        let result = cache.query_contains_key(&key2);
1187        assert_eq!(result, Some(false));
1188    }
1189
1190    #[test]
1191    fn test_insert_and_query_find_keys() {
1192        let mut cache = create_test_cache(true);
1193        let prefix = vec![1, 2];
1194        let keys = vec![vec![3], vec![4], vec![5]];
1195
1196        // Insert find_keys entry
1197        cache.insert_find_keys(prefix.clone(), &keys);
1198        cache.check_coherence();
1199
1200        // Query with exact prefix
1201        let result = cache.query_find_keys(&prefix);
1202        assert_eq!(result, Some(keys.clone()));
1203
1204        // Query with longer prefix that should find the suffix
1205        let longer_prefix = vec![1, 2, 3];
1206        let result = cache.query_find_keys(&longer_prefix);
1207        assert_eq!(result, Some(vec![vec![]])); // Should return empty vec since [1,2,3] matches exactly
1208
1209        // Query with non-matching prefix
1210        let result = cache.query_find_keys(&[9, 9]);
1211        assert_eq!(result, None);
1212    }
1213
1214    #[test]
1215    fn test_insert_and_query_find_key_values() {
1216        let mut cache = create_test_cache(true);
1217        let prefix = vec![1, 2];
1218        let key_values = vec![(vec![3], vec![10]), (vec![4], vec![20])];
1219
1220        // Insert find_key_values entry
1221        cache.insert_find_key_values(prefix.clone(), &key_values);
1222        cache.check_coherence();
1223
1224        // Query with exact prefix
1225        let result = cache.query_find_key_values(&prefix);
1226        assert_eq!(result, Some(key_values.clone()));
1227
1228        // Query with non-matching prefix
1229        let result = cache.query_find_key_values(&[9, 9]);
1230        assert_eq!(result, None);
1231    }
1232
1233    #[test]
1234    fn test_lru_eviction_by_cache_size() {
1235        let mut cache = create_test_cache(true);
1236
1237        // Fill cache beyond max_cache_size
1238        for i in 0..20 {
1239            let key = vec![i];
1240            let value = vec![0; 100]; // Large value to trigger size-based eviction
1241            cache.insert_read_value(&key, &Some(value));
1242            cache.check_coherence();
1243        }
1244
1245        // Should have evicted some entries to stay within limits
1246        assert!(cache.total_size <= cache.config.max_cache_size);
1247        assert!(cache.queue.len() <= cache.config.max_cache_entries);
1248    }
1249
1250    #[test]
1251    fn test_lru_eviction_by_entry_count() {
1252        let mut cache = create_test_cache(true);
1253
1254        // Fill cache beyond max_cache_entries
1255        for i in 0..15 {
1256            let key = vec![i];
1257            let value = vec![i]; // Small values
1258            cache.insert_read_value(&key, &Some(value));
1259            cache.check_coherence();
1260        }
1261
1262        // Should have evicted entries to stay within max_cache_entries
1263        assert!(cache.queue.len() <= cache.config.max_cache_entries);
1264    }
1265
1266    #[test]
1267    fn test_cache_entry_promotion() {
1268        let mut cache = create_test_cache(true);
1269        let key1 = vec![1];
1270        let key2 = vec![2];
1271        let key3 = vec![3];
1272        let value = vec![42];
1273
1274        // Insert two entries
1275        cache.insert_read_value(&key1, &Some(value.clone()));
1276        cache.check_coherence();
1277        cache.insert_read_value(&key2, &Some(value.clone()));
1278        cache.check_coherence();
1279
1280        // Access key1 to promote it
1281        assert_eq!(Some(Some(value)), cache.query_read_value(&key1));
1282
1283        // Access key3 to promote it
1284        assert_eq!(None, cache.query_read_value(&key3));
1285
1286        // The queue should have key1 at the end (most recently used)
1287        let queue_keys = cache.queue.keys().collect::<Vec<_>>();
1288        assert_eq!(queue_keys[queue_keys.len() - 1], &CacheKey::Value(key1));
1289    }
1290
1291    #[test]
1292    fn test_update_find_entry_mut() {
1293        let mut cache = create_test_cache(true);
1294        let prefix = vec![1];
1295        let key = vec![1, 2];
1296        let original_keys = vec![vec![2], vec![3]];
1297
1298        // Insert find_keys entry
1299        cache.insert_find_keys(prefix.clone(), &original_keys);
1300        cache.check_coherence();
1301
1302        // Update an entry
1303        cache.put_key_value(&key, &[42]);
1304        cache.check_coherence();
1305
1306        // The find_keys entry should now contain the updated key
1307        let result = cache.query_find_keys(&prefix);
1308        assert!(result.is_some());
1309        let keys = result.unwrap();
1310        assert!(keys.contains(&vec![2]));
1311    }
1312
1313    #[test]
1314    fn test_delete_prefix_with_exclusive_access() {
1315        let mut cache = create_test_cache(true);
1316        let prefix = vec![1];
1317        let key1 = vec![1, 2];
1318        let key2 = vec![1, 3];
1319        let key3 = vec![2, 4]; // Should not be affected
1320        let value = vec![42];
1321
1322        // Insert some values
1323        cache.insert_read_value(&key1, &Some(value.clone()));
1324        cache.check_coherence();
1325        cache.insert_read_value(&key2, &Some(value.clone()));
1326        cache.check_coherence();
1327        cache.insert_read_value(&key3, &Some(value.clone()));
1328        cache.check_coherence();
1329
1330        // Delete prefix [1]
1331        cache.delete_prefix(&prefix);
1332        cache.check_coherence();
1333
1334        // Keys with prefix [1] should be marked as DoesNotExist
1335        let result1 = cache.query_read_value(&key1);
1336        assert_eq!(result1, Some(None));
1337
1338        let result2 = cache.query_read_value(&key2);
1339        assert_eq!(result2, Some(None));
1340
1341        // Key with different prefix should be unaffected
1342        let result3 = cache.query_read_value(&key3);
1343        assert_eq!(result3, Some(Some(value)));
1344    }
1345
1346    #[test]
1347    fn test_value_entry_size_limits() {
1348        let mut cache = create_test_cache(true);
1349        let key = vec![1];
1350        let large_value = vec![0; cache.config.max_value_entry_size + 1];
1351
1352        // Insert value larger than max_value_entry_size
1353        // This is because the entry size is the key size + the value size
1354        cache.insert_read_value(&key, &Some(large_value));
1355        cache.check_coherence();
1356
1357        // Should not be cached
1358        let result = cache.query_read_value(&key);
1359        assert_eq!(result, None);
1360    }
1361
1362    #[test]
1363    fn test_findkeys_entry_size_limits() {
1364        let mut cache = create_test_cache(true);
1365        let key_prefix = vec![1];
1366        let mut keys = Vec::new();
1367        for i in 0..cache.config.max_find_keys_entry_size {
1368            keys.push(vec![i as u8]);
1369        }
1370        let size = keys.iter().map(Vec::len).sum::<usize>();
1371        assert_eq!(cache.config.max_find_keys_entry_size, size);
1372        // Insert value larger than max_entry_size
1373        // This is because the entry size is the key size + the value size
1374        cache.insert_find_keys(key_prefix.clone(), &keys);
1375        cache.check_coherence();
1376
1377        // Should not be cached
1378        let result = cache.query_find_keys(&key_prefix);
1379        assert_eq!(result, None);
1380    }
1381
1382    #[test]
1383    fn test_findkeyvalues_entry_size_limits() {
1384        let mut cache = create_test_cache(true);
1385        let key_prefix = vec![1];
1386        let mut key_values = Vec::new();
1387        for i in 0..cache.config.max_find_key_values_entry_size / 2 {
1388            key_values.push((vec![i as u8], vec![i as u8]));
1389        }
1390        let size = key_values
1391            .iter()
1392            .map(|(k, v)| k.len() + v.len())
1393            .sum::<usize>();
1394        assert_eq!(cache.config.max_find_key_values_entry_size, size);
1395
1396        // Insert value larger than max_entry_size
1397        cache.insert_find_key_values(key_prefix.clone(), &key_values);
1398        cache.check_coherence();
1399
1400        // Should not be cached
1401        let result = cache.query_find_key_values(&key_prefix);
1402        assert_eq!(result, None);
1403    }
1404
1405    #[test]
1406    fn test_does_not_exist_entry_without_exclusive_access() {
1407        let mut cache = create_test_cache(false);
1408        let key = vec![1];
1409
1410        // Insert DoesNotExist entry without exclusive access
1411        cache.insert_read_value(&key, &None);
1412        cache.check_coherence();
1413
1414        // Should not be cached due to lack of exclusive access
1415        let result = cache.query_read_value(&key);
1416        assert_eq!(result, None);
1417    }
1418
1419    #[test]
1420    fn test_find_keys_entry_operations() {
1421        let mut find_entry = FindKeysEntry(BTreeSet::new());
1422        let key1 = vec![1, 2];
1423        let key2 = vec![1, 3];
1424        let key3 = vec![1, 3, 4];
1425
1426        // Add keys
1427        find_entry.update_entry(&key1, true);
1428        find_entry.update_entry(&key2, true);
1429
1430        // Test contains_key
1431        assert!(find_entry.contains_key(&key1));
1432        assert!(find_entry.contains_key(&key2));
1433        assert!(!find_entry.contains_key(&key3));
1434        assert!(!find_entry.contains_key(&[9, 9]));
1435
1436        // Test get_keys_by_prefix
1437        let keys = find_entry.get_keys_by_prefix(vec![1]);
1438        assert_eq!(keys.len(), 2);
1439        assert!(keys.contains(&vec![2]));
1440        assert!(keys.contains(&vec![3]));
1441
1442        // Remove a key
1443        find_entry.update_entry(&key1, false);
1444        assert!(!find_entry.contains_key(&key1));
1445        assert!(find_entry.contains_key(&key2));
1446    }
1447
1448    #[test]
1449    fn test_find_key_values_entry_operations() {
1450        let mut find_entry = FindKeyValuesEntry(BTreeMap::new());
1451        let key1 = vec![1, 2];
1452        let key2 = vec![1, 3];
1453        let value1 = vec![42];
1454        let value2 = vec![43];
1455
1456        // Add key-value pairs
1457        find_entry.update_entry(&key1, Some(value1.clone()));
1458        find_entry.update_entry(&key2, Some(value2.clone()));
1459
1460        // Test contains_key
1461        assert!(find_entry.contains_key(&key1));
1462        assert!(find_entry.contains_key(&key2));
1463
1464        // Test get_read_value
1465        assert_eq!(find_entry.get_read_value(&key1), Some(value1.clone()));
1466        assert_eq!(find_entry.get_read_value(&key2), Some(value2.clone()));
1467
1468        // Test get_find_key_values with prefix
1469        let key_values = find_entry.get_find_key_values(&[1]);
1470        assert_eq!(key_values.len(), 2);
1471        assert!(key_values.contains(&(vec![2], value1.clone())));
1472        assert!(key_values.contains(&(vec![3], value2.clone())));
1473
1474        // Remove a key
1475        find_entry.update_entry(&key1, None);
1476        assert!(!find_entry.contains_key(&key1));
1477        assert_eq!(find_entry.get_read_value(&key1), None);
1478    }
1479
1480    #[test]
1481    fn test_cache_size_tracking() {
1482        let mut cache = create_test_cache(true);
1483        let initial_size = cache.total_size;
1484        let initial_value_size = cache.total_value_size;
1485
1486        let key = vec![1, 2, 3];
1487        let value = vec![4, 5, 6];
1488        cache.insert_read_value(&key, &Some(value.clone()));
1489        cache.check_coherence();
1490
1491        // Size should increase
1492        assert!(cache.total_size > initial_size);
1493        assert!(cache.total_value_size > initial_value_size);
1494
1495        let value_size_with_entry = cache.total_value_size;
1496
1497        // Insert DoesNotExist entry (None value)
1498        cache.insert_read_value(&key, &None);
1499        cache.check_coherence();
1500
1501        // Value size should be less than when we had a real value,
1502        // since DoesNotExist entries have size 0 for the value part
1503        assert!(cache.total_value_size < value_size_with_entry);
1504    }
1505
1506    #[test]
1507    fn test_trim_value_cache() {
1508        let mut cache = LruPrefixCache::new(
1509            StorageCacheConfig {
1510                max_cache_size: 10000,
1511                max_value_entry_size: 500,
1512                max_find_keys_entry_size: 1000,
1513                max_find_key_values_entry_size: 2000,
1514                max_cache_entries: 100,
1515                max_cache_value_size: 50, // Small limit to trigger trimming
1516                max_cache_find_keys_size: 1000,
1517                max_cache_find_key_values_size: 1000,
1518            },
1519            true,
1520        );
1521
1522        // Insert multiple values to exceed max_cache_value_size
1523        for i in 0..10 {
1524            let key = vec![i];
1525            let value = vec![0; 20]; // Each entry ~20 bytes
1526            cache.insert_read_value(&key, &Some(value));
1527            cache.check_coherence();
1528        }
1529
1530        // Should have trimmed to stay within value cache limit
1531        assert!(cache.total_value_size <= cache.config.max_cache_value_size);
1532    }
1533
1534    fn has_a_prefix_slow_method(prefixes: &BTreeSet<Vec<u8>>, key: &[u8]) -> bool {
1535        for prefix in prefixes {
1536            if key.starts_with(prefix) {
1537                return true;
1538            }
1539        }
1540        false
1541    }
1542
1543    fn has_a_prefix_fast_method(prefixes: &BTreeSet<Vec<u8>>, key: &[u8]) -> bool {
1544        match prefixes.range(..=key.to_vec()).next_back() {
1545            None => false,
1546            Some(prefix) => key.starts_with(prefix),
1547        }
1548    }
1549
1550    fn has_a_prefix(prefixes: &BTreeSet<Vec<u8>>, key: &[u8]) -> bool {
1551        let test1 = has_a_prefix_slow_method(prefixes, key);
1552        let test2 = has_a_prefix_fast_method(prefixes, key);
1553        assert_eq!(
1554            test1, test2,
1555            "The methods for testing prefix return different results"
1556        );
1557        test1
1558    }
1559
1560    fn get_prefix<R: Rng>(rng: &mut R, max_len: usize, entry_size: usize) -> Vec<u8> {
1561        let len = rng.gen_range(1..=max_len);
1562        let mut prefix = Vec::new();
1563        for _ in 0..len {
1564            let entry = rng.gen_range(0..entry_size);
1565            prefix.push(entry as u8);
1566        }
1567        prefix
1568    }
1569
1570    fn insert_into_prefix_set(prefixes: &mut BTreeSet<Vec<u8>>, new_prefix: Vec<u8>) {
1571        if has_a_prefix(prefixes, &new_prefix) {
1572            return;
1573        }
1574        let removed_keys1 = prefixes
1575            .range(get_key_range_for_prefix(new_prefix.clone()))
1576            .cloned()
1577            .collect::<BTreeSet<Vec<u8>>>();
1578        let mut removed_keys2 = BTreeSet::new();
1579        for prefix in prefixes.clone() {
1580            if prefix.starts_with(&new_prefix) {
1581                removed_keys2.insert(prefix);
1582            }
1583        }
1584        assert_eq!(
1585            removed_keys1, removed_keys2,
1586            "Inconsistent result of the computation of the intervals"
1587        );
1588        for prefix in removed_keys2 {
1589            prefixes.remove(&prefix);
1590        }
1591        prefixes.insert(new_prefix);
1592    }
1593
1594    fn test_prefix_free_set(max_len: usize, num_gen: usize, key_size: usize) {
1595        let mut rng = crate::random::make_deterministic_rng();
1596        let mut prefixes = BTreeSet::new();
1597        for _ in 0..num_gen {
1598            let new_prefix = get_prefix(&mut rng, max_len, key_size);
1599            insert_into_prefix_set(&mut prefixes, new_prefix);
1600        }
1601    }
1602
1603    // The functions `get_existing_find_{keys,key_values}_entry(_mut)`
1604    // need to be tested. The following test does some random tests
1605    // on the generated prefix free sets. Two methods are used and
1606    // their consistency are checked.
1607    #[test]
1608    fn test_lower_bounds() {
1609        test_prefix_free_set(10, 500, 2);
1610        test_prefix_free_set(6, 500, 3);
1611        test_prefix_free_set(5, 500, 4);
1612    }
1613
1614    #[test]
1615    fn test_delete_key_operations() {
1616        let mut cache = create_test_cache(true);
1617        let key1 = vec![1, 2, 3];
1618        let key2 = vec![1, 2, 4];
1619        let key3 = vec![2, 3, 4];
1620        let value = vec![42, 43, 44];
1621
1622        // Insert some values
1623        cache.put_key_value(&key1, &value);
1624        cache.check_coherence();
1625        cache.put_key_value(&key2, &value);
1626        cache.check_coherence();
1627        cache.put_key_value(&key3, &value);
1628        cache.check_coherence();
1629
1630        // Verify values are present
1631        assert_eq!(cache.query_read_value(&key1), Some(Some(value.clone())));
1632        assert_eq!(cache.query_read_value(&key2), Some(Some(value.clone())));
1633        assert_eq!(cache.query_read_value(&key3), Some(Some(value.clone())));
1634
1635        // Delete key1
1636        cache.delete_key(&key1);
1637        cache.check_coherence();
1638
1639        // Check that key1 is now marked as DoesNotExist
1640        assert_eq!(cache.query_read_value(&key1), Some(None));
1641        // Other keys should remain unchanged
1642        assert_eq!(cache.query_read_value(&key2), Some(Some(value.clone())));
1643        assert_eq!(cache.query_read_value(&key3), Some(Some(value.clone())));
1644
1645        // Delete key2
1646        cache.delete_key(&key2);
1647        cache.check_coherence();
1648
1649        // Check that key2 is now marked as DoesNotExist
1650        assert_eq!(cache.query_read_value(&key2), Some(None));
1651        // key3 should remain unchanged
1652        assert_eq!(cache.query_read_value(&key3), Some(Some(value)));
1653    }
1654
1655    #[test]
1656    fn test_find_key_values_entry_delete_prefix() {
1657        let mut find_entry = FindKeyValuesEntry(BTreeMap::new());
1658
1659        // Add some key-value pairs
1660        let key1 = vec![1, 2, 3];
1661        let key2 = vec![1, 2, 4];
1662        let key3 = vec![1, 3, 5];
1663        let key4 = vec![2, 4, 6];
1664        let value = vec![42];
1665
1666        find_entry.update_entry(&key1, Some(value.clone()));
1667        find_entry.update_entry(&key2, Some(value.clone()));
1668        find_entry.update_entry(&key3, Some(value.clone()));
1669        find_entry.update_entry(&key4, Some(value.clone()));
1670
1671        // Verify all keys are present
1672        assert!(find_entry.contains_key(&key1));
1673        assert!(find_entry.contains_key(&key2));
1674        assert!(find_entry.contains_key(&key3));
1675        assert!(find_entry.contains_key(&key4));
1676
1677        // Delete prefix [1, 2] - should remove key1 and key2
1678        find_entry.delete_prefix(&[1, 2]);
1679
1680        // Check that keys with prefix [1, 2] are removed
1681        assert!(!find_entry.contains_key(&key1));
1682        assert!(!find_entry.contains_key(&key2));
1683        // Keys with different prefixes should remain
1684        assert!(find_entry.contains_key(&key3));
1685        assert!(find_entry.contains_key(&key4));
1686
1687        // Delete prefix [1] - should remove key3
1688        find_entry.delete_prefix(&[1]);
1689
1690        // Check that key3 is now removed
1691        assert!(!find_entry.contains_key(&key3));
1692        // key4 with different prefix should remain
1693        assert!(find_entry.contains_key(&key4));
1694    }
1695
1696    #[test]
1697    fn test_trim_value_cache_removes_entries() {
1698        let mut cache = LruPrefixCache::new(
1699            StorageCacheConfig {
1700                max_cache_size: 10000,
1701                max_value_entry_size: 500,
1702                max_find_keys_entry_size: 1000,
1703                max_find_key_values_entry_size: 2000,
1704                max_cache_entries: 100,
1705                max_cache_value_size: 30, // Very small limit to force removal
1706                max_cache_find_keys_size: 1000,
1707                max_cache_find_key_values_size: 1000,
1708            },
1709            true,
1710        );
1711
1712        // Insert multiple values that exceed the max_cache_value_size
1713        let mut inserted_keys = Vec::new();
1714        for i in 0..6 {
1715            let key = vec![i];
1716            let value = vec![0; 10]; // Each entry ~10 bytes + key = ~11 bytes
1717            cache.insert_read_value(&key, &Some(value));
1718            cache.check_coherence();
1719            inserted_keys.push(key);
1720        }
1721
1722        // After trimming, total value size should be within limit
1723        assert!(cache.total_value_size <= cache.config.max_cache_value_size);
1724
1725        // Some entries should have been removed (LRU eviction)
1726        let mut remaining_count = 0;
1727        for key in &inserted_keys {
1728            if cache.query_read_value(key).is_some() {
1729                remaining_count += 1;
1730            }
1731        }
1732
1733        // We should have fewer entries than we inserted due to trimming
1734        assert!(remaining_count < inserted_keys.len());
1735
1736        // The most recently inserted entries should still be present
1737        let last_key = &inserted_keys[inserted_keys.len() - 1];
1738        assert!(cache.query_read_value(last_key).is_some());
1739    }
1740
1741    #[test]
1742    fn test_max_value_entry_size_zero_early_termination() {
1743        let mut cache = LruPrefixCache::new(
1744            StorageCacheConfig {
1745                max_cache_size: 1000,
1746                max_value_entry_size: 0, // Zero size - should cause early termination
1747                max_find_keys_entry_size: 100,
1748                max_find_key_values_entry_size: 200,
1749                max_cache_entries: 10,
1750                max_cache_value_size: 500,
1751                max_cache_find_keys_size: 500,
1752                max_cache_find_key_values_size: 500,
1753            },
1754            true,
1755        );
1756
1757        let key1 = vec![1, 2, 3];
1758        let key2 = vec![4, 5, 6];
1759        let value = vec![42, 43, 44];
1760
1761        // Insert values - should be terminated early due to max_value_entry_size == 0
1762        cache.insert_read_value(&key1, &Some(value.clone()));
1763        cache.check_coherence();
1764        cache.insert_read_value(&key2, &None);
1765        cache.check_coherence();
1766
1767        // Values should not be cached due to early termination
1768        assert_eq!(cache.query_read_value(&key1), None);
1769        assert_eq!(cache.query_read_value(&key2), None);
1770
1771        // Cache should remain empty
1772        assert_eq!(cache.total_size, 0);
1773        assert_eq!(cache.total_value_size, 0);
1774        assert!(cache.value_map.is_empty());
1775        assert!(cache.queue.is_empty());
1776
1777        // Test put_key_value also respects the early termination
1778        cache.put_key_value(&key1, &value);
1779        cache.check_coherence();
1780
1781        assert_eq!(cache.query_read_value(&key1), None);
1782        assert_eq!(cache.total_size, 0);
1783
1784        // Test delete_key also respects the early termination
1785        cache.delete_key(&key1);
1786        cache.check_coherence();
1787
1788        assert_eq!(cache.query_read_value(&key1), None);
1789        assert_eq!(cache.total_size, 0);
1790    }
1791
1792    #[test]
1793    fn test_key_value_replacement_same_length() {
1794        let mut cache = create_test_cache(true);
1795        let key = vec![1, 2, 3];
1796        let value1 = vec![42, 43, 44]; // 3 bytes
1797        let value2 = vec![99, 98, 97]; // 3 bytes - same length as value1
1798
1799        // Insert initial value
1800        cache.put_key_value(&key, &value1);
1801        cache.check_coherence();
1802
1803        // Verify initial value is present
1804        assert_eq!(cache.query_read_value(&key), Some(Some(value1.clone())));
1805
1806        let initial_size = cache.total_size;
1807        let initial_value_size = cache.total_value_size;
1808
1809        // Replace with value of same length
1810        cache.put_key_value(&key, &value2);
1811        cache.check_coherence();
1812
1813        // Verify new value is present
1814        assert_eq!(cache.query_read_value(&key), Some(Some(value2.clone())));
1815
1816        // Size should remain the same since values have same length
1817        assert_eq!(cache.total_size, initial_size);
1818        assert_eq!(cache.total_value_size, initial_value_size);
1819
1820        // Cache should still contain exactly one entry
1821        assert_eq!(cache.value_map.len(), 1);
1822        assert_eq!(cache.queue.len(), 1);
1823
1824        // Test replacement with insert_read_value as well
1825        let value3 = vec![11, 22, 33]; // 3 bytes - same length
1826        cache.insert_read_value(&key, &Some(value3.clone()));
1827        cache.check_coherence();
1828
1829        // Verify replacement worked
1830        assert_eq!(cache.query_read_value(&key), Some(Some(value3)));
1831
1832        // Size should still be the same
1833        assert_eq!(cache.total_size, initial_size);
1834        assert_eq!(cache.total_value_size, initial_value_size);
1835    }
1836
1837    #[test]
1838    fn test_max_find_keys_entry_size_zero_early_termination() {
1839        let mut cache = LruPrefixCache::new(
1840            StorageCacheConfig {
1841                max_cache_size: 1000,
1842                max_value_entry_size: 100,
1843                max_find_keys_entry_size: 0, // Zero size - should cause early termination
1844                max_find_key_values_entry_size: 200,
1845                max_cache_entries: 10,
1846                max_cache_value_size: 500,
1847                max_cache_find_keys_size: 500,
1848                max_cache_find_key_values_size: 500,
1849            },
1850            true,
1851        );
1852
1853        let prefix = vec![1, 2];
1854        let keys = vec![vec![3], vec![4], vec![5]];
1855
1856        // Insert find_keys entry - should be terminated early due to max_find_keys_entry_size == 0
1857        cache.insert_find_keys(prefix.clone(), &keys);
1858        cache.check_coherence();
1859
1860        // Find keys should not be cached due to early termination
1861        assert_eq!(cache.query_find_keys(&prefix), None);
1862
1863        // Cache should remain empty for find_keys
1864        assert_eq!(cache.total_find_keys_size, 0);
1865        assert!(cache.find_keys_map.is_empty());
1866
1867        // Verify no find_keys entries in the queue
1868        for (cache_key, _) in &cache.queue {
1869            assert!(!matches!(cache_key, CacheKey::FindKeys(_)));
1870        }
1871
1872        // Test with different prefix and keys to ensure consistent behavior
1873        let prefix2 = vec![9];
1874        let keys2 = vec![vec![1]];
1875        cache.insert_find_keys(prefix2.clone(), &keys2);
1876        cache.check_coherence();
1877
1878        assert_eq!(cache.query_find_keys(&prefix2), None);
1879        assert_eq!(cache.total_find_keys_size, 0);
1880        assert!(cache.find_keys_map.is_empty());
1881    }
1882
1883    #[test]
1884    fn test_max_find_key_values_entry_size_zero_early_termination() {
1885        let mut cache = LruPrefixCache::new(
1886            StorageCacheConfig {
1887                max_cache_size: 1000,
1888                max_value_entry_size: 100,
1889                max_find_keys_entry_size: 100,
1890                max_find_key_values_entry_size: 0, // Zero size - should cause early termination
1891                max_cache_entries: 10,
1892                max_cache_value_size: 500,
1893                max_cache_find_keys_size: 500,
1894                max_cache_find_key_values_size: 500,
1895            },
1896            true,
1897        );
1898
1899        let prefix = vec![1, 2];
1900        let key_values = vec![(vec![3], vec![10]), (vec![4], vec![20])];
1901
1902        // Insert find_key_values entry - should be terminated early due to max_find_key_values_entry_size == 0
1903        cache.insert_find_key_values(prefix.clone(), &key_values);
1904        cache.check_coherence();
1905
1906        // Find key values should not be cached due to early termination
1907        assert_eq!(cache.query_find_key_values(&prefix), None);
1908
1909        // Cache should remain empty for find_key_values
1910        assert_eq!(cache.total_find_key_values_size, 0);
1911        assert!(cache.find_key_values_map.is_empty());
1912
1913        // Verify no find_key_values entries in the queue
1914        for (cache_key, _) in &cache.queue {
1915            assert!(!matches!(cache_key, CacheKey::FindKeyValues(_)));
1916        }
1917
1918        // Test with different data to ensure consistent behavior
1919        let prefix2 = vec![9];
1920        let key_values2 = vec![(vec![1], vec![100])];
1921        cache.insert_find_key_values(prefix2.clone(), &key_values2);
1922        cache.check_coherence();
1923
1924        assert_eq!(cache.query_find_key_values(&prefix2), None);
1925        assert_eq!(cache.total_find_key_values_size, 0);
1926        assert!(cache.find_key_values_map.is_empty());
1927    }
1928
1929    #[test]
1930    fn test_value_entry_exists_returns_none() {
1931        let mut cache = create_test_cache(true);
1932        let key = vec![1, 2, 3];
1933
1934        // Insert a ValueEntry::Exists (this happens when we cache that a key exists but not its value)
1935        cache.insert_contains_key(&key, true);
1936        cache.check_coherence();
1937
1938        // Verify that contains_key query returns Some(true)
1939        assert_eq!(cache.query_contains_key(&key), Some(true));
1940
1941        // When querying for the actual value with ValueEntry::Exists, it should return None
1942        // because we only know the key exists but don't have the actual value cached
1943        assert_eq!(cache.query_read_value(&key), None);
1944
1945        // Test with a key that doesn't exist
1946        let key2 = vec![4, 5, 6];
1947        cache.insert_contains_key(&key2, false);
1948        cache.check_coherence();
1949
1950        // This should return Some(false) for contains_key
1951        assert_eq!(cache.query_contains_key(&key2), Some(false));
1952
1953        // And Some(None) for read_value since we cached that it doesn't exist
1954        assert_eq!(cache.query_read_value(&key2), Some(None));
1955
1956        // Verify the cache state - we should have both entries
1957        assert_eq!(cache.value_map.len(), 2);
1958        assert_eq!(cache.queue.len(), 2);
1959
1960        // Both entries should be ValueEntry::Exists and ValueEntry::DoesNotExist respectively
1961        assert!(matches!(
1962            cache.value_map.get(&key),
1963            Some(ValueEntry::Exists)
1964        ));
1965        assert!(matches!(
1966            cache.value_map.get(&key2),
1967            Some(ValueEntry::DoesNotExist)
1968        ));
1969    }
1970
1971    #[test]
1972    fn test_find_keys_entry_delete_prefix_function() {
1973        let mut find_entry = FindKeysEntry(BTreeSet::new());
1974
1975        // Add some keys
1976        let key1 = vec![1, 2, 3];
1977        let key2 = vec![1, 2, 4];
1978        let key3 = vec![1, 3, 5];
1979        let key4 = vec![2, 4, 6];
1980
1981        find_entry.update_entry(&key1, true);
1982        find_entry.update_entry(&key2, true);
1983        find_entry.update_entry(&key3, true);
1984        find_entry.update_entry(&key4, true);
1985
1986        // Verify all keys are present
1987        assert!(find_entry.contains_key(&key1));
1988        assert!(find_entry.contains_key(&key2));
1989        assert!(find_entry.contains_key(&key3));
1990        assert!(find_entry.contains_key(&key4));
1991        assert_eq!(find_entry.0.len(), 4);
1992
1993        // Test delete_prefix function directly - delete prefix [1, 2]
1994        find_entry.delete_prefix(&[1, 2]);
1995
1996        // Check that keys with prefix [1, 2] are removed
1997        assert!(!find_entry.contains_key(&key1));
1998        assert!(!find_entry.contains_key(&key2));
1999        // Keys with different prefixes should remain
2000        assert!(find_entry.contains_key(&key3));
2001        assert!(find_entry.contains_key(&key4));
2002        assert_eq!(find_entry.0.len(), 2);
2003
2004        // Test delete_prefix with prefix [1] - should remove key3
2005        find_entry.delete_prefix(&[1]);
2006
2007        // Check that key3 is now removed
2008        assert!(!find_entry.contains_key(&key3));
2009        // key4 with different prefix should remain
2010        assert!(find_entry.contains_key(&key4));
2011        assert_eq!(find_entry.0.len(), 1);
2012
2013        // Test delete_prefix with empty prefix - should remove all remaining keys
2014        find_entry.delete_prefix(&[]);
2015
2016        // All keys should be removed
2017        assert!(!find_entry.contains_key(&key4));
2018        assert_eq!(find_entry.0.len(), 0);
2019    }
2020
2021    #[test]
2022    fn test_find_keys_size_decrease() {
2023        let mut cache = create_test_cache(true);
2024        let prefix = vec![1];
2025        let initial_keys = vec![vec![2, 3, 4], vec![3, 4, 5]]; // Larger keys
2026
2027        // Insert initial find_keys entry
2028        cache.insert_find_keys(prefix.clone(), &initial_keys);
2029        cache.check_coherence();
2030
2031        let initial_total_size = cache.total_size;
2032        let initial_find_keys_size = cache.total_find_keys_size;
2033
2034        // Now delete one of the keys, which should decrease the size
2035        let key_to_delete = vec![1, 2, 3, 4]; // This matches prefix + first key
2036        cache.delete_key(&key_to_delete);
2037        cache.check_coherence();
2038
2039        // The find_keys entry should have been updated and size decreased
2040        assert!(cache.total_size < initial_total_size);
2041        assert!(cache.total_find_keys_size < initial_find_keys_size);
2042
2043        // Verify the key was actually removed from the find_keys entry
2044        let result = cache.query_find_keys(&prefix);
2045        assert!(result.is_some());
2046        let keys = result.unwrap();
2047        assert!(keys.contains(&vec![3, 4, 5])); // Second key should still be there
2048        assert!(!keys.contains(&vec![2, 3, 4])); // First key should be gone
2049
2050        cache.check_coherence();
2051    }
2052
2053    #[test]
2054    fn test_trim_find_keys_cache_lru_eviction() {
2055        let mut cache = LruPrefixCache::new(
2056            StorageCacheConfig {
2057                max_cache_size: 10000,
2058                max_value_entry_size: 500,
2059                max_find_keys_entry_size: 1000,
2060                max_find_key_values_entry_size: 2000,
2061                max_cache_entries: 100,
2062                max_cache_value_size: 5000,
2063                max_cache_find_keys_size: 50, // Small limit to trigger trimming
2064                max_cache_find_key_values_size: 5000,
2065            },
2066            true,
2067        );
2068
2069        // Insert first find_keys entry
2070        let prefix1 = vec![1];
2071        let keys1 = vec![vec![2; 10], vec![3; 10]]; // ~20 bytes
2072        cache.insert_find_keys(prefix1.clone(), &keys1);
2073        cache.check_coherence();
2074
2075        // Insert second find_keys entry
2076        let prefix2 = vec![2];
2077        let keys2 = vec![vec![4; 10], vec![5; 10]]; // ~20 bytes
2078        cache.insert_find_keys(prefix2.clone(), &keys2);
2079        cache.check_coherence();
2080
2081        // Both entries should be present at this point
2082        assert!(cache.query_find_keys(&prefix1).is_some());
2083        assert!(cache.query_find_keys(&prefix2).is_some());
2084
2085        // Insert third find_keys entry that should trigger trimming
2086        let prefix3 = vec![3];
2087        let keys3 = vec![vec![6; 10], vec![7; 10]]; // ~20 bytes
2088        cache.insert_find_keys(prefix3.clone(), &keys3);
2089        cache.check_coherence();
2090
2091        // The cache should have trimmed to stay within max_cache_find_keys_size
2092        assert!(cache.total_find_keys_size <= cache.config.max_cache_find_keys_size);
2093
2094        // The least recently used entry (prefix1) should have been evicted
2095        assert_eq!(cache.query_find_keys(&prefix1), None);
2096
2097        // The more recent entries should still be present
2098        assert!(cache.query_find_keys(&prefix2).is_some());
2099        assert!(cache.query_find_keys(&prefix3).is_some());
2100
2101        // Verify we have fewer find_keys entries than we inserted
2102        assert!(cache.find_keys_map.len() < 3);
2103    }
2104
2105    #[test]
2106    fn test_find_keys_removal_from_map() {
2107        let mut cache = LruPrefixCache::new(
2108            StorageCacheConfig {
2109                max_cache_size: 100, // Small cache to trigger eviction
2110                max_value_entry_size: 50,
2111                max_find_keys_entry_size: 1000,
2112                max_find_key_values_entry_size: 2000,
2113                max_cache_entries: 3, // Very small to force eviction
2114                max_cache_value_size: 500,
2115                max_cache_find_keys_size: 500,
2116                max_cache_find_key_values_size: 500,
2117            },
2118            true,
2119        );
2120
2121        let prefix1 = vec![1];
2122        let prefix2 = vec![2];
2123        let prefix3 = vec![3];
2124        let keys = vec![vec![1], vec![2]];
2125
2126        // Insert find_keys entries to fill the cache
2127        cache.insert_find_keys(prefix1.clone(), &keys);
2128        cache.check_coherence();
2129        cache.insert_find_keys(prefix2.clone(), &keys);
2130        cache.check_coherence();
2131
2132        // Verify both entries are present
2133        assert!(cache.find_keys_map.contains_key(&prefix1));
2134        assert!(cache.find_keys_map.contains_key(&prefix2));
2135
2136        // Insert third entry that should trigger eviction and call remove_cache_key_from_map for FindKeys
2137        cache.insert_find_keys(prefix3.clone(), &keys);
2138        cache.check_coherence();
2139
2140        // The first entry should have been evicted
2141        assert!(!cache.find_keys_map.contains_key(&prefix1));
2142        // The newer entries should still be present
2143        assert!(cache.find_keys_map.contains_key(&prefix2));
2144        assert!(cache.find_keys_map.contains_key(&prefix3));
2145
2146        // Verify cache constraints are maintained
2147        assert!(cache.queue.len() <= cache.config.max_cache_entries);
2148    }
2149
2150    #[test]
2151    fn test_find_key_values_removal_from_map() {
2152        let mut cache = LruPrefixCache::new(
2153            StorageCacheConfig {
2154                max_cache_size: 100, // Small cache to trigger eviction
2155                max_value_entry_size: 50,
2156                max_find_keys_entry_size: 1000,
2157                max_find_key_values_entry_size: 2000,
2158                max_cache_entries: 3, // Very small to force eviction
2159                max_cache_value_size: 500,
2160                max_cache_find_keys_size: 500,
2161                max_cache_find_key_values_size: 500,
2162            },
2163            true,
2164        );
2165
2166        let prefix1 = vec![1];
2167        let prefix2 = vec![2];
2168        let prefix3 = vec![3];
2169        let key_values = vec![(vec![1], vec![10]), (vec![2], vec![20])];
2170
2171        // Insert find_key_values entries to fill the cache
2172        cache.insert_find_key_values(prefix1.clone(), &key_values);
2173        cache.check_coherence();
2174        cache.insert_find_key_values(prefix2.clone(), &key_values);
2175        cache.check_coherence();
2176
2177        // Verify both entries are present
2178        assert!(cache.find_key_values_map.contains_key(&prefix1));
2179        assert!(cache.find_key_values_map.contains_key(&prefix2));
2180
2181        // Insert third entry that should trigger eviction and call remove_cache_key_from_map for FindKeyValues
2182        cache.insert_find_key_values(prefix3.clone(), &key_values);
2183        cache.check_coherence();
2184
2185        // The first entry should have been evicted
2186        assert!(!cache.find_key_values_map.contains_key(&prefix1));
2187        // The newer entries should still be present
2188        assert!(cache.find_key_values_map.contains_key(&prefix2));
2189        assert!(cache.find_key_values_map.contains_key(&prefix3));
2190
2191        // Verify cache constraints are maintained
2192        assert!(cache.queue.len() <= cache.config.max_cache_entries);
2193    }
2194
2195    #[test]
2196    fn test_contains_key_failing_without_exclusive_access() {
2197        let mut cache = create_test_cache(false); // has_exclusive_access = false
2198        let key = vec![1, 2, 3];
2199
2200        // With has_exclusive_access = false, query_contains_key should only check value_map
2201        // Since the key is not in value_map, it should return None
2202        let result = cache.query_contains_key(&key);
2203        assert_eq!(result, None);
2204
2205        // Verify that only value_map is checked by inserting directly into value_map
2206        cache.insert_contains_key(&key, true);
2207        cache.check_coherence();
2208
2209        // Now it should return Some(true) because it's found in value_map
2210        let result = cache.query_contains_key(&key);
2211        assert_eq!(result, Some(true));
2212    }
2213
2214    #[test]
2215    fn test_contains_key_found_in_find_key_values() {
2216        let mut cache = create_test_cache(true); // has_exclusive_access = true
2217        let prefix = vec![1, 2];
2218        let key = vec![1, 2, 3, 4];
2219        let key_values = vec![(vec![3, 4], vec![100]), (vec![5, 6], vec![200])];
2220
2221        // Insert a FindKeyValues entry that contains the key we'll query
2222        cache.insert_find_key_values(prefix.clone(), &key_values);
2223        cache.check_coherence();
2224
2225        // Query for the key - this should find it in FindKeyValues (lines 852-854)
2226        let result = cache.query_contains_key(&key);
2227        assert_eq!(result, Some(true));
2228
2229        // Test with a key that doesn't exist in the FindKeyValues
2230        let non_existent_key = vec![1, 2, 7, 8];
2231        let result = cache.query_contains_key(&non_existent_key);
2232        assert_eq!(result, Some(false)); // Found the prefix but key doesn't exist in the entry
2233
2234        // Test with a key that doesn't match any prefix
2235        let unmatched_key = vec![9, 9, 9];
2236        let result = cache.query_contains_key(&unmatched_key);
2237        assert_eq!(result, None); // No matching prefix found
2238    }
2239
2240    #[test]
2241    fn test_find_keys_removal_when_inserting_broader_find_keys() {
2242        let mut cache = create_test_cache(true);
2243
2244        // Insert another FindKeys entry with a more specific prefix
2245        let specific_prefix = vec![1, 2, 3, 4];
2246        let keys2 = vec![vec![6], vec![7]];
2247        cache.insert_find_keys(specific_prefix.clone(), &keys2);
2248        cache.check_coherence();
2249
2250        // Insert a FindKeys entry with a specific prefix
2251        let narrow_prefix = vec![1, 2, 3];
2252        let keys1 = vec![vec![4, 6], vec![4, 7]];
2253        cache.insert_find_keys(narrow_prefix.clone(), &keys1);
2254        cache.check_coherence();
2255    }
2256
2257    #[test]
2258    fn test_overlapping_find_key_values_removes_find_keys_and_find_key_values() {
2259        let mut cache = create_test_cache(true);
2260
2261        // Insert a FindKeys entry
2262        let find_keys_prefix = vec![1, 2, 3];
2263        let keys = vec![vec![4, 6], vec![4, 7], vec![5]];
2264        cache.insert_find_keys(find_keys_prefix.clone(), &keys);
2265        cache.check_coherence();
2266
2267        // Insert a FindKeyValues entry with a different but overlapping prefix
2268        let find_key_values_prefix = vec![1, 2, 3, 4];
2269        let key_values1 = vec![(vec![6], vec![10]), (vec![7], vec![20])];
2270        cache.insert_find_key_values(find_key_values_prefix.clone(), &key_values1);
2271        cache.check_coherence();
2272
2273        // Inserts a Value
2274        cache.put_key_value(&[1, 2, 8, 9], &[254]);
2275        cache.check_coherence();
2276
2277        // Now insert a broader FindKeyValues entry that overlaps with both previous entries
2278        let broad_prefix = vec![1, 2];
2279        let key_values2 = vec![
2280            (vec![3, 4, 6], vec![10]),
2281            (vec![3, 4, 7], vec![20]),
2282            (vec![3, 5], vec![34]),
2283            (vec![8, 9], vec![254]),
2284        ];
2285        cache.insert_find_key_values(broad_prefix.clone(), &key_values2);
2286        cache.check_coherence();
2287
2288        // The broader FindKeyValues should have removed the overlapping FindKeys entry.
2289        assert!(!cache.find_keys_map.contains_key(&find_keys_prefix));
2290
2291        // The broader FindKeyValues should have removed the overlapping FindKeyValues entry.
2292        assert!(!cache
2293            .find_key_values_map
2294            .contains_key(&find_key_values_prefix));
2295
2296        // The new broad FindKeyValues entry should exist
2297        assert!(cache.find_key_values_map.contains_key(&broad_prefix));
2298
2299        // Verify the new entry has the expected key-values
2300        let key_values = cache.query_find_key_values(&broad_prefix).unwrap();
2301        assert!(key_values.contains(&(vec![3, 4, 6], vec![10])));
2302        assert!(key_values.contains(&(vec![3, 4, 7], vec![20])));
2303        assert!(key_values.contains(&(vec![8, 9], vec![254])));
2304
2305        // Test that we can still query for keys under the broad prefix
2306        let query_result = cache.query_contains_key(&[1, 2, 3, 1]);
2307        assert_eq!(query_result, Some(false)); // Should find it in the new FindKeyValues entry
2308    }
2309
2310    #[test]
2311    fn test_delete_prefix_removes_entire_find_keys_entry() {
2312        let mut cache = create_test_cache(true); // has_exclusive_access = true
2313
2314        // Insert a FindKeys entry
2315        let prefix = vec![1, 2, 3];
2316        let keys = vec![vec![4], vec![5], vec![6]];
2317        cache.insert_find_keys(prefix.clone(), &keys);
2318        cache.check_coherence();
2319
2320        // Verify the FindKeys entry exists
2321        assert!(cache.find_keys_map.contains_key(&prefix));
2322        let result = cache.query_find_keys(&prefix);
2323        assert!(result.is_some());
2324
2325        // Delete a prefix that covers the entire FindKeys entry
2326        let delete_prefix = vec![1, 2]; // This covers [1, 2, 3]
2327        cache.delete_prefix(&delete_prefix);
2328        cache.check_coherence();
2329
2330        // Verify the entry is no longer queryable
2331        let result = cache.query_find_keys(&prefix);
2332        assert_eq!(result, Some(vec![]));
2333
2334        // Verify the queue no longer contains the FindKeys entry
2335        for (cache_key, _) in &cache.queue {
2336            assert!(!matches!(cache_key, CacheKey::FindKeys(key) if key == &prefix));
2337        }
2338    }
2339
2340    #[test]
2341    fn test_delete_prefix_removes_keys_within_find_keys_entry() {
2342        let mut cache = create_test_cache(true); // has_exclusive_access = true
2343
2344        // Insert a FindKeys entry with a broader prefix
2345        let find_keys_prefix = vec![1];
2346        let keys = vec![vec![2, 3, 4], vec![2, 3, 5], vec![2, 4, 6], vec![3, 7, 8]];
2347        cache.insert_find_keys(find_keys_prefix.clone(), &keys);
2348        cache.check_coherence();
2349
2350        // Verify the FindKeys entry exists and contains all keys
2351        assert!(cache.find_keys_map.contains_key(&find_keys_prefix));
2352        let initial_keys = cache.query_find_keys(&find_keys_prefix).unwrap();
2353        assert!(initial_keys.contains(&vec![2, 3, 4]));
2354        assert!(initial_keys.contains(&vec![2, 3, 5]));
2355        assert!(initial_keys.contains(&vec![2, 4, 6]));
2356        assert!(initial_keys.contains(&vec![3, 7, 8]));
2357
2358        let initial_size = cache.total_find_keys_size;
2359
2360        // Delete a prefix that only affects some keys within the FindKeys entry
2361        let delete_prefix = vec![1, 2, 3]; // This should only affect keys [2,3,4] and [2,3,5]
2362        cache.delete_prefix(&delete_prefix);
2363        cache.check_coherence();
2364
2365        // The FindKeys entry should still exist but with fewer keys
2366        assert!(cache.find_keys_map.contains_key(&find_keys_prefix));
2367
2368        // Verify that only the keys with prefix [2,3] were removed
2369        let remaining_keys = cache.query_find_keys(&find_keys_prefix).unwrap();
2370        assert!(!remaining_keys.contains(&vec![2, 3, 4])); // Should be removed
2371        assert!(!remaining_keys.contains(&vec![2, 3, 5])); // Should be removed
2372        assert!(remaining_keys.contains(&vec![2, 4, 6])); // Should remain
2373        assert!(remaining_keys.contains(&vec![3, 7, 8])); // Should remain
2374
2375        // The cache size should have decreased due to the removed keys
2376        assert!(cache.total_find_keys_size < initial_size);
2377
2378        // Test another delete that removes more keys
2379        let delete_prefix2 = vec![1, 2]; // This should affect key [2,4,6]
2380        cache.delete_prefix(&delete_prefix2);
2381        cache.check_coherence();
2382
2383        // Check the remaining keys
2384        let final_keys = cache.query_find_keys(&find_keys_prefix).unwrap();
2385        assert!(!final_keys.contains(&vec![2, 4, 6])); // Should now be removed
2386        assert!(final_keys.contains(&vec![3, 7, 8])); // Should still remain
2387    }
2388
2389    #[test]
2390    fn test_put_key_value_without_find_key_values_match() {
2391        let mut cache = create_test_cache(false); // has_exclusive_access = true
2392        let key = vec![1, 2, 3, 4];
2393        let value = vec![100, 200];
2394
2395        // The value should be inserted without accessing the FindKeys / FindKeyValues.
2396        cache.put_key_value(&key, &value);
2397        cache.check_coherence();
2398
2399        // Testing the reading of value.
2400        assert_eq!(cache.query_read_value(&key), Some(Some(value.clone())));
2401        assert!(cache.value_map.contains_key(&key));
2402    }
2403
2404    #[test]
2405    fn test_delete_key_without_exclusive_access() {
2406        let mut cache = create_test_cache(false); // has_exclusive_access = false
2407        let key = vec![1, 2, 3];
2408        let value = vec![42, 43, 44];
2409
2410        // Insert a value first
2411        cache.insert_read_value(&key, &Some(value.clone()));
2412        cache.check_coherence();
2413
2414        // Verify the value is cached
2415        assert_eq!(cache.query_read_value(&key), Some(Some(value)));
2416        assert!(cache.value_map.contains_key(&key));
2417
2418        // Delete the key without exclusive access. So, do not use the
2419        // FindKeys/FindKeyValues.
2420        cache.delete_key(&key);
2421        cache.check_coherence();
2422
2423        // The entry should be removed from the cache.
2424        assert!(!cache.value_map.contains_key(&key));
2425        assert_eq!(cache.query_read_value(&key), None);
2426
2427        // Verify the queue no longer contains the entry
2428        for (cache_key, _) in &cache.queue {
2429            assert!(!matches!(cache_key, CacheKey::Value(k) if k == &key));
2430        }
2431
2432        // Test deleting a key that doesn't exist
2433        let non_existent_key = vec![9, 9, 9];
2434        cache.delete_key(&non_existent_key); // Should not crash
2435        cache.check_coherence();
2436    }
2437
2438    #[test]
2439    fn test_line_502_insert_then_delete_without_exclusive_access() {
2440        let mut cache = create_test_cache(false); // has_exclusive_access = false
2441        let key = vec![1, 2, 3, 4];
2442        let value = vec![100, 200, 201];
2443
2444        // First insert a value entry
2445        cache.insert_read_value(&key, &Some(value.clone()));
2446        cache.check_coherence();
2447
2448        // Verify the value is cached
2449        assert_eq!(cache.query_read_value(&key), Some(Some(value)));
2450        assert!(cache.value_map.contains_key(&key));
2451
2452        // Now insert a DoesNotExist entry (simulating a delete) without exclusive access
2453        // This should trigger line 502: removal due to !has_exclusive_access
2454        cache.insert_read_value(&key, &None);
2455        cache.check_coherence();
2456
2457        // The entry should be completely removed from the cache (line 502)
2458        assert!(!cache.value_map.contains_key(&key));
2459        assert_eq!(cache.query_read_value(&key), None);
2460
2461        // Verify the cache key is removed from the queue
2462        let queue_contains_key = cache
2463            .queue
2464            .iter()
2465            .any(|(cache_key, _)| matches!(cache_key, CacheKey::Value(k) if k == &key));
2466        assert!(!queue_contains_key);
2467    }
2468
2469    #[test]
2470    fn test_does_not_exist_removal_during_insert_find_keys() {
2471        let mut cache = create_test_cache(true); // has_exclusive_access = true
2472        let prefix = vec![1, 2];
2473        let key1 = vec![1, 2, 3];
2474        let key2 = vec![1, 2, 4];
2475        let key3 = vec![1, 2, 5];
2476
2477        // Insert DoesNotExist entries for keys that will be covered by the FindKeys
2478        cache.insert_read_value(&key1, &None); // Creates DoesNotExist entry
2479        cache.insert_read_value(&key2, &None); // Creates DoesNotExist entry
2480        cache.insert_read_value(&key3, &Some(vec![100])); // Creates Value entry (should not be removed)
2481        cache.check_coherence();
2482
2483        // Verify the DoesNotExist entries are cached
2484        assert_eq!(cache.query_read_value(&key1), Some(None));
2485        assert_eq!(cache.query_read_value(&key2), Some(None));
2486        assert_eq!(cache.query_read_value(&key3), Some(Some(vec![100])));
2487        assert!(cache.value_map.contains_key(&key1));
2488        assert!(cache.value_map.contains_key(&key2));
2489        assert!(cache.value_map.contains_key(&key3));
2490
2491        // Insert a FindKeys entry that covers the prefix - this should trigger line 640
2492        // Line 640 filters DoesNotExist entries for removal, but not Value entries
2493        let find_keys_result = vec![key1.clone(), key2.clone(), key3.clone()];
2494        cache.insert_find_keys(prefix.clone(), &find_keys_result);
2495        cache.check_coherence();
2496
2497        // After insert_find_keys, the DoesNotExist entries should be removed (line 640)
2498        // but the Value entry should remain (line 642 returns None for Value entries)
2499        assert_eq!(cache.query_read_value(&key1), None); // DoesNotExist removed
2500        assert_eq!(cache.query_read_value(&key2), None); // DoesNotExist removed
2501        assert_eq!(cache.query_read_value(&key3), Some(Some(vec![100]))); // Value entry kept
2502        assert!(!cache.value_map.contains_key(&key1));
2503        assert!(!cache.value_map.contains_key(&key2));
2504        assert!(cache.value_map.contains_key(&key3)); // Value entry remains
2505
2506        // Verify the FindKeys entry was created
2507        assert_eq!(cache.query_find_keys(&prefix), Some(find_keys_result));
2508    }
2509
2510    #[test]
2511    fn test_trim_value_cache_complete_iteration() {
2512        let mut cache = create_test_cache(true);
2513
2514        // Insert some value entries to populate the cache
2515        let key1 = vec![1, 2, 3];
2516        let key2 = vec![4, 5, 6];
2517        let value1 = vec![100, 200];
2518        let value2 = vec![203, 177];
2519
2520        cache.insert_read_value(&key1, &Some(value1));
2521        cache.insert_read_value(&key2, &Some(value2));
2522        cache.check_coherence();
2523
2524        // Set cache size to 0 to force trimming but ensure queue is not empty
2525        cache.config.max_cache_value_size = 0;
2526
2527        // Call trim_value_cache - this should iterate through entire queue
2528        // and hit line 411 (break when iter.next() returns None)
2529        cache.trim_value_cache();
2530        cache.check_coherence();
2531
2532        // All value entries should be removed since max_cache_value_size = 0
2533        assert!(!cache.value_map.contains_key(&key1));
2534        assert!(!cache.value_map.contains_key(&key2));
2535    }
2536
2537    #[test]
2538    fn test_trim_find_keys_cache_complete_iteration() {
2539        let mut cache = create_test_cache(true);
2540
2541        // Insert some FindKeys entries to populate the cache
2542        let prefix1 = vec![1, 2];
2543        let prefix2 = vec![3, 4];
2544        let keys1 = vec![vec![1, 2, 3], vec![1, 2, 4]];
2545        let keys2 = vec![vec![3, 4, 5], vec![3, 4, 6]];
2546
2547        cache.insert_find_keys(prefix1, &keys1);
2548        cache.insert_find_keys(prefix2, &keys2);
2549        cache.check_coherence();
2550
2551        // Set cache size to 0 to force trimming but ensure queue is not empty
2552        cache.config.max_cache_find_keys_size = 0;
2553
2554        // Call trim_find_keys_cache - this should iterate through entire queue
2555        // and hit line 436 (break when iter.next() returns None)
2556        cache.trim_find_keys_cache();
2557        cache.check_coherence();
2558
2559        // All FindKeys entries should be removed since max_cache_find_keys_size = 0
2560        assert!(cache.find_keys_map.is_empty());
2561    }
2562
2563    #[test]
2564    fn test_trim_find_key_values_cache_complete_iteration() {
2565        let mut cache = create_test_cache(true);
2566
2567        // Insert some FindKeyValues entries to populate the cache
2568        let prefix1 = vec![1, 2];
2569        let prefix2 = vec![3, 4];
2570        let key_values1 = vec![(vec![1, 2, 3], vec![100]), (vec![1, 2, 4], vec![200])];
2571        let key_values2 = vec![(vec![3, 4, 5], vec![203]), (vec![3, 4, 6], vec![177])];
2572
2573        cache.insert_find_key_values(prefix1, &key_values1);
2574        cache.insert_find_key_values(prefix2, &key_values2);
2575        cache.check_coherence();
2576
2577        // Set cache size to 0 to force trimming but ensure queue is not empty
2578        cache.config.max_cache_find_key_values_size = 0;
2579
2580        // Call trim_find_key_values_cache - this should iterate through entire queue
2581        // and hit line 461 (break when iter.next() returns None)
2582        cache.trim_find_key_values_cache();
2583        cache.check_coherence();
2584
2585        // All FindKeyValues entries should be removed since max_cache_find_key_values_size = 0
2586        assert!(cache.find_key_values_map.is_empty());
2587    }
2588
2589    #[test]
2590    fn test_trim_cache_breaks_on_empty_queue() {
2591        let mut cache = LruPrefixCache::new(
2592            StorageCacheConfig {
2593                max_cache_size: 10000,       // to make irrelevant
2594                max_value_entry_size: 10000, // to make irrelevant
2595                max_find_keys_entry_size: 10000,
2596                max_find_key_values_entry_size: 10000,
2597                max_cache_entries: 10,
2598                max_cache_value_size: 500,
2599                max_cache_find_keys_size: 500,
2600                max_cache_find_key_values_size: 500,
2601            },
2602            true,
2603        );
2604
2605        // Insert some entries to populate the cache
2606        for i in 0..10 {
2607            let key = vec![1, 2, i];
2608            let value = vec![100 + i];
2609            cache.insert_read_value(&key, &Some(value));
2610            cache.check_coherence();
2611        }
2612
2613        // Manually manipulate total_size so that the cache gets emptied.
2614        cache.config.max_cache_size = 0;
2615
2616        // Inserting something that triggers the whole cache being emptied.
2617        let key = vec![1, 2];
2618        let value = vec![100];
2619        cache.insert_read_value(&key, &Some(value));
2620        cache.check_coherence();
2621    }
2622}