Skip to main content

fxfs/
lsm_tree.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! # End-Key Indexing for File Extents
6//!
7//! Fxfs indexes file extents by their **end offset** because it avoids expensive reverse
8//! iteration (`Prev()`) during lookups in the LSM tree.
9//!
10//! If we indexed by start offset, a `Seek(>= X)` would return the extent starting *after* X,
11//! requiring a `Prev()` to find the extent actually containing X.
12//!
13//! By indexing by end offset, a `Seek(>= X + 1)` returns the first extent ending *after* X.
14//! Since extents do not overlap, this is the only extent that could possibly contain X,
15//! eliminating the need for backtracking.
16
17mod bloom_filter;
18pub mod cache;
19pub mod merge;
20pub mod persistent_layer;
21pub mod skip_list_layer;
22pub mod types;
23
24#[cfg(any(test, fuzz))]
25pub mod testing;
26
27use crate::drop_event::DropEvent;
28use crate::log::*;
29use crate::metrics::DurationMeasureScope;
30use crate::object_handle::{LayerObject, WriteBytes};
31use crate::object_store::ObjectStore;
32use crate::serialized_types::{LATEST_VERSION, Version};
33
34use anyhow::Error;
35use cache::{ObjectCache, ObjectCacheResult};
36
37use fuchsia_inspect::HistogramProperty;
38use fuchsia_sync::RwLock;
39use fxfs_crypto::Crypt;
40use persistent_layer::{PersistentLayer, PersistentLayerWriter};
41use skip_list_layer::SkipListLayer;
42use std::fmt;
43use std::ops::Bound;
44use std::sync::atomic::{AtomicUsize, Ordering};
45use std::sync::{Arc, Mutex};
46use storage_units::BlockSize;
47use types::{
48    Existence, Item, ItemRef, Key, Layer, LayerIterator, LayerKey, LayerWriter, MaybeContainsKey,
49    MergeType, MergeableKey, OrdLowerBound, Value,
50};
51
52pub use merge::Query;
53
54const SKIP_LIST_LAYER_ITEMS: usize = 512;
55
56// For serialization.
57pub use persistent_layer::{
58    LayerHeader as PersistentLayerHeader, LayerHeaderV39 as PersistentLayerHeaderV39,
59    LayerInfo as PersistentLayerInfo, LayerInfoV39 as PersistentLayerInfoV39, SyncPersistentLayer,
60    layer_from_handle, open_layers,
61};
62
63pub async fn layers_from_handles<K: Key, V: Value>(
64    handles: impl IntoIterator<Item = impl LayerObject + 'static>,
65) -> Result<Vec<Arc<dyn Layer<K, V>>>, Error> {
66    let mut layers = Vec::new();
67    for handle in handles {
68        layers.push(PersistentLayer::open(handle).await?);
69    }
70    Ok(layers)
71}
72
73#[derive(Eq, PartialEq, Debug)]
74pub enum Operation {
75    Insert,
76    ReplaceOrInsert,
77    MergeInto,
78}
79
80pub type MutationCallback<K, V> = Option<Box<dyn Fn(Operation, &Item<K, V>) + Send + Sync>>;
81
82struct Inner<K, V> {
83    mutable_layer: Arc<SkipListLayer<K, V>>,
84    layers: Vec<Arc<dyn Layer<K, V>>>,
85    mutation_callback: MutationCallback<K, V>,
86}
87
88pub const LOG2_HISTOGRAM_BUCKETS: usize = 32;
89
90/// Metrics related to LSM tree churn, layer depths, and compaction performance.
91pub struct CompactionCounters {
92    /// Total number of compaction events that merged layers together.
93    pub compactions: u64,
94    /// Total bytes written during compaction, useful for measuring write amplification.
95    pub compaction_bytes_written: u64,
96    /// Total duration spent compacting layers.
97    pub compaction_time_ns: u64,
98    /// Number of mutable layers sealed. Useful for measuring churn.
99    pub total_layers_added: u64,
100    /// The maximum depth of the LSM tree observed. An indicator of worst-case read amplification.
101    pub max_layer_count: u64,
102    /// Log2 histogram of the sizes of newly compacted layers, used to verify compaction heuristics.
103    pub layer_size_histogram: [u64; LOG2_HISTOGRAM_BUCKETS],
104}
105
106impl Default for CompactionCounters {
107    fn default() -> Self {
108        Self {
109            compactions: 0,
110            compaction_bytes_written: 0,
111            compaction_time_ns: 0,
112            total_layers_added: 0,
113            max_layer_count: 0,
114            layer_size_histogram: [0; LOG2_HISTOGRAM_BUCKETS],
115        }
116    }
117}
118
119/// Global counters and metrics for an LSM tree's lifetime.
120pub struct TreeCounters {
121    /// Number of individual key-lookup attempts (reads) through the tree.
122    pub num_seeks: AtomicUsize,
123    /// Tracks the number of layer files we might have looked at across all seeks.
124    /// Used alongside `layer_files_skipped` to compute the effectiveness of bloom filters.
125    pub layer_files_total: AtomicUsize,
126    /// Tracks how many layer files we skipped searching thanks to the bloom filter rejecting them.
127    pub layer_files_skipped: AtomicUsize,
128    /// Tracks how many times a bloom filter returned true but the key was not found in the layer
129    /// (false positive) during point queries. Range-based queries are not able to properly
130    /// measure false positives since it is possible for them to find a key different than the
131    /// one that hit in the Bloom filter, which would skew the values.
132    pub bloom_filter_false_positives: AtomicUsize,
133    /// Tracks how many times a bloom filter rejected a point query across all layers (true
134    /// negative). Range-based queries are excluded to align with
135    /// `bloom_filter_false_positives`.
136    pub bloom_filter_negatives: AtomicUsize,
137    /// Tracks the number of queries that had an excessive number of fuzzy hash partitions.
138    pub excessive_hash_partitions: AtomicUsize,
139    /// Embedded counters for mutable metrics that require locking.
140    pub compaction: Mutex<CompactionCounters>,
141}
142
143impl Default for TreeCounters {
144    fn default() -> Self {
145        Self {
146            num_seeks: AtomicUsize::new(0),
147            layer_files_total: AtomicUsize::new(0),
148            layer_files_skipped: AtomicUsize::new(0),
149            bloom_filter_false_positives: AtomicUsize::new(0),
150            bloom_filter_negatives: AtomicUsize::new(0),
151            excessive_hash_partitions: AtomicUsize::new(0),
152            compaction: Mutex::new(CompactionCounters::default()),
153        }
154    }
155}
156
157/// Writes the items yielded by the iterator into the supplied object.
158#[fxfs_trace::trace]
159pub async fn compact_with_iterator<K: Key, V: Value, W: WriteBytes + Send>(
160    mut iterator: impl LayerIterator<K, V>,
161    num_items: usize,
162    writer: W,
163    block_size: BlockSize,
164    mut yielder: Option<impl Yielder>,
165) -> Result<u64, Error> {
166    let mut writer = PersistentLayerWriter::<W, K, V>::new(writer, num_items, block_size).await?;
167    while let Some(item_ref) = iterator.get() {
168        debug!(item_ref:?; "compact: writing");
169        writer.write(item_ref).await?;
170        iterator.advance().await?;
171        if let Some(y) = yielder.as_mut() {
172            y.yield_now().await;
173        }
174    }
175    writer.complete().await
176}
177
178/// LSMTree manages a tree of layers to provide a key/value store.  Each layer contains deltas on
179/// the preceding layer.  The top layer is an in-memory mutable layer.  Layers can be compacted to
180/// form a new combined layer.
181pub struct LSMTree<K, V> {
182    data: RwLock<Inner<K, V>>,
183    merge_fn: merge::MergeFn<K, V>,
184    cache: Option<Box<dyn ObjectCache<K, V>>>,
185    counters: Arc<TreeCounters>,
186}
187
188#[fxfs_trace::trace]
189impl<'tree, K: MergeableKey, V: Value> LSMTree<K, V> {
190    /// Creates a new empty tree.
191    pub fn new(merge_fn: merge::MergeFn<K, V>, cache: Option<Box<dyn ObjectCache<K, V>>>) -> Self {
192        let counters = TreeCounters::default();
193        counters.compaction.lock().unwrap().max_layer_count = 1;
194        LSMTree {
195            data: RwLock::new(Inner {
196                mutable_layer: Self::new_mutable_layer(),
197                layers: Vec::new(),
198                mutation_callback: None,
199            }),
200            merge_fn,
201            cache,
202            counters: Arc::new(counters),
203        }
204    }
205
206    /// Opens an existing tree from the provided handles to the layer objects.
207    pub async fn open(
208        merge_fn: merge::MergeFn<K, V>,
209        handles: impl IntoIterator<Item = impl LayerObject + 'static>,
210        cache: Option<Box<dyn ObjectCache<K, V>>>,
211    ) -> Result<Self, Error> {
212        let layers = layers_from_handles(handles).await?;
213        let max_layer_count = layers.len() as u64 + 1;
214        let counters = TreeCounters::default();
215        counters.compaction.lock().unwrap().max_layer_count = max_layer_count;
216        Ok(LSMTree {
217            data: RwLock::new(Inner {
218                mutable_layer: Self::new_mutable_layer(),
219                layers,
220                mutation_callback: None,
221            }),
222            merge_fn,
223            cache,
224            counters: Arc::new(counters),
225        })
226    }
227
228    /// Replaces the immutable layers.
229    pub fn set_layers(&self, layers: Vec<Arc<dyn Layer<K, V>>>) {
230        let mut data = self.data.write();
231        data.layers = layers;
232        let layer_count = data.layers.len() + 1;
233        let mut counters = self.counters.compaction.lock().unwrap();
234        counters.max_layer_count = std::cmp::max(counters.max_layer_count, layer_count as u64);
235    }
236
237    /// Opens layers for `object_ids` from `store` and appends them to the end of the tree (i.e. as
238    /// base layers). This is supposed to be used after replay when we are opening a tree and we
239    /// have discovered the base layers.
240    ///
241    /// Returns the sum of the sizes in bytes of all appended layers.
242    pub async fn append_layers(
243        &self,
244        store: &Arc<ObjectStore>,
245        object_ids: impl IntoIterator<Item = u64>,
246        crypt: Option<Arc<dyn Crypt>>,
247    ) -> Result<u64, Error> {
248        let (layers, total_size) = open_layers(store, object_ids, crypt).await?;
249        self.append_open_layers(layers);
250        Ok(total_size)
251    }
252
253    /// Appends already-opened layers to the end of the tree.
254    pub fn append_open_layers(&self, mut layers: Vec<Arc<dyn Layer<K, V>>>) {
255        let mut data = self.data.write();
256        data.layers.append(&mut layers);
257        let layer_count = data.layers.len() + 1;
258        let mut counters = self.counters.compaction.lock().unwrap();
259        counters.max_layer_count = std::cmp::max(counters.max_layer_count, layer_count as u64);
260    }
261
262    /// Resets the immutable layers.
263    pub fn reset_immutable_layers(&self) {
264        self.data.write().layers = Vec::new();
265    }
266
267    /// Seals the current mutable layer and creates a new one.
268    pub fn seal(&self) {
269        // We need to be sure there are no mutations currently in-progress.  This is currently
270        // guaranteed by ensuring that all mutations take a read lock on `data`.
271        let mut data = self.data.write();
272        let layer = std::mem::replace(&mut data.mutable_layer, Self::new_mutable_layer());
273        data.layers.insert(0, layer);
274        let layer_count = data.layers.len() + 1;
275        let mut counters = self.counters.compaction.lock().unwrap();
276        counters.max_layer_count = std::cmp::max(counters.max_layer_count, layer_count as u64);
277        counters.total_layers_added += 1;
278    }
279
280    /// Resets the tree to an empty state.
281    pub fn reset(&self) {
282        let mut data = self.data.write();
283        data.layers = Vec::new();
284        data.mutable_layer = Self::new_mutable_layer();
285    }
286
287    /// Clears all in-memory caches (object cache and persistent layer chunk caches) for this tree.
288    pub fn clear_cache(&self) {
289        if let Some(cache) = &self.cache {
290            cache.clear();
291        }
292        for layer in self.immutable_layer_set().layers {
293            layer.clear_cached_data();
294        }
295    }
296
297    pub fn cache_len(&self) -> usize {
298        self.cache.as_ref().map_or(0, |c| c.len())
299    }
300
301    pub fn report_compaction_metrics(
302        &self,
303        bytes_written: u64,
304        duration: std::time::Duration,
305        layer_count: usize,
306    ) {
307        let mut counters = self.counters.compaction.lock().unwrap();
308        counters.compactions += 1;
309        counters.compaction_bytes_written += bytes_written;
310        counters.compaction_time_ns += duration.as_nanos() as u64;
311
312        let bucket = if bytes_written == 0 {
313            0
314        } else {
315            std::cmp::min(LOG2_HISTOGRAM_BUCKETS - 1, 63 - bytes_written.leading_zeros() as usize)
316        };
317        counters.layer_size_histogram[bucket] += 1;
318
319        crate::metrics::lsm_tree_metrics().compaction_layer_stack_depth.insert(layer_count as u64);
320    }
321
322    pub fn compaction_bytes_written(&self) -> u64 {
323        self.counters.compaction.lock().unwrap().compaction_bytes_written
324    }
325
326    #[cfg(test)]
327    pub fn counters(&self) -> &TreeCounters {
328        &self.counters
329    }
330
331    /// Returns an empty layer-set for this tree.
332    pub fn empty_layer_set(&self) -> LayerSet<K, V> {
333        LayerSet { layers: Vec::new(), merge_fn: self.merge_fn, counters: self.counters.clone() }
334    }
335
336    /// Adds all the layers (including the mutable layer) to `layer_set`.
337    pub fn add_all_layers_to_layer_set(&self, layer_set: &mut LayerSet<K, V>) {
338        let data = self.data.read();
339        layer_set.layers.reserve_exact(data.layers.len() + 1);
340        layer_set
341            .layers
342            .push(LockedLayer::from(data.mutable_layer.clone() as Arc<dyn Layer<K, V>>));
343        for layer in &data.layers {
344            layer_set.layers.push(layer.clone().into());
345        }
346    }
347
348    /// Returns a clone of the current set of layers (including the mutable layer), after which one
349    /// can get an iterator.
350    pub fn layer_set(&self) -> LayerSet<K, V> {
351        let mut layer_set = self.empty_layer_set();
352        self.add_all_layers_to_layer_set(&mut layer_set);
353        layer_set
354    }
355
356    /// Returns the current set of immutable layers after which one can get an iterator (for e.g.
357    /// compacting).  Since these layers are immutable, getting an iterator should not block
358    /// anything else.
359    pub fn immutable_layer_set(&self) -> LayerSet<K, V> {
360        let data = self.data.read();
361        let mut layers = Vec::with_capacity(data.layers.len());
362        for layer in &data.layers {
363            layers.push(layer.clone().into());
364        }
365        LayerSet { layers, merge_fn: self.merge_fn, counters: self.counters.clone() }
366    }
367
368    /// Returns the number of immutable layers in the tree without cloning the layer set.
369    pub fn immutable_layer_count(&self) -> usize {
370        self.data.read().layers.len()
371    }
372
373    /// Inserts an item into the mutable layer.
374    /// Returns error if item already exists.
375    pub fn insert(&self, item: Item<K, V>) -> Result<(), Error> {
376        let _measure = DurationMeasureScope::new(&crate::metrics::lsm_tree_metrics().insert);
377
378        let item_dup = if self.is_cacheable(&item.key) { Some(item.clone()) } else { None };
379
380        {
381            // `seal` below relies on us holding a read lock whilst we do the mutation.
382            let data = self.data.read();
383            if let Some(mutation_callback) = data.mutation_callback.as_ref() {
384                mutation_callback(Operation::Insert, &item);
385            }
386            data.mutable_layer.insert(item)?;
387        }
388
389        if let Some(item) = item_dup {
390            let val = if item.value == V::DELETED_MARKER { None } else { Some(item.value) };
391            self.invalidate_cache(&item.key, val);
392        }
393        Ok(())
394    }
395
396    /// Replaces or inserts an item into the mutable layer.
397    pub fn replace_or_insert(&self, item: Item<K, V>) {
398        let _measure =
399            DurationMeasureScope::new(&crate::metrics::lsm_tree_metrics().replace_or_insert);
400
401        let item_dup = if self.is_cacheable(&item.key) { Some(item.clone()) } else { None };
402
403        {
404            // `seal` below relies on us holding a read lock whilst we do the mutation.
405            let data = self.data.read();
406            if let Some(mutation_callback) = data.mutation_callback.as_ref() {
407                mutation_callback(Operation::ReplaceOrInsert, &item);
408            }
409            data.mutable_layer.replace_or_insert(item);
410        }
411
412        if let Some(item) = item_dup {
413            let val = if item.value == V::DELETED_MARKER { None } else { Some(item.value) };
414            self.invalidate_cache(&item.key, val);
415        }
416    }
417
418    /// Merges the given item into the mutable layer.
419    pub fn merge_into(&self, item: Item<K, V>, lower_bound: &K) {
420        let _measure = DurationMeasureScope::new(&crate::metrics::lsm_tree_metrics().merge_into);
421
422        let key = if self.is_cacheable(&item.key) { Some(item.key.clone()) } else { None };
423        {
424            // `seal` below relies on us holding a read lock whilst we do the mutation.
425            let data = self.data.read();
426            if let Some(mutation_callback) = data.mutation_callback.as_ref() {
427                mutation_callback(Operation::MergeInto, &item);
428            }
429            data.mutable_layer.merge_into(item, lower_bound, self.merge_fn);
430        }
431
432        if let Some(key) = key {
433            self.invalidate_cache(&key, None);
434        }
435    }
436
437    /// Returns true if `key` is cacheable by the underlying cache.
438    ///
439    /// Returns false if no cache is configured or if the key is not cacheable.
440    /// This allows tree mutation operations (`insert`, `replace_or_insert`, `merge_into`) to skip
441    /// cloning keys and values when cache invalidation would be a no-op.
442    #[inline(always)]
443    fn is_cacheable(&self, key: &K) -> bool {
444        if let Some(cache) = &self.cache { cache.is_cacheable(key) } else { false }
445    }
446
447    /// Invalidates the cache entry for `key` if a cache is configured.
448    ///
449    /// If `value` is Some, the cache entry may be updated with the new value. If `value` is None,
450    /// the entry is removed from the cache. Does nothing if no cache is configured.
451    #[inline(always)]
452    fn invalidate_cache(&self, key: &K, value: Option<V>) {
453        if let Some(cache) = &self.cache {
454            cache.invalidate(key, value);
455        }
456    }
457
458    /// Searches for an exact match for the given key, applying `f` to the found [`ItemRef`].
459    /// If the item does not exist or has a value equal to [`Value::DELETED_MARKER`], returns
460    /// `Ok(None)`.
461    ///
462    /// Range keys (`FuzzyHash::is_range_key`) are not supported.
463    pub async fn find_map<R, F>(&self, search_key: &K, f: F) -> Result<Option<R>, Error>
464    where
465        K: Eq,
466        F: FnOnce(ItemRef<'_, K, V>) -> R,
467    {
468        let _measure = DurationMeasureScope::new(&crate::metrics::lsm_tree_metrics().find);
469        // It is important that the cache lookup is done prior to fetching the layer set as the
470        // placeholder returned acts as a sort of lock for the validity of the item that may be
471        // inserted later via that placeholder.
472        let mut token = if let Some(cache) = &self.cache {
473            match cache.lookup_or_reserve(search_key) {
474                ObjectCacheResult::Value(value) => {
475                    if *value == V::DELETED_MARKER {
476                        return Ok(None);
477                    } else {
478                        return Ok(Some(f(ItemRef { key: search_key, value: &value })));
479                    }
480                }
481                ObjectCacheResult::Placeholder(token) => Some(token),
482                ObjectCacheResult::NoCache => None,
483            }
484        } else {
485            None
486        };
487        let layer_set = self.layer_set();
488        let result = layer_set
489            .find_map(search_key, |item_ref| {
490                if let Some(token) = token.take() {
491                    token.complete(Some(item_ref.value));
492                }
493                f(item_ref)
494            })
495            .await?;
496        Ok(result)
497    }
498
499    /// Searches for an exact match for the given key. If the item does not exist or has a value
500    /// equal to [`Value::DELETED_MARKER`], returns `Ok(None)`.
501    ///
502    /// Range keys (`FuzzyHash::is_range_key`) are not supported.
503    pub fn find(
504        &self,
505        search_key: &K,
506    ) -> impl Future<Output = Result<Option<Item<K, V>>, Error>> + Send
507    where
508        K: Eq,
509    {
510        self.find_map(search_key, |item| Item { key: item.key.clone(), value: item.value.clone() })
511    }
512
513    /// Searches for an exact match for the given key, returning only the value. If the item does
514    /// not exist or has a value equal to [`Value::DELETED_MARKER`], returns `Ok(None)`.
515    ///
516    /// Range keys (`FuzzyHash::is_range_key`) are not supported.
517    pub fn find_value(
518        &self,
519        search_key: &K,
520    ) -> impl Future<Output = Result<Option<V>, Error>> + Send
521    where
522        K: Eq,
523    {
524        self.find_map(search_key, |item| item.value.clone())
525    }
526
527    /// Returns true if an exact match exists for the given key and is not deleted.
528    ///
529    /// Range keys (`FuzzyHash::is_range_key`) are not supported.
530    pub async fn exists(&self, search_key: &K) -> Result<bool, Error>
531    where
532        K: Eq,
533    {
534        Ok(self.find_map(search_key, |_| ()).await?.is_some())
535    }
536
537    pub fn mutable_layer(&self) -> Arc<SkipListLayer<K, V>> {
538        self.data.read().mutable_layer.clone()
539    }
540
541    /// Sets a mutation callback which is a callback that is triggered whenever any mutations are
542    /// applied to the tree.  This might be useful for tests that want to record the precise
543    /// sequence of mutations that are applied to the tree.
544    pub fn set_mutation_callback(&self, mutation_callback: MutationCallback<K, V>) {
545        self.data.write().mutation_callback = mutation_callback;
546    }
547
548    /// Returns the earliest version used by a layer in the tree.
549    pub fn get_earliest_version(&self) -> Version {
550        let mut earliest_version = LATEST_VERSION;
551        for layer in self.layer_set().layers {
552            let layer_version = layer.get_version();
553            if layer_version < earliest_version {
554                earliest_version = layer_version;
555            }
556        }
557        return earliest_version;
558    }
559
560    /// Returns a new mutable layer.
561    pub fn new_mutable_layer() -> Arc<SkipListLayer<K, V>> {
562        SkipListLayer::new(SKIP_LIST_LAYER_ITEMS)
563    }
564
565    /// Replaces the mutable layer.
566    pub fn set_mutable_layer(&self, layer: Arc<SkipListLayer<K, V>>) {
567        self.data.write().mutable_layer = layer;
568    }
569
570    /// Records inspect data for the LSM tree into `node`.  Called lazily when inspect is queried.
571    pub fn record_inspect_data(&self, root: &fuchsia_inspect::Node) {
572        let layer_set = self.layer_set();
573        root.record_child("layers", move |node| {
574            let mut index = 0;
575            for layer in layer_set.layers {
576                node.record_child(format!("{index}"), move |node| {
577                    layer.1.record_inspect_data(node)
578                });
579                index += 1;
580            }
581        });
582        {
583            let counters = self.counters.compaction.lock().unwrap();
584            root.record_uint("num_seeks", self.counters.num_seeks.load(Ordering::Relaxed) as u64);
585            root.record_double("bloom_filter_success_percent", {
586                let layer_files_total = self.counters.layer_files_total.load(Ordering::Relaxed);
587                let layer_files_skipped = self.counters.layer_files_skipped.load(Ordering::Relaxed);
588                if layer_files_total == 0 {
589                    0.0
590                } else {
591                    (layer_files_skipped as f64 * 100.0) / (layer_files_total as f64)
592                }
593            });
594            // False positive rate for point queries: FP / (FP + TN). This matches the definition
595            // of false positive rate used for calculating params based on the target false
596            // positive rate. See usage of `crate::lsm_tree::bloom_filter::TARGET_FP_RATE.`
597            // Range-based queries are not able to properly measure false positives since it is
598            // possible for them to find a key different than the one that hit in the Bloom filter,
599            // which would skew the false positive rate.
600            root.record_double("bloom_filter_false_positive_percent", {
601                let false_positives =
602                    self.counters.bloom_filter_false_positives.load(Ordering::Relaxed);
603                let negatives = self.counters.bloom_filter_negatives.load(Ordering::Relaxed);
604                let total_negatives = false_positives + negatives;
605                if total_negatives == 0 {
606                    0.0
607                } else {
608                    (false_positives as f64 * 100.0) / (total_negatives as f64)
609                }
610            });
611            root.record_uint(
612                "excessive_hash_partitions",
613                self.counters.excessive_hash_partitions.load(Ordering::Relaxed) as u64,
614            );
615            root.record_uint("compactions", counters.compactions);
616            root.record_uint("compaction_bytes_written", counters.compaction_bytes_written);
617            root.record_uint("compaction_time_ns", counters.compaction_time_ns);
618            root.record_uint("total_layers_added", counters.total_layers_added);
619            root.record_uint("max_layer_count", counters.max_layer_count);
620
621            let layer_sizes = root.create_uint_exponential_histogram(
622                "layer_size_histogram_log2",
623                fuchsia_inspect::ExponentialHistogramParams {
624                    floor: 1,
625                    initial_step: 1,
626                    step_multiplier: 2,
627                    buckets: LOG2_HISTOGRAM_BUCKETS,
628                },
629            );
630            for (i, count) in counters.layer_size_histogram.iter().enumerate() {
631                layer_sizes.insert_multiple(1u64 << i, *count as usize);
632            }
633            root.record(layer_sizes);
634        }
635    }
636}
637
638/// This is an RAII wrapper for a layer which holds a lock on the layer (via the Layer::lock
639/// method).
640pub struct LockedLayer<K, V>(Arc<DropEvent>, Arc<dyn Layer<K, V>>);
641
642impl<K, V> LockedLayer<K, V> {
643    pub async fn close_layer(self) {
644        let layer = self.1;
645        std::mem::drop(self.0);
646        layer.close().await;
647    }
648}
649
650impl<K, V> From<Arc<dyn Layer<K, V>>> for LockedLayer<K, V> {
651    fn from(layer: Arc<dyn Layer<K, V>>) -> Self {
652        let event = layer.lock().unwrap();
653        Self(event, layer)
654    }
655}
656
657impl<K, V> std::ops::Deref for LockedLayer<K, V> {
658    type Target = Arc<dyn Layer<K, V>>;
659
660    fn deref(&self) -> &Self::Target {
661        &self.1
662    }
663}
664
665impl<K, V> AsRef<dyn Layer<K, V>> for LockedLayer<K, V> {
666    fn as_ref(&self) -> &(dyn Layer<K, V> + 'static) {
667        self.1.as_ref()
668    }
669}
670
671/// A LayerSet provides a snapshot of the layers at a particular point in time, and allows you to
672/// get an iterator.  Iterators borrow the layers so something needs to hold reference count.
673pub struct LayerSet<K, V> {
674    pub layers: Vec<LockedLayer<K, V>>,
675    merge_fn: merge::MergeFn<K, V>,
676    counters: Arc<TreeCounters>,
677}
678
679impl<K: Key + LayerKey + OrdLowerBound, V: Value> LayerSet<K, V> {
680    pub fn sum_len(&self) -> usize {
681        let mut size = 0;
682        for layer in &self.layers {
683            size += layer.len()
684        }
685        size
686    }
687
688    pub fn merger(&self) -> merge::Merger<'_, K, V> {
689        merge::Merger::new(
690            self.layers.iter().map(|x| x.as_ref()),
691            self.merge_fn,
692            self.counters.clone(),
693        )
694    }
695
696    /// Searches for an exact match for the given key, applying `f` to the found [`ItemRef`].
697    /// If the item does not exist or has a value equal to [`Value::DELETED_MARKER`], returns
698    /// `Ok(None)`.
699    ///
700    /// Range keys (`FuzzyHash::is_range_key`) are not supported.
701    pub async fn find_map<R, F>(&self, search_key: &K, f: F) -> Result<Option<R>, Error>
702    where
703        K: Eq,
704        F: FnOnce(ItemRef<'_, K, V>) -> R,
705    {
706        if search_key.merge_type() == MergeType::OptimizedMerge {
707            self.counters.num_seeks.fetch_add(1, Ordering::Relaxed);
708            for layer in &self.layers {
709                self.counters.layer_files_total.fetch_add(1, Ordering::Relaxed);
710                if layer.maybe_contains_key(search_key) == MaybeContainsKey::False {
711                    self.counters.layer_files_skipped.fetch_add(1, Ordering::Relaxed);
712                    self.counters.bloom_filter_negatives.fetch_add(1, Ordering::Relaxed);
713                    continue;
714                }
715                let iter = layer.seek(Bound::Included(search_key)).await?;
716                let found = iter.get().filter(|item_ref| item_ref.key == search_key);
717                if layer.has_bloom_filter() && found.is_none() {
718                    self.counters.bloom_filter_false_positives.fetch_add(1, Ordering::Relaxed);
719                }
720                if let Some(item_ref) = found {
721                    if *item_ref.value == V::DELETED_MARKER {
722                        return Ok(None);
723                    } else {
724                        return Ok(Some(f(item_ref)));
725                    }
726                }
727            }
728            return Ok(None);
729        }
730
731        let mut merger = self.merger();
732        Ok(match merger.query(Query::Point(search_key)).await?.get() {
733            Some(item_ref)
734                if item_ref.key == search_key && *item_ref.value != V::DELETED_MARKER =>
735            {
736                Some(f(item_ref))
737            }
738            _ => None,
739        })
740    }
741
742    /// See `Layer::key_exists`.
743    pub async fn key_exists(&self, key: &K) -> Result<Existence, Error> {
744        for l in &self.layers {
745            match l.key_exists(key).await? {
746                e @ (Existence::Exists | Existence::MaybeExists) => return Ok(e),
747                _ => {}
748            }
749        }
750        Ok(Existence::Missing)
751    }
752}
753
754impl<K, V> fmt::Debug for LayerSet<K, V> {
755    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
756        fmt.debug_list()
757            .entries(self.layers.iter().map(|l| {
758                if let Some(handle) = l.handle() {
759                    format!("{}", handle.object_id())
760                } else {
761                    format!("{:?}", Arc::as_ptr(l))
762                }
763            }))
764            .finish()
765    }
766}
767
768/// A yielder can be used during compactions which are low priority.
769pub trait Yielder: Send {
770    fn yield_now(&mut self) -> impl Future<Output = ()> + Send;
771}
772
773#[cfg(test)]
774mod tests {
775    use super::{LSMTree, Yielder, compact_with_iterator};
776    use crate::drop_event::DropEvent;
777    use crate::lsm_tree::cache::{ObjectCache, ObjectCachePlaceholder, ObjectCacheResult};
778    use crate::lsm_tree::merge::{ItemOp, MergeLayerIterator, MergeResult};
779    use crate::lsm_tree::types::{
780        BoxedLayerIterator, Existence, Item, ItemRef, Key, Layer, LayerIterator, MaybeContainsKey,
781        Value,
782    };
783    use crate::lsm_tree::{Query, layers_from_handles};
784    use crate::object_handle::ObjectHandle;
785    use crate::serialized_types::{LATEST_VERSION, Version};
786    use crate::testing::fake_object::{FakeObject, FakeObjectHandle};
787    use crate::testing::writer::Writer;
788    use anyhow::{Error, anyhow};
789    use async_trait::async_trait;
790
791    use fuchsia_inspect::hierarchy::{DiagnosticsHierarchy, Property};
792    use fuchsia_inspect::{Inspector, reader};
793    use fuchsia_sync::{Mutex, MutexGuard};
794    use futures::future::BoxFuture;
795    use rand::rng;
796    use rand::seq::SliceRandom as _;
797    use std::sync::Arc;
798    use std::sync::atomic::Ordering;
799    use test_util::assert_near;
800
801    use super::testing::TestKey;
802
803    fn emit_left_merge_fn(
804        _left: &MergeLayerIterator<'_, TestKey, u64>,
805        _right: &MergeLayerIterator<'_, TestKey, u64>,
806    ) -> MergeResult<TestKey, u64> {
807        MergeResult::EmitLeft
808    }
809
810    fn emit_left_i32_merge_fn(
811        _left: &MergeLayerIterator<'_, i32, u64>,
812        _right: &MergeLayerIterator<'_, i32, u64>,
813    ) -> MergeResult<i32, u64> {
814        MergeResult::EmitLeft
815    }
816
817    fn merge_sum_i32(
818        left: &MergeLayerIterator<'_, i32, u64>,
819        right: &MergeLayerIterator<'_, i32, u64>,
820    ) -> MergeResult<i32, u64> {
821        if left.key() == right.key() {
822            MergeResult::Other {
823                emit: None,
824                left: ItemOp::Discard,
825                right: ItemOp::Replace(
826                    Item::new(*left.key(), *left.value() + *right.value()).boxed(),
827                ),
828            }
829        } else {
830            MergeResult::EmitLeft
831        }
832    }
833
834    impl Value for u64 {
835        const DELETED_MARKER: Self = 0;
836    }
837
838    struct NoOpYielder;
839    impl Yielder for NoOpYielder {
840        async fn yield_now(&mut self) {}
841    }
842
843    #[fuchsia::test]
844    async fn test_iteration() {
845        let tree = LSMTree::new(emit_left_merge_fn, None);
846        let items = [Item::new(TestKey(1..1), 1), Item::new(TestKey(2..2), 2)];
847        tree.insert(items[0].clone()).expect("insert error");
848        tree.insert(items[1].clone()).expect("insert error");
849        let layers = tree.layer_set();
850        let mut merger = layers.merger();
851        let mut iter = merger.query(Query::FullScan).await.expect("seek failed");
852        let ItemRef { key, value, .. } = iter.get().expect("missing item");
853        assert_eq!((key, value), (&items[0].key, &items[0].value));
854        iter.advance().await.expect("advance failed");
855        let ItemRef { key, value, .. } = iter.get().expect("missing item");
856        assert_eq!((key, value), (&items[1].key, &items[1].value));
857        iter.advance().await.expect("advance failed");
858        assert!(iter.get().is_none());
859    }
860
861    #[fuchsia::test]
862    async fn test_compact() {
863        let tree = LSMTree::new(emit_left_merge_fn, None);
864        let items = [
865            Item::new(TestKey(1..1), 1),
866            Item::new(TestKey(2..2), 2),
867            Item::new(TestKey(3..3), 3),
868            Item::new(TestKey(4..4), 4),
869        ];
870        tree.insert(items[0].clone()).expect("insert error");
871        tree.insert(items[1].clone()).expect("insert error");
872        tree.seal();
873        tree.insert(items[2].clone()).expect("insert error");
874        tree.insert(items[3].clone()).expect("insert error");
875        tree.seal();
876        let object = Arc::new(FakeObject::new());
877        let handle = FakeObjectHandle::new(object.clone());
878        {
879            let layer_set = tree.immutable_layer_set();
880            let mut merger = layer_set.merger();
881            let iter = merger.query(Query::FullScan).await.expect("create merger");
882            compact_with_iterator(
883                iter,
884                items.len(),
885                Writer::new(&handle).await,
886                handle.block_size(),
887                Option::<NoOpYielder>::None,
888            )
889            .await
890            .expect("compact failed");
891        }
892        tree.set_layers(layers_from_handles([handle]).await.expect("layers_from_handles failed"));
893        let handle = FakeObjectHandle::new(object.clone());
894        let tree = LSMTree::open(emit_left_merge_fn, [handle], None).await.expect("open failed");
895
896        let layers = tree.layer_set();
897        let mut merger = layers.merger();
898        let mut iter = merger.query(Query::FullScan).await.expect("seek failed");
899        for i in 1..5 {
900            let ItemRef { key, value, .. } = iter.get().expect("missing item");
901            assert_eq!((key, value), (&TestKey(i..i), &i));
902            iter.advance().await.expect("advance failed");
903        }
904        assert!(iter.get().is_none());
905    }
906
907    #[fuchsia::test]
908    async fn test_find() {
909        let items = [
910            Item::new(TestKey(1..1), 1),
911            Item::new(TestKey(2..2), 2),
912            Item::new(TestKey(3..3), 3),
913            Item::new(TestKey(4..4), 4),
914        ];
915        let tree = LSMTree::new(emit_left_merge_fn, None);
916        tree.insert(items[0].clone()).expect("insert error");
917        tree.insert(items[1].clone()).expect("insert error");
918        tree.seal();
919        tree.insert(items[2].clone()).expect("insert error");
920        tree.insert(items[3].clone()).expect("insert error");
921
922        let item = tree.find(&items[1].key).await.expect("find failed").expect("not found");
923        assert_eq!(item, items[1]);
924        assert!(tree.find(&TestKey(100..100)).await.expect("find failed").is_none());
925
926        assert_eq!(tree.find_value(&items[2].key).await.expect("find_value failed"), Some(3));
927        assert_eq!(tree.find_value(&TestKey(100..100)).await.expect("find_value failed"), None);
928
929        assert!(tree.exists(&items[0].key).await.expect("exists failed"));
930        assert!(!tree.exists(&TestKey(100..100)).await.expect("exists failed"));
931
932        assert_eq!(
933            tree.find_map(&items[3].key, |item| item.value * 10).await.expect("find_map failed"),
934            Some(40)
935        );
936        assert_eq!(
937            tree.find_map(&TestKey(100..100), |item| item.value * 10)
938                .await
939                .expect("find_map failed"),
940            None
941        );
942    }
943
944    #[fuchsia::test]
945    async fn test_find_no_return_deleted_values() {
946        let items = [Item::new(TestKey(1..1), 1), Item::new(TestKey(2..2), u64::DELETED_MARKER)];
947        let tree = LSMTree::new(emit_left_merge_fn, None);
948        tree.insert(items[0].clone()).expect("insert error");
949        tree.insert(items[1].clone()).expect("insert error");
950
951        let item = tree.find(&items[0].key).await.expect("find failed").expect("not found");
952        assert_eq!(item, items[0]);
953        assert_eq!(tree.find_value(&items[0].key).await.expect("find_value failed"), Some(1));
954        assert_eq!(
955            tree.find_map(&items[0].key, |item| *item.value).await.expect("find_map failed"),
956            Some(1)
957        );
958        assert!(tree.exists(&items[0].key).await.expect("exists failed"));
959
960        assert!(tree.find(&items[1].key).await.expect("find failed").is_none());
961        assert!(tree.find_value(&items[1].key).await.expect("find_value failed").is_none());
962        assert!(tree.find_map(&items[1].key, |_| ()).await.expect("find_map failed").is_none());
963        assert!(!tree.exists(&items[1].key).await.expect("exists failed"));
964    }
965
966    #[fuchsia::test]
967    async fn test_find_full_merge() {
968        let tree = LSMTree::new(emit_left_i32_merge_fn, None);
969        let items = [
970            Item::new(1, 10),
971            Item::new(2, 20),
972            Item::new(3, 30),
973            Item::new(4, u64::DELETED_MARKER),
974        ];
975        for item in &items {
976            tree.insert(item.clone()).expect("insert error");
977        }
978
979        assert_eq!(tree.find(&1).await.expect("find failed"), Some(items[0].clone()));
980        assert_eq!(tree.find_value(&2).await.expect("find_value failed"), Some(20));
981        assert!(tree.exists(&3).await.expect("exists failed"));
982        assert_eq!(
983            tree.find_map(&3, |item| *item.value * 2).await.expect("find_map failed"),
984            Some(60)
985        );
986
987        // Missing key
988        assert_eq!(tree.find(&99).await.expect("find failed"), None);
989        assert_eq!(tree.find_value(&99).await.expect("find_value failed"), None);
990        assert!(!tree.exists(&99).await.expect("exists failed"));
991        assert_eq!(tree.find_map(&99, |_| ()).await.expect("find_map failed"), None);
992
993        // Deleted key
994        assert_eq!(tree.find(&4).await.expect("find failed"), None);
995        assert_eq!(tree.find_value(&4).await.expect("find_value failed"), None);
996        assert!(!tree.exists(&4).await.expect("exists failed"));
997        assert_eq!(tree.find_map(&4, |_| ()).await.expect("find_map failed"), None);
998    }
999
1000    #[fuchsia::test]
1001    async fn test_find_full_merge_multi_layer() {
1002        let tree = LSMTree::new(merge_sum_i32, None);
1003
1004        // Base layer:
1005        tree.insert(Item::new(1, 100)).expect("insert error");
1006        tree.insert(Item::new(2, 200)).expect("insert error");
1007        tree.insert(Item::new(3, 300)).expect("insert error");
1008
1009        tree.seal();
1010
1011        // Top layer:
1012        // Key 1 has an update (+50) that should merge to 150.
1013        // Key 4 is new (40).
1014        tree.insert(Item::new(1, 50)).expect("insert error");
1015        tree.insert(Item::new(4, 40)).expect("insert error");
1016
1017        // Key 1 should be merged across layers: 50 + 100 = 150.
1018        assert_eq!(tree.find_value(&1).await.expect("find_value failed"), Some(150));
1019        assert_eq!(tree.find(&1).await.expect("find failed"), Some(Item::new(1, 150)));
1020        assert!(tree.exists(&1).await.expect("exists failed"));
1021        assert_eq!(
1022            tree.find_map(&1, |item| *item.value * 2).await.expect("find_map failed"),
1023            Some(300)
1024        );
1025
1026        // Key 2 only exists in the base layer: 200.
1027        assert_eq!(tree.find_value(&2).await.expect("find_value failed"), Some(200));
1028        assert!(tree.exists(&2).await.expect("exists failed"));
1029
1030        // Key 3 only exists in the base layer: 300.
1031        assert_eq!(tree.find_value(&3).await.expect("find_value failed"), Some(300));
1032        assert!(tree.exists(&3).await.expect("exists failed"));
1033
1034        // Key 4 only exists in the top layer: 40.
1035        assert_eq!(tree.find_value(&4).await.expect("find_value failed"), Some(40));
1036        assert!(tree.exists(&4).await.expect("exists failed"));
1037
1038        // Key 5 is missing entirely.
1039        assert_eq!(tree.find_value(&5).await.expect("find_value failed"), None);
1040        assert!(!tree.exists(&5).await.expect("exists failed"));
1041    }
1042
1043    #[fuchsia::test]
1044    async fn test_find_optimized_merge_multi_layer() {
1045        let tree = LSMTree::new(emit_left_merge_fn, None);
1046
1047        // Insert items in base layer (older).
1048        tree.insert(Item::new(TestKey(1..1), 10)).expect("insert error");
1049        tree.insert(Item::new(TestKey(2..2), 20)).expect("insert error");
1050        tree.insert(Item::new(TestKey(3..3), 30)).expect("insert error");
1051
1052        tree.seal();
1053
1054        // In the newer layer:
1055        // - Update key 2 to 25
1056        // - Tombstone key 3
1057        // - Insert new key 4
1058        tree.insert(Item::new(TestKey(2..2), 25)).expect("insert error");
1059        tree.insert(Item::new(TestKey(3..3), u64::DELETED_MARKER)).expect("insert error");
1060        tree.insert(Item::new(TestKey(4..4), 40)).expect("insert error");
1061
1062        // Key 1: only in older layer.
1063        assert_eq!(tree.find_value(&TestKey(1..1)).await.expect("find_value failed"), Some(10));
1064        assert!(tree.exists(&TestKey(1..1)).await.expect("exists failed"));
1065
1066        // Key 2: updated in newer layer (shadows older layer).
1067        assert_eq!(tree.find_value(&TestKey(2..2)).await.expect("find_value failed"), Some(25));
1068        assert!(tree.exists(&TestKey(2..2)).await.expect("exists failed"));
1069
1070        // Key 3: deleted in newer layer (shadows older layer).
1071        assert_eq!(tree.find(&TestKey(3..3)).await.expect("find failed"), None);
1072        assert_eq!(tree.find_value(&TestKey(3..3)).await.expect("find_value failed"), None);
1073        assert!(!tree.exists(&TestKey(3..3)).await.expect("exists failed"));
1074        assert_eq!(tree.find_map(&TestKey(3..3), |_| ()).await.expect("find_map failed"), None);
1075
1076        // Key 4: only in newer layer.
1077        assert_eq!(tree.find_value(&TestKey(4..4)).await.expect("find_value failed"), Some(40));
1078        assert!(tree.exists(&TestKey(4..4)).await.expect("exists failed"));
1079
1080        // Key 5: missing in all layers.
1081        assert_eq!(tree.find_value(&TestKey(5..5)).await.expect("find_value failed"), None);
1082        assert!(!tree.exists(&TestKey(5..5)).await.expect("exists failed"));
1083    }
1084
1085    #[fuchsia::test]
1086    async fn test_find_bloom_filter_rejection() {
1087        struct BloomFilterMockLayer {
1088            drop_event: Mutex<Option<Arc<DropEvent>>>,
1089        }
1090
1091        impl BloomFilterMockLayer {
1092            fn new() -> Self {
1093                Self { drop_event: Mutex::new(Some(Arc::new(DropEvent::new()))) }
1094            }
1095        }
1096
1097        #[async_trait]
1098        impl<K: Key, V: Value> Layer<K, V> for BloomFilterMockLayer {
1099            async fn seek(
1100                &self,
1101                _bound: std::ops::Bound<&K>,
1102            ) -> Result<BoxedLayerIterator<'_, K, V>, Error> {
1103                panic!("seek should not be called on layer skipped by bloom filter");
1104            }
1105
1106            fn lock(&self) -> Option<Arc<DropEvent>> {
1107                self.drop_event.lock().clone()
1108            }
1109
1110            fn len(&self) -> usize {
1111                0
1112            }
1113
1114            async fn close(&self) {}
1115
1116            fn get_version(&self) -> Version {
1117                LATEST_VERSION
1118            }
1119
1120            fn maybe_contains_key(&self, _key: &K) -> MaybeContainsKey {
1121                MaybeContainsKey::False
1122            }
1123
1124            async fn key_exists(&self, _key: &K) -> Result<Existence, Error> {
1125                unimplemented!()
1126            }
1127        }
1128
1129        let tree = LSMTree::new(emit_left_merge_fn, None);
1130        let layer: Arc<dyn Layer<TestKey, u64>> = Arc::new(BloomFilterMockLayer::new());
1131        tree.set_layers(vec![layer]);
1132
1133        let skipped_before = tree.counters.layer_files_skipped.load(Ordering::Relaxed);
1134        let total_before = tree.counters.layer_files_total.load(Ordering::Relaxed);
1135
1136        // Searching for any key: the bloom filter on the immutable layer reports False,
1137        // so seek() is never called (which would panic) and the layer is skipped.
1138        assert_eq!(tree.find_value(&TestKey(1..1)).await.expect("find failed"), None);
1139        assert!(!tree.exists(&TestKey(1..1)).await.expect("exists failed"));
1140
1141        let skipped_after = tree.counters.layer_files_skipped.load(Ordering::Relaxed);
1142        let total_after = tree.counters.layer_files_total.load(Ordering::Relaxed);
1143
1144        // 2 queries (find_value and exists); each inspects mutable layer + 1 immutable mock layer.
1145        // The mock layer is skipped by the bloom filter on both queries.
1146        assert_eq!(skipped_after - skipped_before, 2);
1147        assert_eq!(total_after - total_before, 4);
1148    }
1149
1150    #[fuchsia::test]
1151    async fn test_bloom_filter_false_positive_metrics() {
1152        struct MockBloomLayerIterator {
1153            item: Option<Item<TestKey, u64>>,
1154        }
1155
1156        impl LayerIterator<TestKey, u64> for MockBloomLayerIterator {
1157            async fn advance(&mut self) -> Result<(), Error> {
1158                self.item = None;
1159                Ok(())
1160            }
1161
1162            fn advance_dyn<'a>(
1163                &'a mut self,
1164            ) -> Result<Option<BoxFuture<'a, Result<(), Error>>>, Error> {
1165                self.item = None;
1166                Ok(None)
1167            }
1168
1169            fn get(&self) -> Option<ItemRef<'_, TestKey, u64>> {
1170                self.item.as_ref().map(|item| item.as_item_ref())
1171            }
1172        }
1173
1174        struct MockBloomLayer {
1175            drop_event: Mutex<Option<Arc<DropEvent>>>,
1176            items: Vec<Item<TestKey, u64>>,
1177            key_rejected_prefix: u64,
1178        }
1179
1180        impl MockBloomLayer {
1181            fn new(items: Vec<Item<TestKey, u64>>, key_rejected_prefix: u64) -> Self {
1182                Self {
1183                    drop_event: Mutex::new(Some(Arc::new(DropEvent::new()))),
1184                    items,
1185                    key_rejected_prefix,
1186                }
1187            }
1188        }
1189
1190        #[async_trait]
1191        impl Layer<TestKey, u64> for MockBloomLayer {
1192            async fn seek(
1193                &self,
1194                bound: std::ops::Bound<&TestKey>,
1195            ) -> Result<BoxedLayerIterator<'_, TestKey, u64>, Error> {
1196                let item = match bound {
1197                    std::ops::Bound::Included(k) => {
1198                        self.items.iter().find(|i| i.key.0.start >= k.0.start).cloned()
1199                    }
1200                    _ => None,
1201                };
1202                Ok(Box::new(MockBloomLayerIterator { item }))
1203            }
1204
1205            fn lock(&self) -> Option<Arc<DropEvent>> {
1206                self.drop_event.lock().clone()
1207            }
1208
1209            fn len(&self) -> usize {
1210                self.items.len()
1211            }
1212
1213            async fn close(&self) {}
1214
1215            fn get_version(&self) -> Version {
1216                LATEST_VERSION
1217            }
1218
1219            fn has_bloom_filter(&self) -> bool {
1220                true
1221            }
1222
1223            fn maybe_contains_key(&self, key: &TestKey) -> MaybeContainsKey {
1224                if key.0.start >= self.key_rejected_prefix {
1225                    MaybeContainsKey::False
1226                } else {
1227                    MaybeContainsKey::Maybe
1228                }
1229            }
1230
1231            async fn key_exists(&self, _key: &TestKey) -> Result<Existence, Error> {
1232                unimplemented!()
1233            }
1234        }
1235
1236        let items = vec![
1237            Item::new(TestKey(10..10), 42),
1238            Item::new(TestKey(20..20), u64::DELETED_MARKER),
1239            Item::new(TestKey(30..30), 100),
1240        ];
1241        // Keys with start >= 90 are rejected by the bloom filter (True Negatives).
1242        let layer = Arc::new(MockBloomLayer::new(items, 90));
1243        let tree = LSMTree::new(emit_left_merge_fn, None);
1244        tree.set_layers(vec![layer.clone()]);
1245
1246        let get_fpr = |hierarchy: &DiagnosticsHierarchy| match hierarchy
1247            .get_property("bloom_filter_false_positive_percent")
1248        {
1249            Some(Property::Double(_, val)) => *val,
1250            other => panic!("Unexpected property: {other:?}"),
1251        };
1252        let get_success_percent = |hierarchy: &DiagnosticsHierarchy| match hierarchy
1253            .get_property("bloom_filter_success_percent")
1254        {
1255            Some(Property::Double(_, val)) => *val,
1256            other => panic!("Unexpected property: {other:?}"),
1257        };
1258
1259        // 1. Initial inspect: 0 total negatives (FP=0, TN=0), FPR should be 0.0
1260        let inspector = Inspector::default();
1261        tree.record_inspect_data(inspector.root());
1262        let hierarchy = reader::read(&inspector).await.unwrap();
1263        assert_near!(get_fpr(&hierarchy), 0.0, 1e-6);
1264        assert_near!(get_success_percent(&hierarchy), 0.0, 1e-6);
1265
1266        // 2. Query key 10..10: present item -> true positive (not counted as FP or Neg).
1267        assert_eq!(tree.find_value(&TestKey(10..10)).await.expect("find failed"), Some(42));
1268        assert_eq!(tree.counters.bloom_filter_false_positives.load(Ordering::Relaxed), 0);
1269        assert_eq!(tree.counters.bloom_filter_negatives.load(Ordering::Relaxed), 0);
1270
1271        // 3. Query key 20..20: deleted tombstone item -> found is true, not an FP or Neg.
1272        assert_eq!(tree.find_value(&TestKey(20..20)).await.expect("find failed"), None);
1273        assert_eq!(tree.counters.bloom_filter_false_positives.load(Ordering::Relaxed), 0);
1274        assert_eq!(tree.counters.bloom_filter_negatives.load(Ordering::Relaxed), 0);
1275
1276        // 4. Query key 25..25: miss that lands on next key (30..30) -> false positive.
1277        // FP = 1, TN = 0 => classical FPR = 1 / (1 + 0) = 100.0%.
1278        assert_eq!(tree.find_value(&TestKey(25..25)).await.expect("find failed"), None);
1279        assert_eq!(tree.counters.bloom_filter_false_positives.load(Ordering::Relaxed), 1);
1280        assert_eq!(tree.counters.bloom_filter_negatives.load(Ordering::Relaxed), 0);
1281
1282        let inspector = Inspector::default();
1283        tree.record_inspect_data(inspector.root());
1284        let hierarchy = reader::read(&inspector).await.unwrap();
1285        assert_near!(get_fpr(&hierarchy), 100.0, 1e-6);
1286        assert_near!(get_success_percent(&hierarchy), 0.0, 1e-6);
1287
1288        // 5. Query key 90..90: bloom filter says False (rejected, true negative).
1289        // FP = 1, TN = 1 => classical FPR = 1 / (1 + 1) = 50.0%.
1290        // 1 layer skipped out of 8 total layer evaluations (2 layers across 4 queries) => 12.5%.
1291        assert_eq!(tree.find_value(&TestKey(90..90)).await.expect("find failed"), None);
1292        assert_eq!(tree.counters.bloom_filter_false_positives.load(Ordering::Relaxed), 1);
1293        assert_eq!(tree.counters.bloom_filter_negatives.load(Ordering::Relaxed), 1);
1294
1295        let inspector = Inspector::default();
1296        tree.record_inspect_data(inspector.root());
1297        let hierarchy = reader::read(&inspector).await.unwrap();
1298        assert_near!(get_fpr(&hierarchy), 50.0, 1e-6);
1299        assert_near!(get_success_percent(&hierarchy), 12.5, 1e-6);
1300
1301        // 6. Query keys 91..91 and 92..92: two more true negatives.
1302        // FP = 1, TN = 3 => classical FPR = 1 / (1 + 3) = 25.0%.
1303        // 3 layers skipped out of 12 total layer evaluations (2 layers across 6 queries) => 25.0%.
1304        assert_eq!(tree.find_value(&TestKey(91..91)).await.expect("find failed"), None);
1305        assert_eq!(tree.find_value(&TestKey(92..92)).await.expect("find failed"), None);
1306        assert_eq!(tree.counters.bloom_filter_false_positives.load(Ordering::Relaxed), 1);
1307        assert_eq!(tree.counters.bloom_filter_negatives.load(Ordering::Relaxed), 3);
1308
1309        let inspector = Inspector::default();
1310        tree.record_inspect_data(inspector.root());
1311        let hierarchy = reader::read(&inspector).await.unwrap();
1312        assert_near!(get_fpr(&hierarchy), 25.0, 1e-6);
1313        assert_near!(get_success_percent(&hierarchy), 25.0, 1e-6);
1314    }
1315
1316    #[fuchsia::test]
1317    async fn test_empty_seal() {
1318        let tree = LSMTree::new(emit_left_merge_fn, None);
1319        tree.seal();
1320        let item = Item::new(TestKey(1..1), 1);
1321        tree.insert(item.clone()).expect("insert error");
1322        let object = Arc::new(FakeObject::new());
1323        let handle = FakeObjectHandle::new(object.clone());
1324        {
1325            let layer_set = tree.immutable_layer_set();
1326            let mut merger = layer_set.merger();
1327            let iter = merger.query(Query::FullScan).await.expect("create merger");
1328            compact_with_iterator(
1329                iter,
1330                0,
1331                Writer::new(&handle).await,
1332                handle.block_size(),
1333                Option::<NoOpYielder>::None,
1334            )
1335            .await
1336            .expect("compact failed");
1337        }
1338        tree.set_layers(layers_from_handles([handle]).await.expect("layers_from_handles failed"));
1339        let found_item = tree.find(&item.key).await.expect("find failed").expect("not found");
1340        assert_eq!(found_item, item);
1341        assert!(!tree.exists(&TestKey(2..2)).await.expect("find failed"));
1342    }
1343
1344    #[fuchsia::test]
1345    async fn test_filter() {
1346        let items = [
1347            Item::new(TestKey(1..1), 1),
1348            Item::new(TestKey(2..2), 2),
1349            Item::new(TestKey(3..3), 3),
1350            Item::new(TestKey(4..4), 4),
1351        ];
1352        let tree = LSMTree::new(emit_left_merge_fn, None);
1353        tree.insert(items[0].clone()).expect("insert error");
1354        tree.insert(items[1].clone()).expect("insert error");
1355        tree.insert(items[2].clone()).expect("insert error");
1356        tree.insert(items[3].clone()).expect("insert error");
1357
1358        let layers = tree.layer_set();
1359        let mut merger = layers.merger();
1360
1361        // Filter out odd keys (which also guarantees we skip the first key which is an edge case).
1362        let mut iter = merger
1363            .query(Query::FullScan)
1364            .await
1365            .expect("seek failed")
1366            .filter(|item: ItemRef<'_, TestKey, u64>| item.key.0.start % 2 == 0)
1367            .await
1368            .expect("filter failed");
1369
1370        assert_eq!(iter.get(), Some(items[1].as_item_ref()));
1371        iter.advance().await.expect("advance failed");
1372        assert_eq!(iter.get(), Some(items[3].as_item_ref()));
1373        iter.advance().await.expect("advance failed");
1374        assert!(iter.get().is_none());
1375    }
1376
1377    #[fuchsia::test]
1378    async fn test_insert_order_agnostic() {
1379        let items = [
1380            Item::new(TestKey(1..1), 1),
1381            Item::new(TestKey(2..2), 2),
1382            Item::new(TestKey(3..3), 3),
1383            Item::new(TestKey(4..4), 4),
1384            Item::new(TestKey(5..5), 5),
1385            Item::new(TestKey(6..6), 6),
1386        ];
1387        let a = LSMTree::new(emit_left_merge_fn, None);
1388        for item in &items {
1389            a.insert(item.clone()).expect("insert error");
1390        }
1391        let b = LSMTree::new(emit_left_merge_fn, None);
1392        let mut shuffled = items.clone();
1393        shuffled.shuffle(&mut rng());
1394        for item in &shuffled {
1395            b.insert(item.clone()).expect("insert error");
1396        }
1397        let layers = a.layer_set();
1398        let mut merger = layers.merger();
1399        let mut iter_a = merger.query(Query::FullScan).await.expect("seek failed");
1400        let layers = b.layer_set();
1401        let mut merger = layers.merger();
1402        let mut iter_b = merger.query(Query::FullScan).await.expect("seek failed");
1403
1404        for item in items {
1405            assert_eq!(Some(item.as_item_ref()), iter_a.get());
1406            assert_eq!(Some(item.as_item_ref()), iter_b.get());
1407            iter_a.advance().await.expect("advance failed");
1408            iter_b.advance().await.expect("advance failed");
1409        }
1410        assert!(iter_a.get().is_none());
1411        assert!(iter_b.get().is_none());
1412    }
1413
1414    enum AuditCacheResult<V> {
1415        Value(V),
1416        NoCache,
1417    }
1418
1419    struct AuditCacheInner<V: Value> {
1420        lookups: u64,
1421        completions: u64,
1422        invalidations: u64,
1423        drops: u64,
1424        result: Option<AuditCacheResult<V>>,
1425        is_cacheable: bool,
1426    }
1427
1428    impl<V: Value> AuditCacheInner<V> {
1429        fn stats(&self) -> (u64, u64, u64, u64) {
1430            (self.lookups, self.completions, self.invalidations, self.drops)
1431        }
1432    }
1433
1434    struct AuditCache<V: Value> {
1435        inner: Arc<Mutex<AuditCacheInner<V>>>,
1436    }
1437
1438    impl<V: Value> AuditCache<V> {
1439        fn new() -> Self {
1440            Self {
1441                inner: Arc::new(Mutex::new(AuditCacheInner {
1442                    lookups: 0,
1443                    completions: 0,
1444                    invalidations: 0,
1445                    drops: 0,
1446                    result: None,
1447                    is_cacheable: true,
1448                })),
1449            }
1450        }
1451    }
1452
1453    struct AuditPlaceholder<V: Value> {
1454        inner: Arc<Mutex<AuditCacheInner<V>>>,
1455        completed: Mutex<bool>,
1456    }
1457
1458    impl<V: Value> ObjectCachePlaceholder<V> for AuditPlaceholder<V> {
1459        fn complete(self: Box<Self>, _: Option<&V>) {
1460            self.inner.lock().completions += 1;
1461            *self.completed.lock() = true;
1462        }
1463    }
1464
1465    impl<V: Value> Drop for AuditPlaceholder<V> {
1466        fn drop(&mut self) {
1467            if !*self.completed.lock() {
1468                self.inner.lock().drops += 1;
1469            }
1470        }
1471    }
1472
1473    impl<K: Key + std::cmp::PartialEq, V: Value> ObjectCache<K, V> for AuditCache<V> {
1474        fn lookup_or_reserve(&self, _key: &K) -> ObjectCacheResult<'_, V> {
1475            {
1476                let mut inner = self.inner.lock();
1477                inner.lookups += 1;
1478                match MutexGuard::try_map_or_err(inner, |inner| match &mut inner.result {
1479                    Some(AuditCacheResult::Value(value)) => Ok(value),
1480                    Some(AuditCacheResult::NoCache) => Err(false),
1481                    None => Err(true),
1482                }) {
1483                    Ok(guard) => {
1484                        return ObjectCacheResult::Value(guard);
1485                    }
1486                    Err((_, false)) => {
1487                        return ObjectCacheResult::NoCache;
1488                    }
1489                    Err((_, true)) => {}
1490                }
1491            }
1492            ObjectCacheResult::Placeholder(Box::new(AuditPlaceholder {
1493                inner: self.inner.clone(),
1494                completed: Mutex::new(false),
1495            }))
1496        }
1497
1498        fn is_cacheable(&self, _key: &K) -> bool {
1499            self.inner.lock().is_cacheable
1500        }
1501
1502        fn invalidate(&self, _key: &K, _value: Option<V>) {
1503            self.inner.lock().invalidations += 1;
1504        }
1505
1506        fn clear(&self) {
1507            self.inner.lock().result = None;
1508        }
1509    }
1510
1511    #[fuchsia::test]
1512    async fn test_cache_handling() {
1513        let item = Item::new(TestKey(1..1), 1);
1514        let cache = Box::new(AuditCache::new());
1515        let inner = cache.inner.clone();
1516        let a = LSMTree::new(emit_left_merge_fn, Some(cache));
1517
1518        // Zero counters.
1519        assert_eq!(inner.lock().stats(), (0, 0, 0, 0));
1520
1521        // Look for an item, but don't find it. So no insertion. It is dropped.
1522        assert!(!a.exists(&item.key).await.expect("Failed find"));
1523        assert_eq!(inner.lock().stats(), (1, 0, 0, 1));
1524
1525        // Insert attempts to invalidate.
1526        let _ = a.insert(item.clone());
1527        assert_eq!(inner.lock().stats(), (1, 0, 1, 1));
1528
1529        // Look for item, find it and insert into the cache.
1530        assert_eq!(
1531            a.find(&item.key).await.expect("Failed find").expect("Item should be found.").value,
1532            item.value
1533        );
1534        assert_eq!(inner.lock().stats(), (2, 1, 1, 1));
1535
1536        // find_value on item2 also inserts into cache
1537        let item2 = Item::new(TestKey(2..2), 2);
1538        let _ = a.insert(item2.clone());
1539        assert_eq!(a.find_value(&item2.key).await.expect("Failed find_value"), Some(item2.value));
1540        assert_eq!(inner.lock().stats(), (3, 2, 2, 1));
1541
1542        // exists on item3 also inserts into cache
1543        let item3 = Item::new(TestKey(3..3), 3);
1544        let _ = a.insert(item3.clone());
1545        assert!(a.exists(&item3.key).await.expect("Failed exists"));
1546        assert_eq!(inner.lock().stats(), (4, 3, 3, 1));
1547
1548        // find_map on item4 also inserts into cache
1549        let item4 = Item::new(TestKey(4..4), 4);
1550        let _ = a.insert(item4.clone());
1551        assert_eq!(
1552            a.find_map(&item4.key, |item| item.value * 2).await.expect("Failed find_map"),
1553            Some(8)
1554        );
1555        assert_eq!(inner.lock().stats(), (5, 4, 4, 1));
1556
1557        // Insert or replace attempts to invalidate as well.
1558        a.replace_or_insert(item.clone());
1559        assert_eq!(inner.lock().stats(), (5, 4, 5, 1));
1560    }
1561
1562    #[fuchsia::test]
1563    async fn test_cache_hit() {
1564        let item = Item::new(TestKey(1..1), 1);
1565        let cache = Box::new(AuditCache::new());
1566        let inner = cache.inner.clone();
1567        let a = LSMTree::new(emit_left_merge_fn, Some(cache));
1568
1569        // Zero counters.
1570        assert_eq!(inner.lock().stats(), (0, 0, 0, 0));
1571
1572        // Insert attempts to invalidate.
1573        let _ = a.insert(item.clone());
1574        assert_eq!(inner.lock().stats(), (0, 0, 1, 0));
1575
1576        // Set up the item to find in the cache.
1577        inner.lock().result = Some(AuditCacheResult::Value(item.value.clone()));
1578
1579        // Look for item, find it in cache, so no insert.
1580        assert_eq!(
1581            a.find_value(&item.key).await.expect("Failed find").expect("Item should be found."),
1582            item.value
1583        );
1584        assert_eq!(inner.lock().stats(), (1, 0, 1, 0));
1585    }
1586
1587    #[fuchsia::test]
1588    async fn test_cache_hit_deleted_marker() {
1589        let item = Item::new(TestKey(1..1), 1);
1590        let cache = Box::new(AuditCache::new());
1591        let inner = cache.inner.clone();
1592        let a = LSMTree::new(emit_left_merge_fn, Some(cache));
1593
1594        // Zero counters.
1595        assert_eq!(inner.lock().stats(), (0, 0, 0, 0));
1596
1597        // Insert attempts to invalidate.
1598        let _ = a.insert(item.clone());
1599        assert_eq!(inner.lock().stats(), (0, 0, 1, 0));
1600
1601        // Set up the cache to return DELETED_MARKER.
1602        inner.lock().result = Some(AuditCacheResult::Value(u64::DELETED_MARKER));
1603
1604        // find_value should hit the cache, see DELETED_MARKER, and return None.
1605        assert_eq!(a.find_value(&item.key).await.expect("Failed find_value"), None);
1606        assert_eq!(inner.lock().stats(), (1, 0, 1, 0));
1607
1608        // exists should also return false on cache hit DELETED_MARKER.
1609        inner.lock().result = Some(AuditCacheResult::Value(u64::DELETED_MARKER));
1610        assert!(!a.exists(&item.key).await.expect("Failed exists"));
1611        assert_eq!(inner.lock().stats(), (2, 0, 1, 0));
1612
1613        // find should also return None on cache hit DELETED_MARKER.
1614        inner.lock().result = Some(AuditCacheResult::Value(u64::DELETED_MARKER));
1615        assert!(a.find(&item.key).await.expect("Failed find").is_none());
1616        assert_eq!(inner.lock().stats(), (3, 0, 1, 0));
1617
1618        // find_map should also return None on cache hit DELETED_MARKER.
1619        inner.lock().result = Some(AuditCacheResult::Value(u64::DELETED_MARKER));
1620        assert!(a.find_map(&item.key, |_| ()).await.expect("Failed find_map").is_none());
1621        assert_eq!(inner.lock().stats(), (4, 0, 1, 0));
1622    }
1623
1624    #[fuchsia::test]
1625    async fn test_cache_says_uncacheable() {
1626        let item = Item::new(TestKey(1..1), 1);
1627        let cache = Box::new(AuditCache::new());
1628        let inner = cache.inner.clone();
1629        let a = LSMTree::new(emit_left_merge_fn, Some(cache));
1630        let _ = a.insert(item.clone());
1631
1632        // One invalidation from the insert.
1633        assert_eq!(inner.lock().stats(), (0, 0, 1, 0));
1634
1635        // Set up the NoCache response to find in the cache.
1636        inner.lock().result = Some(AuditCacheResult::NoCache);
1637
1638        // Look for item, it is uncacheable, so no insert.
1639        assert_eq!(
1640            a.find_value(&item.key).await.expect("Failed find").expect("Should find item"),
1641            item.value
1642        );
1643        assert_eq!(inner.lock().stats(), (1, 0, 1, 0));
1644    }
1645
1646    #[fuchsia::test]
1647    async fn test_uncacheable_key_skips_invalidation() {
1648        let item = Item::new(TestKey(1..1), 1);
1649        let cache = Box::new(AuditCache::new());
1650        cache.inner.lock().is_cacheable = false;
1651        let inner = cache.inner.clone();
1652        let a = LSMTree::new(emit_left_merge_fn, Some(cache));
1653
1654        // Insert of an uncacheable key should not invalidate the cache.
1655        a.insert(item.clone()).expect("insert failed");
1656        assert_eq!(inner.lock().stats(), (0, 0, 0, 0));
1657
1658        // replace_or_insert of an uncacheable key should not invalidate the cache.
1659        a.replace_or_insert(item.clone());
1660        assert_eq!(inner.lock().stats(), (0, 0, 0, 0));
1661
1662        // merge_into of an uncacheable key should not invalidate the cache.
1663        a.merge_into(item.clone(), &TestKey(1..1));
1664        assert_eq!(inner.lock().stats(), (0, 0, 0, 0));
1665    }
1666
1667    struct FailLayer {
1668        drop_event: Mutex<Option<Arc<DropEvent>>>,
1669    }
1670
1671    impl FailLayer {
1672        fn new() -> Self {
1673            Self { drop_event: Mutex::new(Some(Arc::new(DropEvent::new()))) }
1674        }
1675    }
1676
1677    #[async_trait]
1678    impl<K: Key, V: Value> Layer<K, V> for FailLayer {
1679        async fn seek(
1680            &self,
1681            _bound: std::ops::Bound<&K>,
1682        ) -> Result<BoxedLayerIterator<'_, K, V>, Error> {
1683            Err(anyhow!("Purposely failed seek"))
1684        }
1685
1686        fn lock(&self) -> Option<Arc<DropEvent>> {
1687            self.drop_event.lock().clone()
1688        }
1689
1690        fn len(&self) -> usize {
1691            0
1692        }
1693
1694        async fn close(&self) {
1695            let listener = match std::mem::replace(&mut (*self.drop_event.lock()), None) {
1696                Some(drop_event) => drop_event.listen(),
1697                None => return,
1698            };
1699            listener.await;
1700        }
1701
1702        fn get_version(&self) -> Version {
1703            LATEST_VERSION
1704        }
1705
1706        async fn key_exists(&self, _key: &K) -> Result<Existence, Error> {
1707            unimplemented!();
1708        }
1709    }
1710
1711    struct MockLayer {
1712        exists_result: Existence,
1713        drop_event: Mutex<Option<Arc<DropEvent>>>,
1714        cleared: std::sync::atomic::AtomicBool,
1715    }
1716
1717    impl MockLayer {
1718        fn new(exists_result: Existence) -> Self {
1719            Self {
1720                exists_result,
1721                drop_event: Mutex::new(Some(Arc::new(DropEvent::new()))),
1722                cleared: std::sync::atomic::AtomicBool::new(false),
1723            }
1724        }
1725    }
1726
1727    #[async_trait]
1728    impl<K: Key, V: Value> Layer<K, V> for MockLayer {
1729        async fn seek(
1730            &self,
1731            _bound: std::ops::Bound<&K>,
1732        ) -> Result<BoxedLayerIterator<'_, K, V>, Error> {
1733            unimplemented!()
1734        }
1735
1736        fn clear_cached_data(&self) {
1737            self.cleared.store(true, Ordering::Relaxed);
1738        }
1739
1740        fn lock(&self) -> Option<Arc<DropEvent>> {
1741            self.drop_event.lock().clone()
1742        }
1743
1744        fn len(&self) -> usize {
1745            0
1746        }
1747
1748        async fn close(&self) {
1749            let listener = match std::mem::replace(&mut (*self.drop_event.lock()), None) {
1750                Some(drop_event) => drop_event.listen(),
1751                None => return,
1752            };
1753            listener.await;
1754        }
1755
1756        fn get_version(&self) -> Version {
1757            LATEST_VERSION
1758        }
1759
1760        async fn key_exists(&self, _key: &K) -> Result<Existence, Error> {
1761            Ok(self.exists_result)
1762        }
1763    }
1764
1765    #[fuchsia::test]
1766    async fn test_clear_cache() {
1767        let item = Item::new(TestKey(1..1), 1);
1768        let cache = Box::new(AuditCache::new());
1769        let inner = cache.inner.clone();
1770        let tree = LSMTree::new(emit_left_merge_fn, Some(cache));
1771
1772        let layer1 = Arc::new(MockLayer::new(Existence::MaybeExists));
1773        let layer2 = Arc::new(MockLayer::new(Existence::MaybeExists));
1774        tree.set_layers(vec![
1775            layer1.clone() as Arc<dyn Layer<TestKey, u64>>,
1776            layer2.clone() as Arc<dyn Layer<TestKey, u64>>,
1777        ]);
1778
1779        inner.lock().result = Some(AuditCacheResult::Value(item.value));
1780        assert_eq!(tree.find_value(&item.key).await.expect("find_value failed"), Some(item.value));
1781        assert!(!layer1.cleared.load(Ordering::Relaxed));
1782        assert!(!layer2.cleared.load(Ordering::Relaxed));
1783
1784        tree.clear_cache();
1785
1786        assert!(inner.lock().result.is_none());
1787        assert!(layer1.cleared.load(Ordering::Relaxed));
1788        assert!(layer2.cleared.load(Ordering::Relaxed));
1789    }
1790
1791    #[fuchsia::test]
1792    async fn test_layer_set_key_exists() {
1793        use super::LockedLayer;
1794
1795        let tree = LSMTree::new(emit_left_merge_fn, None);
1796        let mut layer_set = tree.empty_layer_set();
1797
1798        // Empty layer set should return Missing.
1799        assert_eq!(
1800            layer_set.key_exists(&TestKey(0..1)).await.expect("key_exists failed"),
1801            Existence::Missing
1802        );
1803
1804        // Add a layer that returns Missing.
1805        layer_set.layers.push(LockedLayer::from(
1806            Arc::new(MockLayer::new(Existence::Missing)) as Arc<dyn Layer<TestKey, u64>>
1807        ));
1808        assert_eq!(
1809            layer_set.key_exists(&TestKey(0..1)).await.expect("key_exists failed"),
1810            Existence::Missing
1811        );
1812
1813        // Add a layer that returns MaybeExists.
1814        layer_set.layers.push(LockedLayer::from(
1815            Arc::new(MockLayer::new(Existence::MaybeExists)) as Arc<dyn Layer<TestKey, u64>>
1816        ));
1817        assert_eq!(
1818            layer_set.key_exists(&TestKey(0..1)).await.expect("key_exists failed"),
1819            Existence::MaybeExists
1820        );
1821
1822        // Add a layer that returns Exists.
1823        layer_set.layers.insert(
1824            0,
1825            LockedLayer::from(
1826                Arc::new(MockLayer::new(Existence::Exists)) as Arc<dyn Layer<TestKey, u64>>
1827            ),
1828        );
1829        assert_eq!(
1830            layer_set.key_exists(&TestKey(0..1)).await.expect("key_exists failed"),
1831            Existence::Exists
1832        );
1833    }
1834
1835    #[fuchsia::test]
1836    async fn test_failed_lookup() {
1837        let cache = Box::new(AuditCache::new());
1838        let inner = cache.inner.clone();
1839        let a = LSMTree::new(emit_left_merge_fn, Some(cache));
1840        a.set_layers(vec![Arc::new(FailLayer::new())]);
1841
1842        // Zero counters.
1843        assert_eq!(inner.lock().stats(), (0, 0, 0, 0));
1844
1845        // Lookup should fail and drop the placeholder.
1846        assert!(a.find(&TestKey(1..1)).await.is_err());
1847        assert_eq!(inner.lock().stats(), (1, 0, 0, 1));
1848    }
1849}
1850
1851#[cfg(fuzz)]
1852mod fuzz {
1853    use crate::lsm_tree::types::{Item, Value};
1854    use crate::serialized_types::{
1855        LATEST_VERSION, Version, Versioned, VersionedLatest, versioned_type,
1856    };
1857    use arbitrary::Arbitrary;
1858
1859    use fuzz::fuzz;
1860
1861    use super::testing::TestKey;
1862
1863    impl Versioned for u64 {}
1864    versioned_type! { 1.. => u64 }
1865
1866    impl Value for u64 {
1867        const DELETED_MARKER: Self = 0;
1868    }
1869
1870    // Note: This code isn't really dead. it's used below in
1871    // `fuzz_lsm_tree_action`. However, the `#[fuzz]` proc macro attribute
1872    // obfuscates the usage enough to confuse the compiler.
1873    #[allow(dead_code)]
1874    #[derive(Arbitrary)]
1875    enum FuzzAction {
1876        Insert(Item<TestKey, u64>),
1877        ReplaceOrInsert(Item<TestKey, u64>),
1878        MergeInto(Item<TestKey, u64>, TestKey),
1879        Find(TestKey),
1880        Seal,
1881    }
1882
1883    #[fuzz]
1884    fn fuzz_lsm_tree_actions(actions: Vec<FuzzAction>) {
1885        use super::LSMTree;
1886        use crate::lsm_tree::merge::{MergeLayerIterator, MergeResult};
1887        use futures::executor::block_on;
1888
1889        fn emit_left_merge_fn(
1890            _left: &MergeLayerIterator<'_, TestKey, u64>,
1891            _right: &MergeLayerIterator<'_, TestKey, u64>,
1892        ) -> MergeResult<TestKey, u64> {
1893            MergeResult::EmitLeft
1894        }
1895
1896        let tree = LSMTree::new(emit_left_merge_fn, None);
1897        for action in actions {
1898            match action {
1899                FuzzAction::Insert(item) => {
1900                    let _ = tree.insert(item);
1901                }
1902                FuzzAction::ReplaceOrInsert(item) => {
1903                    tree.replace_or_insert(item);
1904                }
1905                FuzzAction::Find(key) => {
1906                    block_on(tree.find(&key)).expect("find failed");
1907                }
1908                FuzzAction::MergeInto(item, bound) => tree.merge_into(item, &bound),
1909                FuzzAction::Seal => tree.seal(),
1910            };
1911        }
1912    }
1913}