Skip to main content

fxfs/lsm_tree/
persistent_layer.rs

1// Copyright 2024 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// PersistentLayer object format
6//
7// The layer is made up of 1 or more "blocks" whose size are some multiple of the block size used
8// by the underlying handle.
9//
10// The persistent layer has 4 types of blocks:
11//  - Header block
12//  - Data block
13//  - BloomFilter block
14//  - Seek block (+LayerInfo)
15//
16// The structure of the file is as follows:
17//
18// blk#     contents
19// 0        [Header]
20// 1        [Data]
21// 2        [Data]
22// ...      [Data]
23// L        [BloomFilter]
24// L + 1    [BloomFilter]
25// ...      [BloomFilter]
26// M        [Seek]
27// M + 1    [Seek]
28// ...      [Seek]
29// N        [Seek/LayerInfo]
30//
31// Generally, there will be an order of magnitude more Data blocks than Seek/BloomFilter blocks.
32//
33// Header contains a Version-prefixed LayerHeader struct.  This version is used for everything in
34// the layer file.
35//
36// Data blocks contain a little endian encoded u16 item count at the start, then a series of
37// serialized items, and a list of little endian u16 offsets within the block for where
38// serialized items start, excluding the first item (since it is at a known offset). The list of
39// offsets ends at the end of the block and since the items are of variable length, there may be
40// space between the two sections if the next item and its offset cannot fit into the block.
41//
42// |item_count|item|item|item|item|item|item|dead space|offset|offset|offset|offset|offset|
43//
44// BloomFilter blocks contain a bitmap which is used to probabilistically determine if a given key
45// might exist in the layer file.   See `BloomFilter` for details on this structure.  Note that this
46// can be absent from the file for small layer files.
47//
48// Seek/LayerInfo blocks contain both the seek table, and a single LayerInfo struct at the tail of
49// the last block, with the LayerInfo's length written as a little-endian u64 at the very end.  The
50// padding between the two structs is ignored but nominally is zeroed. They share blocks to avoid
51// wasting padding bytes.  Note that the seek table can be absent from the file for small layer
52// files (but there will always be one block for the LayerInfo).
53//
54// The seek table consists of a little-endian u64 for every data block except for the first one. The
55// entries should be monotonically increasing, as they represent some mapping for how the keys for
56// the first item in each block would be predominantly sorted, and there may be duplicate entries.
57// There should be exactly as many seek blocks as are required to house one entry fewer than the
58// number of data blocks.
59
60use crate::drop_event::DropEvent;
61use crate::errors::FxfsError;
62use crate::filesystem::MAX_BLOCK_SIZE;
63use crate::log::*;
64use crate::lsm_tree::bloom_filter::{BloomFilterReader, BloomFilterStats, BloomFilterWriter};
65use crate::lsm_tree::types::{
66    BoxedLayerIterator, Existence, FuzzyHash, Item, ItemRef, Key, Layer, LayerIterator, LayerValue,
67    LayerWriter,
68};
69use crate::object_handle::{ObjectHandle, ReadObjectHandle, WriteBytes};
70use crate::object_store::caching_object_handle::{CHUNK_SIZE, CachedChunk, CachingObjectHandle};
71use crate::round::{round_down, round_up};
72use crate::serialized_types::{
73    LATEST_VERSION, REMOVE_ITEM_SEQUENCE_VERSION, Version, Versioned, VersionedLatest,
74};
75use anyhow::{Context, Error, anyhow, bail, ensure};
76use async_trait::async_trait;
77use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
78use fprint::TypeFingerprint;
79use fuchsia_sync::Mutex;
80use serde::{Deserialize, Serialize};
81use static_assertions::const_assert;
82use std::cmp::Ordering;
83use std::io::{Read, Write as _};
84use std::marker::PhantomData;
85use std::ops::Bound;
86use std::sync::Arc;
87
88const PERSISTENT_LAYER_MAGIC: &[u8; 8] = b"FxfsLayr";
89
90/// LayerHeader is stored in the first block of the persistent layer.
91pub type LayerHeader = LayerHeaderV39;
92
93#[derive(Debug, Serialize, Deserialize, TypeFingerprint, Versioned)]
94pub struct LayerHeaderV39 {
95    /// 'FxfsLayr'
96    magic: [u8; 8],
97    /// The block size used within this layer file. This is typically set at compaction time to the
98    /// same block size as the underlying object handle.
99    ///
100    /// (Each block starts with a 2 byte item count so there is a 64k item limit per block,
101    /// regardless of block size).
102    block_size: u64,
103}
104
105/// The last block of each layer contains metadata for the rest of the layer.
106pub type LayerInfo = LayerInfoV39;
107
108#[derive(Debug, Serialize, Deserialize, TypeFingerprint, Versioned)]
109pub struct LayerInfoV39 {
110    /// How many items are in the layer file.  Mainly used for sizing bloom filters during
111    /// compaction.
112    num_items: usize,
113    /// The number of data blocks in the layer file.
114    num_data_blocks: u64,
115    /// The size of the bloom filter in the layer file.  Not necessarily block-aligned.
116    bloom_filter_size_bytes: usize,
117    /// The seed for the nonces used in the bloom filter.
118    bloom_filter_seed: u64,
119    /// How many nonces to use for bloom filter hashing.
120    bloom_filter_num_hashes: usize,
121}
122
123/// A handle to a persistent layer.
124pub struct PersistentLayer<K, V> {
125    // We retain a reference to the underlying object handle so we can hand out references to it for
126    // `Layer::handle` when clients need it.  Internal reads should go through
127    // `caching_object_handle` so they are cached.  Note that `CachingObjectHandle` used to
128    // implement `ReadObjectHandle`, but that was removed so that `CachingObjectHandle` could hand
129    // out data references rather than requiring copying to a buffer, which speeds up LSM tree
130    // operations.
131    object_handle: Arc<dyn ReadObjectHandle>,
132    caching_object_handle: CachingObjectHandle<Arc<dyn ReadObjectHandle>>,
133    version: Version,
134    block_size: u64,
135    data_size: u64,
136    seek_table: Vec<u64>,
137    num_items: usize,
138    bloom_filter: Option<BloomFilterReader<K>>,
139    bloom_filter_stats: Option<BloomFilterStats>,
140    close_event: Mutex<Option<Arc<DropEvent>>>,
141    _value_type: PhantomData<V>,
142}
143
144#[derive(Debug)]
145struct BufferCursor {
146    chunk: Option<CachedChunk>,
147    pos: usize,
148}
149
150impl std::io::Read for BufferCursor {
151    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
152        let chunk = if let Some(chunk) = &self.chunk {
153            chunk
154        } else {
155            return Ok(0);
156        };
157        let to_read = std::cmp::min(buf.len(), chunk.len().saturating_sub(self.pos));
158        if to_read > 0 {
159            buf[..to_read].copy_from_slice(&chunk[self.pos..self.pos + to_read]);
160            self.pos += to_read;
161        }
162        Ok(to_read)
163    }
164}
165
166const MIN_BLOCK_SIZE: u64 = 512;
167
168// For small layer files, don't bother with the bloom filter.  Arbitrarily chosen.
169const MINIMUM_DATA_BLOCKS_FOR_BLOOM_FILTER: usize = 4;
170
171// How many blocks we reserve for the header.  Data blocks start at this offset.
172const NUM_HEADER_BLOCKS: u64 = 1;
173
174/// The smallest possible (empty) layer file is always 2 blocks, one for the header and one for
175/// LayerInfo.
176const MINIMUM_LAYER_FILE_BLOCKS: u64 = 2;
177
178// Put safety rails on the size of the bloom filter and seek table to avoid OOMing the system.
179// It's more likely that tampering has occurred in these cases.
180const MAX_BLOOM_FILTER_SIZE: usize = 64 * 1024 * 1024;
181const MAX_SEEK_TABLE_SIZE: usize = 64 * 1024 * 1024;
182
183// The following constants refer to sizes of metadata in the data blocks.
184const PER_DATA_BLOCK_HEADER_SIZE: usize = 2;
185const PER_DATA_BLOCK_SEEK_ENTRY_SIZE: usize = 2;
186
187// A key-only iterator, used while seeking through the tree.
188struct KeyOnlyIterator<'iter, K: Key, V: LayerValue> {
189    // Allocated out of |layer|.
190    buffer: BufferCursor,
191
192    layer: &'iter PersistentLayer<K, V>,
193
194    // The position of the _next_ block to be read.
195    pos: u64,
196
197    // The item index in the current block.
198    item_index: u16,
199
200    // The number of items in the current block.
201    item_count: u16,
202
203    // The current key.
204    key: Option<K>,
205
206    // Set by a wrapping iterator once the value has been deserialized, so the KeyOnlyIterator knows
207    // whether it is pointing at the next key or not.
208    value_deserialized: bool,
209}
210
211impl<K: Key, V: LayerValue> KeyOnlyIterator<'_, K, V> {
212    fn new<'iter>(layer: &'iter PersistentLayer<K, V>, pos: u64) -> KeyOnlyIterator<'iter, K, V> {
213        assert!(pos % layer.block_size == 0);
214        KeyOnlyIterator {
215            layer,
216            buffer: BufferCursor { chunk: None, pos: pos as usize % CHUNK_SIZE },
217            pos,
218            item_index: 0,
219            item_count: 0,
220            key: None,
221            value_deserialized: false,
222        }
223    }
224
225    // Repositions the iterator to point to the `index`'th item in the current block.
226    // Returns an error if the index is out of range or the resulting offset contains an obviously
227    // invalid value.
228    fn seek_to_block_item(&mut self, index: u16) -> Result<(), Error> {
229        ensure!(index < self.item_count, FxfsError::OutOfRange);
230        if index == self.item_index && self.value_deserialized {
231            // Fast-path when we are seeking in a linear manner, as is the case when advancing a
232            // wrapping iterator that also deserializes the values.
233            return Ok(());
234        }
235        let offset_in_block = if index == 0 {
236            // First entry isn't actually recorded, it is at the start of the block after the item
237            // count.
238            PER_DATA_BLOCK_HEADER_SIZE
239        } else {
240            let old_buffer_pos = self.buffer.pos;
241            self.buffer.pos = round_up(self.buffer.pos, self.layer.block_size as usize).unwrap()
242                - (PER_DATA_BLOCK_SEEK_ENTRY_SIZE * (usize::from(self.item_count - index)));
243            let res = self.buffer.read_u16::<LittleEndian>();
244            self.buffer.pos = old_buffer_pos;
245            let offset_in_block = res.context("Failed to read offset")? as usize;
246            if offset_in_block >= self.layer.block_size as usize
247                || offset_in_block <= PER_DATA_BLOCK_HEADER_SIZE
248            {
249                return Err(anyhow!(FxfsError::Inconsistent))
250                    .context(format!("Offset {} is out of valid range.", offset_in_block));
251            }
252            offset_in_block
253        };
254        self.item_index = index;
255        self.buffer.pos =
256            round_down(self.buffer.pos, self.layer.block_size as usize) + offset_in_block;
257        Ok(())
258    }
259
260    async fn advance(&mut self) -> Result<(), Error> {
261        if self.item_index >= self.item_count {
262            if self.pos >= self.layer.data_offset() + self.layer.data_size {
263                self.key = None;
264                return Ok(());
265            }
266            if self.buffer.chunk.is_none() || self.pos as usize % CHUNK_SIZE == 0 {
267                self.buffer.chunk = Some(
268                    self.layer
269                        .caching_object_handle
270                        .read(self.pos as usize)
271                        .await
272                        .context("Reading during advance")?,
273                );
274            }
275            self.buffer.pos = self.pos as usize % CHUNK_SIZE;
276            self.item_count = self.buffer.read_u16::<LittleEndian>()?;
277            if self.item_count == 0 {
278                bail!(
279                    "Read block with zero item count (object: {}, offset: {})",
280                    self.layer.object_handle.object_id(),
281                    self.pos
282                );
283            }
284            debug!(
285                pos = self.pos,
286                buf:? = self.buffer,
287                object_size = self.layer.data_offset() + self.layer.data_size,
288                oid = self.layer.object_handle.object_id();
289                ""
290            );
291            self.pos += self.layer.block_size;
292            self.item_index = 0;
293            self.value_deserialized = true;
294        }
295        self.seek_to_block_item(self.item_index)?;
296        self.key = Some(
297            K::deserialize_from_version(self.buffer.by_ref(), self.layer.version)
298                .context("Corrupt layer (key)")?,
299        );
300        self.item_index += 1;
301        self.value_deserialized = false;
302        Ok(())
303    }
304
305    fn get(&self) -> Option<&K> {
306        self.key.as_ref()
307    }
308}
309
310struct Iterator<'iter, K: Key, V: LayerValue> {
311    inner: KeyOnlyIterator<'iter, K, V>,
312    // The current item.
313    item: Option<Item<K, V>>,
314}
315
316impl<'iter, K: Key, V: LayerValue> Iterator<'iter, K, V> {
317    fn new(mut seek_iterator: KeyOnlyIterator<'iter, K, V>) -> Result<Self, Error> {
318        let key = std::mem::take(&mut seek_iterator.key);
319        let item = if let Some(key) = key {
320            seek_iterator.value_deserialized = true;
321            let value = V::deserialize_from_version(
322                seek_iterator.buffer.by_ref(),
323                seek_iterator.layer.version,
324            )
325            .context("Corrupt layer (value)")?;
326            if seek_iterator.layer.version.major < REMOVE_ITEM_SEQUENCE_VERSION {
327                seek_iterator.buffer.read_u64::<LittleEndian>().context("Corrupt layer (seq)")?;
328            }
329            Some(Item { key, value })
330        } else {
331            None
332        };
333        Ok(Self { inner: seek_iterator, item })
334    }
335}
336
337#[async_trait]
338impl<'iter, K: Key, V: LayerValue> LayerIterator<K, V> for Iterator<'iter, K, V> {
339    async fn advance(&mut self) -> Result<(), Error> {
340        self.inner.advance().await?;
341        let key = std::mem::take(&mut self.inner.key);
342        self.item = if let Some(key) = key {
343            self.inner.value_deserialized = true;
344            let value =
345                V::deserialize_from_version(self.inner.buffer.by_ref(), self.inner.layer.version)
346                    .context("Corrupt layer (value)")?;
347            if self.inner.layer.version.major < REMOVE_ITEM_SEQUENCE_VERSION {
348                self.inner.buffer.read_u64::<LittleEndian>().context("Corrupt layer (seq)")?;
349            }
350            Some(Item { key, value })
351        } else {
352            None
353        };
354        Ok(())
355    }
356
357    fn get(&self) -> Option<ItemRef<'_, K, V>> {
358        self.item.as_ref().map(<&Item<K, V>>::into)
359    }
360}
361
362// Returns the size of the seek table in bytes.
363fn seek_table_size(num_data_blocks: u64) -> usize {
364    // The first data block doesn't have an entry.
365    let seek_table_entries = num_data_blocks.saturating_sub(1) as usize;
366    if seek_table_entries == 0 {
367        return 0;
368    }
369    let entry_size = std::mem::size_of::<u64>();
370    seek_table_entries * entry_size
371}
372
373async fn load_seek_table(
374    object_handle: &(impl ReadObjectHandle + 'static),
375    seek_table_offset: u64,
376    num_data_blocks: u64,
377) -> Result<Vec<u64>, Error> {
378    let seek_table_size = seek_table_size(num_data_blocks);
379    if seek_table_size == 0 {
380        return Ok(vec![]);
381    }
382    if seek_table_size > MAX_SEEK_TABLE_SIZE {
383        return Err(anyhow!(FxfsError::NotSupported)).context("Seek table too large");
384    }
385    let mut buffer = object_handle.allocate_buffer(seek_table_size).await;
386    let bytes_read = object_handle
387        .read(seek_table_offset, buffer.as_mut())
388        .await
389        .context("Reading seek table blocks")?;
390    ensure!(bytes_read == seek_table_size, "Short read");
391
392    let mut seek_table = Vec::with_capacity(num_data_blocks as usize);
393    // No entry for the first data block, assume a lower bound 0.
394    seek_table.push(0);
395    let mut prev = 0;
396    for chunk in buffer.subslice(0..seek_table_size).as_ptr_slice().iter_as::<[u8; 8]>() {
397        let next = u64::from_le_bytes(chunk.read());
398        // Should be in strict ascending order, otherwise something's broken, or we've gone off
399        // the end and we're reading zeroes.
400        if prev > next {
401            return Err(anyhow!(FxfsError::Inconsistent))
402                .context(format!("Seek table entry out of order, {:?} > {:?}", prev, next));
403        }
404        prev = next;
405        seek_table.push(next);
406    }
407    Ok(seek_table)
408}
409
410async fn load_bloom_filter<K: FuzzyHash>(
411    handle: &(impl ReadObjectHandle + 'static),
412    bloom_filter_offset: u64,
413    layer_info: &LayerInfo,
414) -> Result<Option<BloomFilterReader<K>>, Error> {
415    if layer_info.bloom_filter_size_bytes == 0 {
416        return Ok(None);
417    }
418    if layer_info.bloom_filter_size_bytes > MAX_BLOOM_FILTER_SIZE {
419        return Err(anyhow!(FxfsError::NotSupported)).context("Bloom filter too large");
420    }
421    let mut buffer = handle.allocate_buffer(layer_info.bloom_filter_size_bytes).await;
422    handle.read(bloom_filter_offset, buffer.as_mut()).await.context("Failed to read")?;
423    Ok(Some(BloomFilterReader::read(
424        buffer.subslice(0..layer_info.bloom_filter_size_bytes).as_ptr_slice(),
425        layer_info.bloom_filter_seed,
426        layer_info.bloom_filter_num_hashes,
427    )?))
428}
429
430impl<K: Key, V: LayerValue> PersistentLayer<K, V> {
431    pub async fn open(handle: impl ReadObjectHandle + 'static) -> Result<Arc<Self>, Error> {
432        let bs = handle.block_size();
433        let mut buffer = handle.allocate_buffer(bs as usize).await;
434        handle.read(0, buffer.as_mut()).await.context("Failed to read first block")?;
435        let mut reader = buffer.as_ptr_slice();
436        let version = Version::deserialize_from(&mut reader)?;
437
438        ensure!(version <= LATEST_VERSION, FxfsError::InvalidVersion);
439        let header = LayerHeader::deserialize_from_version(&mut reader, version)
440            .context("Failed to deserialize header")?;
441        if &header.magic != PERSISTENT_LAYER_MAGIC {
442            return Err(anyhow!(FxfsError::Inconsistent).context("Invalid layer file magic"));
443        }
444        if header.block_size == 0 || !header.block_size.is_power_of_two() {
445            return Err(anyhow!(FxfsError::Inconsistent))
446                .context(format!("Invalid block size {}", header.block_size));
447        }
448        ensure!(header.block_size > 0, FxfsError::Inconsistent);
449        ensure!(header.block_size <= MAX_BLOCK_SIZE, FxfsError::NotSupported);
450        let physical_block_size = handle.block_size();
451        if header.block_size % physical_block_size != 0 {
452            return Err(anyhow!(FxfsError::Inconsistent)).context(format!(
453                "{} not a multiple of physical block size {}",
454                header.block_size, physical_block_size
455            ));
456        }
457
458        let bs = header.block_size as usize;
459        if handle.get_size() < MINIMUM_LAYER_FILE_BLOCKS * bs as u64 {
460            return Err(anyhow!(FxfsError::Inconsistent).context("Layer file too short"));
461        }
462
463        let layer_info = {
464            let last_block_offset = handle
465                .get_size()
466                .checked_sub(header.block_size)
467                .ok_or(FxfsError::Inconsistent)
468                .context("Layer file unexpectedly short")?;
469            handle
470                .read(last_block_offset, buffer.subslice_mut(0..header.block_size as usize))
471                .await
472                .context("Failed to read layer info")?;
473            let layer_info_len =
474                u64::from_le_bytes(buffer.subslice(bs - 8..bs).as_ptr_slice().read().unwrap());
475            let layer_info_offset = bs
476                .checked_sub(std::mem::size_of::<u64>() + layer_info_len as usize)
477                .ok_or(FxfsError::Inconsistent)
478                .context("Invalid layer info length")?;
479            let mut reader = buffer.subslice(layer_info_offset..).as_ptr_slice();
480            LayerInfo::deserialize_from_version(&mut reader, version)
481                .context("Failed to deserialize LayerInfo")?
482        };
483        std::mem::drop(buffer);
484        if layer_info.num_items == 0 && layer_info.num_data_blocks > 0 {
485            return Err(anyhow!(FxfsError::Inconsistent))
486                .context("Invalid num_items/num_data_blocks");
487        }
488        let total_blocks = handle.get_size() / header.block_size;
489        let bloom_filter_blocks =
490            round_up(layer_info.bloom_filter_size_bytes as u64, header.block_size)
491                .unwrap_or(layer_info.bloom_filter_size_bytes as u64)
492                / header.block_size;
493        if layer_info.num_data_blocks + bloom_filter_blocks
494            > total_blocks - MINIMUM_LAYER_FILE_BLOCKS
495        {
496            return Err(anyhow!(FxfsError::Inconsistent)).context("Invalid number of blocks");
497        }
498
499        let bloom_filter_offset =
500            header.block_size * (NUM_HEADER_BLOCKS + layer_info.num_data_blocks);
501        let bloom_filter = if version == LATEST_VERSION {
502            load_bloom_filter(&handle, bloom_filter_offset, &layer_info)
503                .await
504                .context("Failed to load bloom filter")?
505        } else {
506            // Ignore the bloom filter for layer files in outdated versions.  We don't know whether
507            // keys have changed formats or not (and therefore have different hash values), so we
508            // must ignore the bloom filter and always query the layer.
509            None
510        };
511        let bloom_filter_stats = bloom_filter.as_ref().map(|b| b.stats());
512
513        let seek_offset = header.block_size
514            * (NUM_HEADER_BLOCKS + layer_info.num_data_blocks + bloom_filter_blocks);
515        let seek_table = load_seek_table(&handle, seek_offset, layer_info.num_data_blocks)
516            .await
517            .context("Failed to load seek table")?;
518
519        let object_handle = Arc::new(handle) as Arc<dyn ReadObjectHandle>;
520        let caching_object_handle = CachingObjectHandle::new(object_handle.clone());
521        Ok(Arc::new(PersistentLayer {
522            object_handle,
523            caching_object_handle,
524            version,
525            block_size: header.block_size,
526            data_size: layer_info.num_data_blocks * header.block_size,
527            seek_table,
528            num_items: layer_info.num_items,
529            bloom_filter,
530            bloom_filter_stats,
531            close_event: Mutex::new(Some(Arc::new(DropEvent::new()))),
532            _value_type: PhantomData::default(),
533        }))
534    }
535
536    /// Whether the bloom filter for the layer file is consulted or not.  If this is false, then
537    /// `maybe_contains_key` will always return true.
538    /// Note that the persistent layer file may still have a bloom filter, but it might be ignored
539    /// (e.g. for a layer file on an older version).
540    pub fn has_bloom_filter(&self) -> bool {
541        self.bloom_filter.is_some()
542    }
543
544    fn data_offset(&self) -> u64 {
545        NUM_HEADER_BLOCKS * self.block_size
546    }
547}
548
549#[async_trait]
550impl<K: Key, V: LayerValue> Layer<K, V> for PersistentLayer<K, V> {
551    fn handle(&self) -> Option<&dyn ReadObjectHandle> {
552        Some(&self.object_handle)
553    }
554
555    fn purge_cached_data(&self) {
556        self.caching_object_handle.purge();
557    }
558
559    async fn seek<'a>(&'a self, bound: Bound<&K>) -> Result<BoxedLayerIterator<'a, K, V>, Error> {
560        let (key, excluded) = match bound {
561            Bound::Unbounded => {
562                let mut iterator = Iterator::new(KeyOnlyIterator::new(self, self.data_offset()))?;
563                iterator.advance().await.context("Unbounded seek advance")?;
564                return Ok(Box::new(iterator));
565            }
566            Bound::Included(k) => (k, false),
567            Bound::Excluded(k) => (k, true),
568        };
569        let first_data_block_index = self.data_offset() / self.block_size;
570
571        let (mut left_offset, mut right_offset) = {
572            // We are searching for a range here, as multiple items can have the same value in
573            // this approximate search. Since the values used are the smallest in the associated
574            // block it means that if the value equals the target you should also search the
575            // one before it. The goal is for table[left] < target < table[right].
576            let target = key.get_leading_u64();
577            // Because the first entry in the table is always 0, right_index will never be 0.
578            let right_index = self.seek_table.as_slice().partition_point(|&x| x <= target) as u64;
579            // Since partition_point will find the index of the first place where the predicate
580            // is false, we subtract 1 to get the index where it was last true.
581            let left_index = self.seek_table.as_slice()[..right_index as usize]
582                .partition_point(|&x| x < target)
583                .saturating_sub(1) as u64;
584
585            (
586                (left_index + first_data_block_index) * self.block_size,
587                (right_index + first_data_block_index) * self.block_size,
588            )
589        };
590        let mut left = KeyOnlyIterator::new(self, left_offset);
591        left.advance().await.context("Initial seek advance")?;
592        match left.get() {
593            None => return Ok(Box::new(Iterator::new(left)?)),
594            Some(left_key) => match left_key.cmp_upper_bound(key) {
595                Ordering::Greater => return Ok(Box::new(Iterator::new(left)?)),
596                Ordering::Equal => {
597                    if excluded {
598                        left.advance().await?;
599                    }
600                    return Ok(Box::new(Iterator::new(left)?));
601                }
602                Ordering::Less => {}
603            },
604        }
605        let mut right = None;
606        while right_offset - left_offset > self.block_size {
607            // Pick a block midway.
608            let mid_offset =
609                round_down(left_offset + (right_offset - left_offset) / 2, self.block_size);
610            let mut iterator = KeyOnlyIterator::new(self, mid_offset);
611            iterator.advance().await?;
612            let iter_key: &K = iterator.get().unwrap();
613            match iter_key.cmp_upper_bound(key) {
614                Ordering::Greater => {
615                    right_offset = mid_offset;
616                    right = Some(iterator);
617                }
618                Ordering::Equal => {
619                    if excluded {
620                        iterator.advance().await?;
621                    }
622                    return Ok(Box::new(Iterator::new(iterator)?));
623                }
624                Ordering::Less => {
625                    left_offset = mid_offset;
626                    left = iterator;
627                }
628            }
629        }
630
631        // Finish the binary search on the block pointed to by `left`.
632        let mut left_index = 0;
633        let mut right_index = left.item_count;
634        // If the size is zero then we don't touch the iterator.
635        while left_index < (right_index - 1) {
636            let mid_index = left_index + ((right_index - left_index) / 2);
637            left.seek_to_block_item(mid_index).context("Read index offset for binary search")?;
638            left.advance().await?;
639            match left.get().unwrap().cmp_upper_bound(key) {
640                Ordering::Greater => {
641                    right_index = mid_index;
642                }
643                Ordering::Equal => {
644                    if excluded {
645                        left.advance().await?;
646                    }
647                    return Ok(Box::new(Iterator::new(left)?));
648                }
649                Ordering::Less => {
650                    left_index = mid_index;
651                }
652            }
653        }
654        // When we don't find an exact match, we need to return with the first entry *after* the the
655        // target key which might be the first one in the next block, currently already pointed to
656        // by the "right" buffer, but usually it's just the result of the right index within the
657        // "left" buffer.
658        if right_index < left.item_count {
659            left.seek_to_block_item(right_index)
660                .context("Read index for offset of right pointer")?;
661        } else if let Some(right) = right {
662            return Ok(Box::new(Iterator::new(right)?));
663        } else {
664            // We want the end of the layer.  `right_index == left.item_count`, so `left_index ==
665            // left.item_count - 1`, and the left iterator must be positioned on `left_index` since
666            // we cannot have gone through the `Ordering::Greater` path above because `right_index`
667            // would not be equal to `left.item_count` in that case, so all we need to do is advance
668            // the iterator.
669        }
670        left.advance().await?;
671        return Ok(Box::new(Iterator::new(left)?));
672    }
673
674    fn len(&self) -> usize {
675        self.num_items
676    }
677
678    fn maybe_contains_key(&self, key: &K) -> bool {
679        self.bloom_filter.as_ref().map_or(true, |f| f.maybe_contains(key))
680    }
681
682    async fn key_exists(&self, key: &K) -> Result<Existence, Error> {
683        match &self.bloom_filter {
684            Some(filter) => Ok(if filter.maybe_contains(key) {
685                Existence::MaybeExists
686            } else {
687                Existence::Missing
688            }),
689            None => {
690                let iter = self.seek(Bound::Included(key)).await?;
691                Ok(iter.get().map_or(Existence::Missing, |i| {
692                    if i.key.cmp_upper_bound(key).is_eq() {
693                        Existence::Exists
694                    } else {
695                        Existence::Missing
696                    }
697                }))
698            }
699        }
700    }
701
702    fn lock(&self) -> Option<Arc<DropEvent>> {
703        self.close_event.lock().clone()
704    }
705
706    async fn close(&self) {
707        let listener = self.close_event.lock().take().expect("close already called").listen();
708        listener.await;
709    }
710
711    fn get_version(&self) -> Version {
712        return self.version;
713    }
714
715    fn record_inspect_data(self: Arc<Self>, node: &fuchsia_inspect::Node) {
716        node.record_uint("num_items", self.num_items as u64);
717        node.record_bool("persistent", true);
718        node.record_uint("size", self.object_handle.get_size());
719        if let Some(stats) = self.bloom_filter_stats.as_ref() {
720            node.record_child("bloom_filter", move |node| {
721                node.record_uint("size", stats.size as u64);
722                node.record_uint("num_hashes", stats.num_hashes as u64);
723                node.record_uint("fill_percentage", stats.fill_percentage as u64);
724            });
725        }
726    }
727}
728
729// This ensures that item_count can't be overflowed below.
730const_assert!(MAX_BLOCK_SIZE <= u16::MAX as u64 + 1);
731
732// -- Writer support --
733
734pub struct PersistentLayerWriter<W: WriteBytes, K: Key, V: LayerValue> {
735    writer: W,
736    block_size: u64,
737    buf: Vec<u8>,
738    buf_item_count: LayerWriterBufItemCount,
739    item_count: usize,
740    block_offsets: Vec<u16>,
741    block_keys: Vec<u64>,
742    bloom_filter: BloomFilterWriter<K>,
743    _value: PhantomData<V>,
744}
745
746impl<W: WriteBytes, K: Key, V: LayerValue> PersistentLayerWriter<W, K, V> {
747    /// Creates a new writer that will serialize items to the object accessible via |object_handle|
748    pub async fn new(writer: W, num_items: usize, block_size: u64) -> Result<Self, Error> {
749        Self::new_with_version(writer, num_items, block_size, LATEST_VERSION).await
750    }
751
752    pub(crate) async fn new_with_version(
753        mut writer: W,
754        num_items: usize,
755        block_size: u64,
756        version: Version,
757    ) -> Result<Self, Error> {
758        ensure!(block_size <= MAX_BLOCK_SIZE, FxfsError::NotSupported);
759        ensure!(block_size >= MIN_BLOCK_SIZE, FxfsError::NotSupported);
760
761        // Write the header block.
762        let header = LayerHeader { magic: PERSISTENT_LAYER_MAGIC.clone(), block_size };
763        let mut buf = vec![0u8; block_size as usize];
764        {
765            let mut cursor = std::io::Cursor::new(&mut buf[..]);
766            version.serialize_into(&mut cursor)?;
767            header.serialize_into(&mut cursor)?;
768        }
769        writer.write_bytes(&buf[..]).await?;
770
771        let seed: u64 = rand::random();
772        Ok(Self {
773            writer,
774            block_size,
775            buf: Vec::new(),
776            buf_item_count: LayerWriterBufItemCount(0),
777            item_count: 0,
778            block_offsets: Vec::new(),
779            block_keys: Vec::new(),
780            bloom_filter: BloomFilterWriter::new(seed, num_items),
781            _value: PhantomData,
782        })
783    }
784
785    /// Writes 'buf[..len]' out as a block.
786    ///
787    /// Blocks are fixed size, consisting of a 16-bit item count, data, zero padding
788    /// and seek table at the end.
789    async fn write_block(&mut self, len: usize) -> Result<(), Error> {
790        if *self.buf_item_count == 0 {
791            return Ok(());
792        }
793        let seek_table_size = self.block_offsets.len() * PER_DATA_BLOCK_SEEK_ENTRY_SIZE;
794        assert!(PER_DATA_BLOCK_HEADER_SIZE + seek_table_size + len <= self.block_size as usize);
795        let mut cursor = std::io::Cursor::new(vec![0u8; self.block_size as usize]);
796        cursor.write_u16::<LittleEndian>(*self.buf_item_count)?;
797        cursor.write_all(self.buf.drain(..len).as_ref())?;
798        cursor.set_position(self.block_size - seek_table_size as u64);
799        // Write the seek table. Entries are 2 bytes each and items are always at least 10.
800        for &offset in &self.block_offsets {
801            cursor.write_u16::<LittleEndian>(offset)?;
802        }
803        self.writer.write_bytes(cursor.get_ref()).await?;
804        debug!(item_count = *self.buf_item_count, byte_count = len; "wrote items");
805        *self.buf_item_count = 0;
806        self.block_offsets.clear();
807        Ok(())
808    }
809
810    // Assumes the writer is positioned to a new block.
811    // Returns the size, in bytes, of the seek table.
812    // Note that the writer will be positioned to exactly the end of the seek table, not to the end
813    // of a block.
814    async fn write_seek_table(&mut self) -> Result<usize, Error> {
815        if self.block_keys.len() == 0 {
816            return Ok(0);
817        }
818        let size = self.block_keys.len() * std::mem::size_of::<u64>();
819        self.buf.resize(size, 0);
820        let mut len = 0;
821        for key in &self.block_keys {
822            LittleEndian::write_u64(&mut self.buf[len..len + std::mem::size_of::<u64>()], *key);
823            len += std::mem::size_of::<u64>();
824        }
825        self.writer.write_bytes(&self.buf).await?;
826        Ok(size)
827    }
828
829    // Assumes the writer is positioned to exactly the end of the seek table, which was
830    // `seek_table_len` bytes.
831    async fn write_info(
832        &mut self,
833        num_data_blocks: u64,
834        bloom_filter_size_bytes: usize,
835        seek_table_len: usize,
836    ) -> Result<(), Error> {
837        let block_size = self.writer.block_size() as usize;
838        let layer_info = LayerInfo {
839            num_items: self.item_count,
840            num_data_blocks,
841            bloom_filter_size_bytes,
842            bloom_filter_seed: self.bloom_filter.seed(),
843            bloom_filter_num_hashes: self.bloom_filter.num_hashes(),
844        };
845        let actual_len = {
846            let mut cursor = std::io::Cursor::new(&mut self.buf);
847            layer_info.serialize_into(&mut cursor)?;
848            let layer_info_len = cursor.position();
849            cursor.write_u64::<LittleEndian>(layer_info_len)?;
850            cursor.position() as usize
851        };
852
853        // We want the LayerInfo to be at the end of the last block.  That might require creating a
854        // new block if we don't have enough room.
855        let avail_in_block = block_size - (seek_table_len % block_size);
856        let to_skip = if avail_in_block < actual_len {
857            block_size + avail_in_block - actual_len
858        } else {
859            avail_in_block - actual_len
860        } as u64;
861        self.writer.skip(to_skip).await?;
862        self.writer.write_bytes(&self.buf[..actual_len]).await?;
863        Ok(())
864    }
865
866    // Assumes the writer is positioned to a new block.
867    // Returns the size of the bloom filter, in bytes.
868    async fn write_bloom_filter(&mut self) -> Result<usize, Error> {
869        if self.data_blocks() < MINIMUM_DATA_BLOCKS_FOR_BLOOM_FILTER {
870            return Ok(0);
871        }
872        // TODO(https://fxbug.dev/323571978): Avoid bounce-buffering.
873        let size = round_up(self.bloom_filter.serialized_size(), self.block_size as usize).unwrap();
874        self.buf.resize(size, 0);
875        let mut cursor = std::io::Cursor::new(&mut self.buf);
876        self.bloom_filter.write(&mut cursor)?;
877        self.writer.write_bytes(&self.buf).await?;
878        Ok(self.bloom_filter.serialized_size())
879    }
880
881    // Returns the bloom filter writer. Intended to be used for testing purposes, e.g., gain access
882    // to the bloom filter to then corrupt it.
883    #[cfg(test)]
884    pub(crate) fn bloom_filter(&mut self) -> &mut BloomFilterWriter<K> {
885        &mut self.bloom_filter
886    }
887
888    fn data_blocks(&self) -> usize {
889        if self.item_count == 0 { 0 } else { self.block_keys.len() + 1 }
890    }
891}
892
893impl<W: WriteBytes + Send, K: Key, V: LayerValue> LayerWriter<K, V>
894    for PersistentLayerWriter<W, K, V>
895{
896    async fn write(&mut self, item: ItemRef<'_, K, V>) -> Result<(), Error> {
897        // Note the length before we write this item.
898        let len = self.buf.len();
899        item.key.serialize_into(&mut self.buf)?;
900        item.value.serialize_into(&mut self.buf)?;
901
902        let mut added_offset = false;
903        // Never record the first item. The offset is always the same.
904        if *self.buf_item_count > 0 {
905            self.block_offsets.push(u16::try_from(len + PER_DATA_BLOCK_HEADER_SIZE).unwrap());
906            added_offset = true;
907        }
908
909        // If writing the item took us over a block, flush the bytes in the buffer prior to this
910        // item.
911        if PER_DATA_BLOCK_HEADER_SIZE
912            + self.buf.len()
913            + (self.block_offsets.len() * PER_DATA_BLOCK_SEEK_ENTRY_SIZE)
914            > self.block_size as usize - 1
915        {
916            if added_offset {
917                // Drop the recently added offset from the list. The latest item will be the first
918                // on the next block and have a known offset there.
919                self.block_offsets.pop();
920            }
921            self.write_block(len).await?;
922
923            // Note that this will not insert an entry for the first data block.
924            self.block_keys.push(item.key.get_leading_u64());
925        }
926
927        self.bloom_filter.insert(&item.key);
928        *self.buf_item_count += 1;
929        self.item_count += 1;
930        Ok(())
931    }
932
933    async fn complete(mut self) -> Result<u64, Error> {
934        self.write_block(self.buf.len()).await?;
935        let data_blocks = self.data_blocks() as u64;
936        let bloom_filter_len = self.write_bloom_filter().await?;
937        let seek_table_len = self.write_seek_table().await?;
938        self.write_info(data_blocks, bloom_filter_len, seek_table_len).await?;
939        self.writer.complete().await
940    }
941}
942
943/// Logs a warning if this object is dropped and the contained value isn't 0.
944#[repr(transparent)]
945struct LayerWriterBufItemCount(u16);
946
947impl Drop for LayerWriterBufItemCount {
948    fn drop(&mut self) {
949        debug_assert!(self.0 == 0, "Dropping unwritten items; did you forget to call complete?");
950        if self.0 > 0 {
951            warn!("Dropping unwritten items; did you forget to call complete?");
952        }
953    }
954}
955
956impl std::ops::Deref for LayerWriterBufItemCount {
957    type Target = u16;
958    fn deref(&self) -> &u16 {
959        &self.0
960    }
961}
962
963impl std::ops::DerefMut for LayerWriterBufItemCount {
964    fn deref_mut(&mut self) -> &mut u16 {
965        &mut self.0
966    }
967}
968
969#[cfg(test)]
970mod tests {
971    use super::{PersistentLayer, PersistentLayerWriter};
972    use crate::filesystem::MAX_BLOCK_SIZE;
973    use crate::lsm_tree::LayerIterator;
974    use crate::lsm_tree::persistent_layer::MINIMUM_DATA_BLOCKS_FOR_BLOOM_FILTER;
975    use crate::lsm_tree::types::{Existence, Item, ItemRef, Layer, LayerWriter, OrdUpperBound};
976    use crate::object_handle::WriteBytes;
977    use crate::object_store::AttributeId;
978    use crate::object_store::object_record::ObjectKey;
979    use crate::round::round_up;
980    use crate::serialized_types::{LATEST_VERSION, Version};
981    use crate::testing::fake_object::{FakeObject, FakeObjectHandle};
982    use crate::testing::writer::Writer;
983
984    use std::fmt::Debug;
985
986    use std::ops::{Bound, Range};
987    use std::sync::Arc;
988
989    impl<W: WriteBytes> Debug for PersistentLayerWriter<W, i32, i32> {
990        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
991            f.debug_struct("rPersistentLayerWriter")
992                .field("block_size", &self.block_size)
993                .field("item_count", &*self.buf_item_count)
994                .finish()
995        }
996    }
997
998    #[fuchsia::test]
999    async fn test_iterate_after_write() {
1000        const BLOCK_SIZE: u64 = 512;
1001        const ITEM_COUNT: i32 = 10000;
1002
1003        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1004        {
1005            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1006                Writer::new(&handle).await,
1007                ITEM_COUNT as usize * 4,
1008                BLOCK_SIZE,
1009            )
1010            .await
1011            .expect("writer new");
1012            for i in 0..ITEM_COUNT {
1013                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
1014            }
1015            writer.complete().await.expect("flush failed");
1016        }
1017        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1018        let mut iterator = layer.seek(Bound::Unbounded).await.expect("seek failed");
1019        for i in 0..ITEM_COUNT {
1020            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1021            assert_eq!((key, value), (&i, &i));
1022            iterator.advance().await.expect("failed to advance");
1023        }
1024        assert!(iterator.get().is_none());
1025    }
1026
1027    #[fuchsia::test]
1028    async fn test_seek_after_write() {
1029        const BLOCK_SIZE: u64 = 512;
1030        const ITEM_COUNT: i32 = 5000;
1031
1032        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1033        {
1034            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1035                Writer::new(&handle).await,
1036                ITEM_COUNT as usize * 18,
1037                BLOCK_SIZE,
1038            )
1039            .await
1040            .expect("writer new");
1041            for i in 0..ITEM_COUNT {
1042                // Populate every other value as an item.
1043                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
1044            }
1045            writer.complete().await.expect("flush failed");
1046        }
1047        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1048        // Search for all values to check the in-between values.
1049        for i in 0..ITEM_COUNT * 2 {
1050            // We've written every other value, we expect to get either the exact value searched
1051            // for, or the next one after it. So round up to the nearest multiple of 2.
1052            let expected = round_up(i, 2).unwrap();
1053            let mut iterator = layer.seek(Bound::Included(&i)).await.expect("failed to seek");
1054            // We've written values up to (N-1)*2=2*N-2, so when looking for 2*N-1 we'll go off the
1055            // end of the layer and get back no item.
1056            if i >= (ITEM_COUNT * 2) - 1 {
1057                assert!(iterator.get().is_none());
1058            } else {
1059                let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1060                assert_eq!((key, value), (&expected, &expected));
1061            }
1062
1063            // Check that we can advance to the next item.
1064            iterator.advance().await.expect("failed to advance");
1065            // The highest value is 2*N-2, searching for 2*N-3 will find the last value, and
1066            // advancing will go off the end of the layer and return no item. If there was
1067            // previously no item, then it will latch and always return no item.
1068            if i >= (ITEM_COUNT * 2) - 3 {
1069                assert!(iterator.get().is_none());
1070            } else {
1071                let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1072                let next = expected + 2;
1073                assert_eq!((key, value), (&next, &next));
1074            }
1075        }
1076    }
1077
1078    #[fuchsia::test]
1079    async fn test_seek_unbounded() {
1080        const BLOCK_SIZE: u64 = 512;
1081        const ITEM_COUNT: i32 = 1000;
1082
1083        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1084        {
1085            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1086                Writer::new(&handle).await,
1087                ITEM_COUNT as usize * 18,
1088                BLOCK_SIZE,
1089            )
1090            .await
1091            .expect("writer new");
1092            for i in 0..ITEM_COUNT {
1093                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
1094            }
1095            writer.complete().await.expect("flush failed");
1096        }
1097        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1098        let mut iterator = layer.seek(Bound::Unbounded).await.expect("failed to seek");
1099        let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1100        assert_eq!((key, value), (&0, &0));
1101
1102        // Check that we can advance to the next item.
1103        iterator.advance().await.expect("failed to advance");
1104        let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1105        assert_eq!((key, value), (&1, &1));
1106    }
1107
1108    #[fuchsia::test]
1109    async fn test_zero_items() {
1110        const BLOCK_SIZE: u64 = 512;
1111
1112        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1113        {
1114            let writer = PersistentLayerWriter::<_, i32, i32>::new(
1115                Writer::new(&handle).await,
1116                0,
1117                BLOCK_SIZE,
1118            )
1119            .await
1120            .expect("writer new");
1121            writer.complete().await.expect("flush failed");
1122        }
1123
1124        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1125        let iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1126            .seek(Bound::Unbounded)
1127            .await
1128            .expect("seek failed");
1129        assert!(iterator.get().is_none())
1130    }
1131
1132    #[fuchsia::test]
1133    async fn test_one_item() {
1134        const BLOCK_SIZE: u64 = 512;
1135
1136        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1137        {
1138            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1139                Writer::new(&handle).await,
1140                1,
1141                BLOCK_SIZE,
1142            )
1143            .await
1144            .expect("writer new");
1145            writer.write(Item::new(42, 42).as_item_ref()).await.expect("write failed");
1146            writer.complete().await.expect("flush failed");
1147        }
1148
1149        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1150        {
1151            let mut iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1152                .seek(Bound::Unbounded)
1153                .await
1154                .expect("seek failed");
1155            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1156            assert_eq!((key, value), (&42, &42));
1157            iterator.advance().await.expect("failed to advance");
1158            assert!(iterator.get().is_none())
1159        }
1160        {
1161            let mut iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1162                .seek(Bound::Included(&30))
1163                .await
1164                .expect("seek failed");
1165            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1166            assert_eq!((key, value), (&42, &42));
1167            iterator.advance().await.expect("failed to advance");
1168            assert!(iterator.get().is_none())
1169        }
1170        {
1171            let mut iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1172                .seek(Bound::Included(&42))
1173                .await
1174                .expect("seek failed");
1175            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1176            assert_eq!((key, value), (&42, &42));
1177            iterator.advance().await.expect("failed to advance");
1178            assert!(iterator.get().is_none())
1179        }
1180        {
1181            let iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1182                .seek(Bound::Included(&43))
1183                .await
1184                .expect("seek failed");
1185            assert!(iterator.get().is_none())
1186        }
1187    }
1188
1189    #[fuchsia::test]
1190    async fn test_large_block_size() {
1191        // At the upper end of the supported size.
1192        const BLOCK_SIZE: u64 = MAX_BLOCK_SIZE;
1193        // Items will be 18 bytes, so fill up a few pages.
1194        const ITEM_COUNT: i32 = ((BLOCK_SIZE as i32) / 18) * 3;
1195
1196        let handle =
1197            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE as usize);
1198        {
1199            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1200                Writer::new(&handle).await,
1201                ITEM_COUNT as usize * 18,
1202                BLOCK_SIZE,
1203            )
1204            .await
1205            .expect("writer new");
1206            // Use large values to force varint encoding to use consistent space.
1207            for i in 2000000000..(2000000000 + ITEM_COUNT) {
1208                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
1209            }
1210            writer.complete().await.expect("flush failed");
1211        }
1212
1213        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1214        let mut iterator = layer.seek(Bound::Unbounded).await.expect("seek failed");
1215        for i in 2000000000..(2000000000 + ITEM_COUNT) {
1216            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1217            assert_eq!((key, value), (&i, &i));
1218            iterator.advance().await.expect("failed to advance");
1219        }
1220        assert!(iterator.get().is_none());
1221    }
1222
1223    #[fuchsia::test]
1224    async fn test_overlarge_block_size() {
1225        // At the upper end of the supported size.
1226        const BLOCK_SIZE: u64 = MAX_BLOCK_SIZE * 2;
1227
1228        let handle =
1229            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE as usize);
1230        PersistentLayerWriter::<_, i32, i32>::new(Writer::new(&handle).await, 0, BLOCK_SIZE)
1231            .await
1232            .expect_err("Creating writer with overlarge block size.");
1233    }
1234
1235    #[fuchsia::test]
1236    async fn test_seek_bound_excluded() {
1237        const BLOCK_SIZE: u64 = 512;
1238        const ITEM_COUNT: i32 = 10000;
1239
1240        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1241        {
1242            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1243                Writer::new(&handle).await,
1244                ITEM_COUNT as usize * 18,
1245                BLOCK_SIZE,
1246            )
1247            .await
1248            .expect("writer new");
1249            for i in 0..ITEM_COUNT {
1250                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
1251            }
1252            writer.complete().await.expect("flush failed");
1253        }
1254        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1255
1256        for i in 9982..ITEM_COUNT {
1257            let mut iterator = layer.seek(Bound::Excluded(&i)).await.expect("failed to seek");
1258            let i_plus_one = i + 1;
1259            if i_plus_one < ITEM_COUNT {
1260                let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1261
1262                assert_eq!((key, value), (&i_plus_one, &i_plus_one));
1263
1264                // Check that we can advance to the next item.
1265                iterator.advance().await.expect("failed to advance");
1266                let i_plus_two = i + 2;
1267                if i_plus_two < ITEM_COUNT {
1268                    let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1269                    assert_eq!((key, value), (&i_plus_two, &i_plus_two));
1270                } else {
1271                    assert!(iterator.get().is_none());
1272                }
1273            } else {
1274                assert!(iterator.get().is_none());
1275            }
1276        }
1277    }
1278
1279    use crate::lsm_tree::testing::TestKey;
1280
1281    /// Generates extent records for a given object_id (of size 1).
1282    /// This produces a series of records with the same leading_u64.
1283    /// Returns the generated items and the next available object_id.
1284    fn generate_extents(
1285        object_id: u64,
1286        base_offset: u64,
1287        count: u64,
1288    ) -> (Vec<Item<ObjectKey, u64>>, u64) {
1289        let mut items = Vec::new();
1290        for i in 0..count {
1291            items.push(Item::new(
1292                ObjectKey::extent(
1293                    object_id,
1294                    AttributeId::TEST_ID,
1295                    base_offset + i..base_offset + i + 1,
1296                ),
1297                object_id,
1298            ));
1299        }
1300        (items, object_id + 1)
1301    }
1302
1303    /// Generates objects object_ids over a range.
1304    /// This produced a series of records with unique leading_u64.
1305    /// Returns the generated items and the next available value for sequencing.
1306    fn generate_objects(object_id_range: Range<u64>) -> (Vec<Item<ObjectKey, u64>>, u64) {
1307        let mut items = Vec::new();
1308        let end = object_id_range.end;
1309        for object_id in object_id_range {
1310            items.push(Item::new(ObjectKey::object(object_id), object_id));
1311        }
1312        (items, end)
1313    }
1314
1315    // Create a large spread of data across several blocks to ensure that no part of the range is
1316    // lost by the partial search using the layer seek table.
1317    #[fuchsia::test]
1318    async fn test_block_seek_duplicate_leading_u64() {
1319        // At the upper end of the supported size.
1320        const BLOCK_SIZE: u64 = 512;
1321        const ITEMS_PER_PHASE: u64 = 50;
1322
1323        let mut to_find = Vec::new();
1324
1325        let handle =
1326            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE as usize);
1327        {
1328            let mut items = Vec::new();
1329            // Make all values take up maximum space for varint encoding.
1330            let mut object_id = u32::MAX as u64 + 1;
1331
1332            // First fill the front with duplicate object IDs, then look at the start,
1333            // middle and end of the range.
1334            {
1335                let base_extent_offset = 0;
1336                let (mut generated, next_object_id) =
1337                    generate_extents(object_id, base_extent_offset, ITEMS_PER_PHASE * 3);
1338                items.append(&mut generated);
1339                let count = ITEMS_PER_PHASE * 3;
1340                to_find.push(ObjectKey::extent(
1341                    object_id,
1342                    AttributeId::TEST_ID,
1343                    base_extent_offset..base_extent_offset + 1,
1344                ));
1345                to_find.push(ObjectKey::extent(
1346                    object_id,
1347                    AttributeId::TEST_ID,
1348                    base_extent_offset + (count / 2)..base_extent_offset + (count / 2) + 1,
1349                ));
1350                to_find.push(ObjectKey::extent(
1351                    object_id,
1352                    AttributeId::TEST_ID,
1353                    base_extent_offset + (count - 1)..base_extent_offset + count,
1354                ));
1355                object_id = next_object_id;
1356            }
1357
1358            // Add some filler of all different leading u64.
1359            {
1360                let (mut generated, next_object_id) =
1361                    generate_objects(object_id..object_id + ITEMS_PER_PHASE * 3);
1362                items.append(&mut generated);
1363                object_id = next_object_id;
1364            }
1365
1366            // Fill the middle with duplicate object IDs, then look at the start,
1367            // middle and end of the range.
1368            {
1369                let base_extent_offset = 1000;
1370                let (mut generated, next_object_id) =
1371                    generate_extents(object_id, base_extent_offset, ITEMS_PER_PHASE * 3);
1372                items.append(&mut generated);
1373                let count = ITEMS_PER_PHASE * 3;
1374                to_find.push(ObjectKey::extent(
1375                    object_id,
1376                    AttributeId::TEST_ID,
1377                    base_extent_offset..base_extent_offset + 1,
1378                ));
1379                to_find.push(ObjectKey::extent(
1380                    object_id,
1381                    AttributeId::TEST_ID,
1382                    base_extent_offset + (count / 2)..base_extent_offset + (count / 2) + 1,
1383                ));
1384                to_find.push(ObjectKey::extent(
1385                    object_id,
1386                    AttributeId::TEST_ID,
1387                    base_extent_offset + (count - 1)..base_extent_offset + count,
1388                ));
1389                object_id = next_object_id;
1390            }
1391
1392            // Add some filler of all different leading u64.
1393            {
1394                let (mut generated, next_object_id) =
1395                    generate_objects(object_id..object_id + ITEMS_PER_PHASE * 3);
1396                items.append(&mut generated);
1397                object_id = next_object_id;
1398            }
1399
1400            // Fill the end with duplicate object IDs, then look at the start,
1401            // middle and end of the range.
1402            {
1403                let base_extent_offset = 2000;
1404                let (mut generated, _) =
1405                    generate_extents(object_id, base_extent_offset, ITEMS_PER_PHASE * 3);
1406                items.append(&mut generated);
1407                let count = ITEMS_PER_PHASE * 3;
1408                to_find.push(ObjectKey::extent(
1409                    object_id,
1410                    AttributeId::TEST_ID,
1411                    base_extent_offset..base_extent_offset + 1,
1412                ));
1413                to_find.push(ObjectKey::extent(
1414                    object_id,
1415                    AttributeId::TEST_ID,
1416                    base_extent_offset + (count / 2)..base_extent_offset + (count / 2) + 1,
1417                ));
1418                to_find.push(ObjectKey::extent(
1419                    object_id,
1420                    AttributeId::TEST_ID,
1421                    base_extent_offset + (count - 1)..base_extent_offset + count,
1422                ));
1423            }
1424
1425            // Sort items by cmp_upper_bound!
1426            items.sort_by(|a, b| a.key.cmp_upper_bound(&b.key));
1427
1428            let mut writer = PersistentLayerWriter::<_, ObjectKey, u64>::new(
1429                Writer::new(&handle).await,
1430                3 * BLOCK_SIZE as usize,
1431                BLOCK_SIZE,
1432            )
1433            .await
1434            .expect("writer new");
1435
1436            for item in items {
1437                writer.write(item.as_item_ref()).await.expect("write failed");
1438            }
1439
1440            writer.complete().await.expect("flush failed");
1441        }
1442
1443        let layer = PersistentLayer::<ObjectKey, u64>::open(handle).await.expect("new failed");
1444        for target in to_find {
1445            let iterator: Box<dyn LayerIterator<ObjectKey, u64>> =
1446                layer.seek(Bound::Included(&target)).await.expect("failed to seek");
1447            let ItemRef { key, .. } = iterator.get().expect("missing item");
1448            assert_eq!(&target, key);
1449        }
1450    }
1451
1452    #[fuchsia::test]
1453    async fn test_two_seek_blocks() {
1454        // At the upper end of the supported size.
1455        const BLOCK_SIZE: u64 = 512;
1456        const ITEMS_PER_PHASE: u64 = 50;
1457        const ITEM_COUNT: u64 = ITEMS_PER_PHASE * ((BLOCK_SIZE / 8) + 2);
1458
1459        let mut to_find = Vec::new();
1460
1461        let handle =
1462            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE as usize);
1463        {
1464            let mut writer = PersistentLayerWriter::<_, TestKey, u64>::new(
1465                Writer::new(&handle).await,
1466                ITEM_COUNT as usize * 18,
1467                BLOCK_SIZE,
1468            )
1469            .await
1470            .expect("writer new");
1471
1472            // Make all values take up maximum space for varint encoding.
1473            let initial_value = u32::MAX as u64 + 1;
1474            for i in 0..ITEM_COUNT {
1475                writer
1476                    .write(
1477                        Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
1478                            .as_item_ref(),
1479                    )
1480                    .await
1481                    .expect("write failed");
1482            }
1483            // Look at the start middle and end.
1484            to_find.push(TestKey(initial_value..initial_value));
1485            let middle = initial_value + ITEM_COUNT / 2;
1486            to_find.push(TestKey(middle..middle));
1487            let end = initial_value + ITEM_COUNT - 1;
1488            to_find.push(TestKey(end..end));
1489
1490            writer.complete().await.expect("flush failed");
1491        }
1492
1493        let layer = PersistentLayer::<TestKey, u64>::open(handle).await.expect("new failed");
1494        for target in to_find {
1495            let iterator: Box<dyn LayerIterator<TestKey, u64>> =
1496                layer.seek(Bound::Included(&target)).await.expect("failed to seek");
1497            let ItemRef { key, .. } = iterator.get().expect("missing item");
1498            assert_eq!(&target, key);
1499        }
1500    }
1501
1502    // Verifies behaviour around creating full seek blocks, to ensure that it is able to be opened
1503    // and parsed afterward.
1504    #[fuchsia::test]
1505    async fn test_full_seek_block() {
1506        const BLOCK_SIZE: u64 = 512;
1507        const ITEMS_PER_PHASE: u64 = 50;
1508
1509        // How many entries there are in a seek table block.
1510        const SEEK_TABLE_ENTRIES: u64 = BLOCK_SIZE / 8;
1511
1512        // Number of entries to fill a seek block would need one more block of entries, but we're
1513        // starting low here on purpose to do a range and make sure we hit the size we are
1514        // interested in.
1515        const START_ENTRIES_COUNT: u64 = ITEMS_PER_PHASE * SEEK_TABLE_ENTRIES;
1516
1517        for entries in START_ENTRIES_COUNT..START_ENTRIES_COUNT + (ITEMS_PER_PHASE * 2) {
1518            let handle = FakeObjectHandle::new_with_block_size(
1519                Arc::new(FakeObject::new()),
1520                BLOCK_SIZE as usize,
1521            );
1522            {
1523                let mut writer = PersistentLayerWriter::<_, TestKey, u64>::new(
1524                    Writer::new(&handle).await,
1525                    entries as usize,
1526                    BLOCK_SIZE,
1527                )
1528                .await
1529                .expect("writer new");
1530
1531                // Make all values take up maximum space for varint encoding.
1532                let initial_value = u32::MAX as u64 + 1;
1533                for i in 0..entries {
1534                    writer
1535                        .write(
1536                            Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
1537                                .as_item_ref(),
1538                        )
1539                        .await
1540                        .expect("write failed");
1541                }
1542
1543                writer.complete().await.expect("flush failed");
1544            }
1545            PersistentLayer::<TestKey, u64>::open(handle).await.expect("new failed");
1546        }
1547    }
1548
1549    #[fuchsia::test]
1550    async fn test_ignore_bloom_filter_on_older_versions() {
1551        const BLOCK_SIZE: u64 = 512;
1552        const ITEMS_PER_PHASE: u64 = 50;
1553        // Add enough items to create enough blocks for a bloom filter to be necessary.
1554        const ITEM_COUNT: u64 = (1 + MINIMUM_DATA_BLOCKS_FOR_BLOOM_FILTER as u64) * ITEMS_PER_PHASE;
1555
1556        let old_version_handle =
1557            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE as usize);
1558        let current_version_handle =
1559            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE as usize);
1560        {
1561            let mut old_version_writer =
1562                PersistentLayerWriter::<_, TestKey, u64>::new_with_version(
1563                    Writer::new(&old_version_handle).await,
1564                    ITEM_COUNT as usize,
1565                    BLOCK_SIZE,
1566                    Version { major: LATEST_VERSION.major - 1, minor: 0 },
1567                )
1568                .await
1569                .expect("writer new");
1570            let mut current_version_writer = PersistentLayerWriter::<_, TestKey, u64>::new(
1571                Writer::new(&current_version_handle).await,
1572                ITEM_COUNT as usize,
1573                BLOCK_SIZE,
1574            )
1575            .await
1576            .expect("writer new");
1577
1578            // Make all values take up maximum space for varint encoding.
1579            let initial_value = u32::MAX as u64 + 1;
1580            for i in 0..ITEM_COUNT {
1581                old_version_writer
1582                    .write(
1583                        Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
1584                            .as_item_ref(),
1585                    )
1586                    .await
1587                    .expect("write failed");
1588                current_version_writer
1589                    .write(
1590                        Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
1591                            .as_item_ref(),
1592                    )
1593                    .await
1594                    .expect("write failed");
1595            }
1596
1597            old_version_writer.complete().await.expect("flush failed");
1598            current_version_writer.complete().await.expect("flush failed");
1599        }
1600
1601        let old_layer =
1602            PersistentLayer::<TestKey, u64>::open(old_version_handle).await.expect("open failed");
1603        let current_layer = PersistentLayer::<TestKey, u64>::open(current_version_handle)
1604            .await
1605            .expect("open failed");
1606        assert!(!old_layer.has_bloom_filter());
1607        assert!(current_layer.has_bloom_filter());
1608    }
1609
1610    #[fuchsia::test]
1611    async fn test_key_exists_no_bloom_filter() {
1612        const BLOCK_SIZE: u64 = 8192;
1613        // Not enough items to trigger a bloom filter.
1614        const ITEM_COUNT: i32 = 100;
1615
1616        let handle =
1617            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE as usize);
1618        {
1619            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1620                Writer::new(&handle).await,
1621                ITEM_COUNT as usize,
1622                BLOCK_SIZE,
1623            )
1624            .await
1625            .expect("writer new");
1626            for i in 0..ITEM_COUNT {
1627                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
1628            }
1629            writer.complete().await.expect("flush failed");
1630        }
1631        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1632        assert!(!layer.has_bloom_filter());
1633
1634        for i in 0..ITEM_COUNT {
1635            assert_eq!(
1636                layer.key_exists(&(i * 2)).await.expect("key_exists failed"),
1637                Existence::Exists
1638            );
1639            assert_eq!(
1640                layer.key_exists(&(i * 2 + 1)).await.expect("key_exists failed"),
1641                Existence::Missing
1642            );
1643        }
1644    }
1645
1646    #[fuchsia::test]
1647    async fn test_key_exists_with_bloom_filter() {
1648        const BLOCK_SIZE: u64 = 512;
1649        // Enough items to trigger a bloom filter.
1650        const ITEM_COUNT: i32 = 10000;
1651
1652        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1653        {
1654            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1655                Writer::new(&handle).await,
1656                ITEM_COUNT as usize,
1657                BLOCK_SIZE,
1658            )
1659            .await
1660            .expect("writer new");
1661            for i in 0..ITEM_COUNT {
1662                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
1663            }
1664            writer.complete().await.expect("flush failed");
1665        }
1666        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1667        assert!(layer.has_bloom_filter());
1668
1669        for i in 0..ITEM_COUNT {
1670            // With a bloom filter, we expect MaybeExists for present keys.
1671            assert_eq!(
1672                layer.key_exists(&(i * 2)).await.expect("key_exists failed"),
1673                Existence::MaybeExists
1674            );
1675        }
1676
1677        // For missing keys, we expect Missing, but might get MaybeExists due to false positives.
1678        // We can at least assert it's NOT Exists.
1679        let mut missing_count = 0;
1680        for i in 0..ITEM_COUNT {
1681            let result = layer.key_exists(&(i * 2 + 1)).await.expect("key_exists failed");
1682            assert_ne!(result, Existence::Exists);
1683            if result == Existence::Missing {
1684                missing_count += 1;
1685            }
1686        }
1687        // We expect mostly Missing.
1688        assert!(missing_count > ITEM_COUNT / 2);
1689    }
1690}