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 if the layer is empty.
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 contains a little-endian u64 for each data block, recording the leading u64 of
55// that block's first key. Entries are in sorted order (duplicates are possible when an object
56// spans multiple blocks).
57
58use crate::drop_event::DropEvent;
59use crate::errors::FxfsError;
60use crate::filesystem::MAX_BLOCK_SIZE;
61use crate::log::*;
62use crate::lsm_tree::bloom_filter::{BloomFilterReader, BloomFilterStats, BloomFilterWriter};
63use crate::lsm_tree::types::{
64    BoxedLayerIterator, Existence, FuzzyHash, Item, ItemRef, Key, Layer, LayerIterator, LayerValue,
65    LayerWriter, MaybeContainsKey,
66};
67use crate::object_handle::{LayerObject, ObjectHandle, ReadObjectHandle, WriteBytes};
68use crate::object_store::caching_object_handle::{CHUNK_SIZE, CachedChunk, CachingObjectHandle};
69use crate::object_store::extent::MIN_BLOCK_SIZE;
70use crate::object_store::{DataObjectHandle, HandleOptions, ObjectStore};
71use crate::serialized_types::serialized_key::{KeyDeserializer, compare_keys};
72use crate::serialized_types::{
73    LATEST_VERSION, OLD_KEY_SERIALIZATION_VERSION, Version, Versioned, VersionedLatest,
74};
75use anyhow::{Context, Error, anyhow, ensure};
76use async_trait::async_trait;
77use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
78use fprint::TypeFingerprint;
79use fuchsia_sync::Mutex;
80use futures::future::BoxFuture;
81use futures::stream::{FuturesUnordered, TryStreamExt};
82use fxfs_crypto::{Crypt, UnwrappedKey, WrappedKey};
83use serde::{Deserialize, Serialize};
84use static_assertions::const_assert;
85use std::cmp::Ordering;
86use std::io::{Read as _, Write as _};
87use std::marker::PhantomData;
88use std::ops::Bound;
89use std::sync::Arc;
90use storage_ptr_slice::PtrByteSlice;
91use storage_units::BlockSize;
92
93const PERSISTENT_LAYER_MAGIC: &[u8; 8] = b"FxfsLayr";
94
95/// LayerHeader is stored in the first block of the persistent layer.
96pub type LayerHeader = LayerHeaderV39;
97
98#[derive(Debug, Serialize, Deserialize, TypeFingerprint, Versioned)]
99pub struct LayerHeaderV39 {
100    /// 'FxfsLayr'
101    magic: [u8; 8],
102    /// The block size used within this layer file. This is typically set at compaction time to the
103    /// same block size as the underlying object handle.
104    ///
105    /// (Each block starts with a 2 byte item count so there is a 64k item limit per block,
106    /// regardless of block size).
107    block_size: u64,
108}
109
110/// The last block of each layer contains metadata for the rest of the layer.
111pub type LayerInfo = LayerInfoV39;
112
113#[derive(Debug, Serialize, Deserialize, TypeFingerprint, Versioned)]
114pub struct LayerInfoV39 {
115    /// How many items are in the layer file.  Mainly used for sizing bloom filters during
116    /// compaction.
117    num_items: usize,
118    /// The number of data blocks in the layer file.
119    num_data_blocks: u64,
120    /// The size of the bloom filter in the layer file.  Not necessarily block-aligned.
121    bloom_filter_size_bytes: usize,
122    /// The seed for the nonces used in the bloom filter.
123    bloom_filter_seed: u64,
124    /// How many nonces to use for bloom filter hashing.
125    bloom_filter_num_hashes: usize,
126}
127
128struct LayerData<K> {
129    object_id: u64,
130    version: Version,
131    block_size: BlockSize,
132    data_size: u64,
133    seek_table: Vec<u64>,
134    num_items: usize,
135    bloom_filter: Option<BloomFilterReader<K>>,
136    bloom_filter_stats: Option<BloomFilterStats>,
137    close_event: Mutex<Option<Arc<DropEvent>>>,
138}
139
140impl<K> LayerData<K> {
141    fn data_offset(&self) -> u64 {
142        NUM_HEADER_BLOCKS * self.block_size
143    }
144}
145
146/// A handle to an asynchronous, chunk-cached persistent layer.
147pub struct PersistentLayer<K, V> {
148    object_handle: CachingObjectHandle<Arc<dyn LayerObject>>,
149    data: LayerData<K>,
150    _value_type: PhantomData<V>,
151}
152
153/// A handle to a synchronous, slice-backed persistent layer.
154pub struct SyncPersistentLayer<K, V> {
155    object_handle: Arc<dyn LayerObject>,
156    data: LayerData<K>,
157    _value_type: PhantomData<V>,
158}
159
160struct BufferCursor<B> {
161    buffer: B,
162    pos: usize,
163}
164
165impl<B: LayerBuffer> BufferCursor<B> {
166    fn as_bytes(&self) -> &[u8] {
167        self.buffer.as_bytes_from(self.pos)
168    }
169}
170
171impl<B: LayerBuffer> std::io::Read for BufferCursor<B> {
172    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
173        let to_read = self.buffer.read_at(self.pos, buf);
174        self.pos += to_read;
175        Ok(to_read)
176    }
177}
178
179trait LayerBuffer {
180    fn read_at(&self, pos: usize, buf: &mut [u8]) -> usize;
181
182    fn as_bytes_from(&self, pos: usize) -> &[u8];
183
184    fn has_io_error(&self) -> bool {
185        false
186    }
187}
188
189struct ChunkBuffer<'iter> {
190    handle: &'iter CachingObjectHandle<Arc<dyn LayerObject>>,
191    // The currently loaded chunk and its index.
192    chunk: Option<(usize, CachedChunk)>,
193}
194
195impl LayerBuffer for ChunkBuffer<'_> {
196    fn read_at(&self, pos: usize, buf: &mut [u8]) -> usize {
197        let Some((_, chunk)) = &self.chunk else {
198            return 0;
199        };
200        let to_read = std::cmp::min(buf.len(), chunk.len().saturating_sub(pos));
201        if to_read > 0 {
202            buf[..to_read].copy_from_slice(&chunk[pos..pos + to_read]);
203        }
204        to_read
205    }
206
207    fn as_bytes_from(&self, pos: usize) -> &[u8] {
208        self.chunk.as_ref().and_then(|(_, c)| c.get(pos..)).unwrap_or(&[])
209    }
210}
211
212#[derive(Clone, Copy)]
213struct SliceBuffer<'iter> {
214    handle: &'iter dyn LayerObject,
215    slice: &'iter [u8],
216}
217
218impl LayerBuffer for SliceBuffer<'_> {
219    fn read_at(&self, pos: usize, buf: &mut [u8]) -> usize {
220        let to_read = std::cmp::min(buf.len(), self.slice.len().saturating_sub(pos));
221        if to_read > 0 {
222            buf[..to_read].copy_from_slice(&self.slice[pos..pos + to_read]);
223        }
224        to_read
225    }
226
227    fn as_bytes_from(&self, pos: usize) -> &[u8] {
228        self.slice.get(pos..).unwrap_or(&[])
229    }
230
231    fn has_io_error(&self) -> bool {
232        self.handle.has_io_error()
233    }
234}
235
236// How many blocks we reserve for the header.  Data blocks start at this offset.
237const NUM_HEADER_BLOCKS: u64 = 1;
238
239/// The smallest possible (empty) layer file is always 2 blocks, one for the header and one for
240/// LayerInfo.
241const MINIMUM_LAYER_FILE_BLOCKS: u64 = 2;
242
243// Put safety rails on the size of the bloom filter and seek table to avoid OOMing the system.
244// It's more likely that tampering has occurred in these cases.
245const MAX_BLOOM_FILTER_SIZE: usize = 64 * 1024 * 1024;
246const MAX_SEEK_TABLE_SIZE: usize = 64 * 1024 * 1024;
247
248// The following constants refer to sizes of metadata in the data blocks.
249const PER_DATA_BLOCK_HEADER_SIZE: usize = 2;
250const PER_DATA_BLOCK_SEEK_ENTRY_SIZE: usize = 2;
251
252enum KeyState<K> {
253    None,
254    Deserialized(K),
255    InPlace,
256}
257
258// A key-only iterator, used while seeking through the tree.
259struct KeyOnlyIterator<'iter, K: Key, V: LayerValue, B> {
260    // Allocated out of |layer|.
261    buffer: BufferCursor<B>,
262
263    layer: &'iter LayerData<K>,
264
265    // The position of the _next_ block to be read.
266    pos: u64,
267
268    // The item index in the current block.
269    item_index: u16,
270
271    // The number of items in the current block.
272    item_count: u16,
273
274    // The current key state.
275    key: KeyState<K>,
276
277    // The base value used for decoding keys in the current block.
278    current_block_base_u64: u64,
279
280    _value_type: PhantomData<V>,
281}
282
283impl<K: Key, V: LayerValue, B: LayerBuffer> KeyOnlyIterator<'_, K, V, B> {
284    fn corruption_error(&self, err: impl std::fmt::Display + Send + Sync + 'static) -> Error {
285        if self.buffer.buffer.has_io_error() {
286            anyhow!(zx_status::Status::IO).context(err)
287        } else {
288            anyhow!(FxfsError::Inconsistent).context(err)
289        }
290    }
291
292    // Repositions the iterator to point to the `index`'th item in the current block.
293    // Returns an error if the index is out of range or the resulting offset contains an obviously
294    // invalid value.
295    fn seek_to_block_item(&mut self, index: u16) -> Result<(), Error> {
296        ensure!(index < self.item_count, FxfsError::OutOfRange);
297        if index == self.item_index && matches!(self.key, KeyState::None) {
298            // Fast-path when we are seeking in a linear manner, as is the case when advancing a
299            // wrapping iterator that also deserializes the values.
300            return Ok(());
301        }
302        let block_start =
303            self.layer.block_size.align_down((self.buffer.pos as u64).saturating_sub(1)) as usize;
304        let offset_in_block = if index == 0 {
305            // First entry isn't actually recorded, it is at the start of the block after the item
306            // count.
307            PER_DATA_BLOCK_HEADER_SIZE
308        } else {
309            let old_buffer_pos = self.buffer.pos;
310            let seek_entry_pos = (block_start + self.layer.block_size.get() as usize)
311                .checked_sub(PER_DATA_BLOCK_SEEK_ENTRY_SIZE * usize::from(self.item_count - index))
312                .ok_or_else(|| {
313                    self.corruption_error(format!(
314                        "Invalid item count {} for index {index}",
315                        self.item_count
316                    ))
317                })?;
318            if seek_entry_pos < block_start + PER_DATA_BLOCK_HEADER_SIZE {
319                return Err(self.corruption_error(format!(
320                    "Invalid item count {} for index {index}",
321                    self.item_count
322                )));
323            }
324            self.buffer.pos = seek_entry_pos;
325            let res = self.buffer.read_u16::<LittleEndian>();
326            self.buffer.pos = old_buffer_pos;
327            let offset_in_block = res
328                .map_err(|e| self.corruption_error(e))
329                .context("Failed to read offset")? as usize;
330            if offset_in_block >= self.layer.block_size.get() as usize
331                || offset_in_block <= PER_DATA_BLOCK_HEADER_SIZE
332            {
333                return Err(self
334                    .corruption_error(format!("Offset {offset_in_block} is out of valid range.")));
335            }
336            offset_in_block
337        };
338        self.item_index = index;
339        self.key = KeyState::None;
340        self.buffer.pos = block_start + offset_in_block;
341        Ok(())
342    }
343
344    fn take_item(&mut self) -> Result<Option<Item<K, V>>, Error> {
345        let key = match std::mem::replace(&mut self.key, KeyState::None) {
346            KeyState::None => return Ok(None),
347            KeyState::InPlace => {
348                let (mut deserializer, key_len) =
349                    KeyDeserializer::new(self.buffer.as_bytes(), Some(self.current_block_base_u64))
350                        .map_err(|e| self.corruption_error(e))
351                        .context("Corrupt layer (key format)")?;
352                let key = K::deserialize_key_from(&mut deserializer)
353                    .map_err(|e| self.corruption_error(e))
354                    .context("Corrupt layer (key)")?;
355                if !deserializer.is_empty() {
356                    return Err(self.corruption_error("Trailing bytes in serialized key"));
357                }
358                self.buffer.pos += key_len;
359                key
360            }
361            KeyState::Deserialized(key) => key,
362        };
363        let value = V::deserialize_from_version(self.buffer.by_ref(), self.layer.version)
364            .map_err(|e| self.corruption_error(e))
365            .context("Corrupt layer (value)")?;
366        Ok(Some(Item { key, value }))
367    }
368
369    fn read_block_header(&mut self) -> Result<(), Error> {
370        self.item_count =
371            self.buffer.read_u16::<LittleEndian>().map_err(|e| self.corruption_error(e))?;
372        if self.item_count == 0 {
373            return Err(self.corruption_error(format!(
374                "Read block with zero item count (object: {}, offset: {})",
375                self.layer.object_id, self.pos
376            )));
377        }
378        if PER_DATA_BLOCK_HEADER_SIZE
379            + (usize::from(self.item_count) - 1) * PER_DATA_BLOCK_SEEK_ENTRY_SIZE
380            >= self.layer.block_size.get() as usize
381        {
382            return Err(self.corruption_error("Block seek table overlaps header"));
383        }
384        debug!(
385            pos = self.pos,
386            object_size = self.layer.data_offset() + self.layer.data_size,
387            oid = self.layer.object_id;
388            ""
389        );
390        if self.layer.version > OLD_KEY_SERIALIZATION_VERSION {
391            let block_index = (self.pos - self.layer.data_offset()) / self.layer.block_size;
392            self.current_block_base_u64 = *self
393                .layer
394                .seek_table
395                .get(block_index as usize)
396                .ok_or_else(|| self.corruption_error("Block index out of bounds"))?;
397        }
398        self.pos += self.layer.block_size;
399        self.item_index = 0;
400        self.key = KeyState::None;
401        Ok(())
402    }
403
404    fn deserialize_current_key(&mut self) -> Result<(), Error> {
405        self.seek_to_block_item(self.item_index)?;
406        self.key = if self.layer.version <= OLD_KEY_SERIALIZATION_VERSION {
407            KeyState::Deserialized(
408                K::deserialize_from_version(self.buffer.by_ref(), self.layer.version)
409                    .map_err(|e| self.corruption_error(e))
410                    .context("Corrupt layer (key)")?,
411            )
412        } else {
413            KeyState::InPlace
414        };
415        self.item_index += 1;
416        Ok(())
417    }
418
419    // Binary searches the current block for `search_key`.  The iterator must be positioned at the
420    // first item in the block, and that item must be less than `search_key`.  If the block
421    // contains a key that is greater than or equal to `search_key`, the iterator is positioned at
422    // the first such key and `Some(true)` is returned for an exact match, or `Some(false)`
423    // otherwise.  If every key in the block is less than `search_key`, `None` is returned and the
424    // caller should advance the iterator to the next block.
425    fn binary_search_block(
426        &mut self,
427        search_key: &mut SearchKey<'_, K>,
428    ) -> Result<Option<bool>, Error> {
429        if self.layer.version > OLD_KEY_SERIALIZATION_VERSION {
430            let target = search_key
431                .serialized_with_base(self.current_block_base_u64)
432                .ok_or_else(|| self.corruption_error("Search key precedes block"))?;
433            return self.binary_search_block_in_place(target);
434        }
435
436        let mut left_index = 0;
437        let mut right_index = self.item_count;
438        while left_index < (right_index - 1) {
439            let mid_index = left_index + ((right_index - left_index) / 2);
440            self.seek_to_block_item(mid_index).context("Read index offset for binary search")?;
441            self.deserialize_current_key()?;
442            match search_key.compare(self)?.context("Unexpected EOF")? {
443                Ordering::Greater => right_index = mid_index,
444                Ordering::Equal => return Ok(Some(true)),
445                Ordering::Less => left_index = mid_index,
446            }
447        }
448        if right_index < self.item_count {
449            self.seek_to_block_item(right_index)
450                .context("Read index for offset of right pointer")?;
451            self.deserialize_current_key()?;
452            return Ok(Some(false));
453        }
454        self.key = KeyState::None;
455        Ok(None)
456    }
457
458    // Like `binary_search_block`, but compares the serialized `target` key directly against the
459    // keys in the block without repositioning the iterator for each probe.
460    fn binary_search_block_in_place(&mut self, target: &[u8]) -> Result<Option<bool>, Error> {
461        let mut left_index = 0;
462        let mut right_index = self.item_count;
463        if right_index > 1 {
464            let block_size = self.layer.block_size.get() as usize;
465            let block_start =
466                self.layer.block_size.align_down((self.buffer.pos as u64).saturating_sub(1))
467                    as usize;
468            let block_bytes = self
469                .buffer
470                .buffer
471                .as_bytes_from(block_start)
472                .get(..block_size)
473                .ok_or_else(|| self.corruption_error("Short block"))?;
474            // `read_block_header` has checked that the seek entries don't overlap the header.
475            let seek_table_offset =
476                block_size - usize::from(right_index - 1) * PER_DATA_BLOCK_SEEK_ENTRY_SIZE;
477            let (data_bytes, seek_entries) = block_bytes.split_at(seek_table_offset);
478            let mut found = None;
479            while left_index < (right_index - 1) {
480                let mid_index = left_index + ((right_index - left_index) / 2);
481                let entry_pos = usize::from(mid_index - 1) * PER_DATA_BLOCK_SEEK_ENTRY_SIZE;
482                let offset = LittleEndian::read_u16(
483                    &seek_entries[entry_pos..entry_pos + PER_DATA_BLOCK_SEEK_ENTRY_SIZE],
484                ) as usize;
485                if offset >= seek_table_offset || offset <= PER_DATA_BLOCK_HEADER_SIZE {
486                    return Err(
487                        self.corruption_error(format!("Offset {offset} is out of valid range."))
488                    );
489                }
490                match compare_keys(&data_bytes[offset..], target)
491                    .map_err(|e| self.corruption_error(e))?
492                {
493                    Ordering::Greater => {
494                        right_index = mid_index;
495                        found = Some((mid_index, offset, false));
496                    }
497                    Ordering::Equal => {
498                        found = Some((mid_index, offset, true));
499                        break;
500                    }
501                    Ordering::Less => left_index = mid_index,
502                }
503            }
504            if let Some((index, offset, exact)) = found {
505                self.item_index = index + 1;
506                self.key = KeyState::InPlace;
507                self.buffer.pos = block_start + offset;
508                return Ok(Some(exact));
509            }
510        }
511        self.item_index = self.item_count;
512        self.key = KeyState::None;
513        Ok(None)
514    }
515}
516
517impl<'iter, K: Key, V: LayerValue, B> KeyOnlyIterator<'iter, K, V, B> {
518    // Returns an iterator which reads the block at `pos` (the file offset of a key block) out of
519    // `buffer`, starting at `buffer_pos`.
520    fn new(layer: &'iter LayerData<K>, buffer: B, buffer_pos: usize, pos: u64) -> Self {
521        assert!(layer.block_size.is_aligned(pos));
522        Self {
523            layer,
524            buffer: BufferCursor { buffer, pos: buffer_pos },
525            pos,
526            item_index: 0,
527            item_count: 0,
528            key: KeyState::None,
529            current_block_base_u64: 0,
530            _value_type: PhantomData,
531        }
532    }
533}
534
535impl<'iter, K: Key, V: LayerValue> KeyOnlyIterator<'iter, K, V, ChunkBuffer<'iter>> {
536    fn new_async(layer: &'iter PersistentLayer<K, V>, pos: u64) -> Self {
537        Self::new(
538            &layer.data,
539            ChunkBuffer { handle: &layer.object_handle, chunk: None },
540            (pos % CHUNK_SIZE) as usize,
541            pos,
542        )
543    }
544
545    // Returns a new iterator for the block at `pos`, reusing the chunk held by `self` or `other`
546    // if either contains `pos`, which saves a cache lookup.
547    fn reposition(&self, pos: u64, other: Option<&Self>) -> Self {
548        let chunk_num = (pos / CHUNK_SIZE) as usize;
549        let chunk =
550            std::iter::once(self).chain(other).find_map(|iter| match &iter.buffer.buffer.chunk {
551                Some((n, chunk)) if *n == chunk_num => Some((chunk_num, chunk.clone())),
552                _ => None,
553            });
554        Self::new(
555            self.layer,
556            ChunkBuffer { handle: self.buffer.buffer.handle, chunk },
557            (pos % CHUNK_SIZE) as usize,
558            pos,
559        )
560    }
561
562    async fn advance(&mut self) -> Result<(), Error> {
563        if !self.try_advance()? {
564            let chunk_num = (self.pos / CHUNK_SIZE) as usize;
565            let chunk = self
566                .buffer
567                .buffer
568                .handle
569                .read(self.pos as usize)
570                .await
571                .context("Reading during advance")?;
572            self.buffer.buffer.chunk = Some((chunk_num, chunk));
573            self.buffer.pos = (self.pos % CHUNK_SIZE) as usize;
574            self.read_block_header()?;
575            self.deserialize_current_key()?;
576        }
577        Ok(())
578    }
579
580    // Advances without blocking.  Returns false, leaving the iterator unchanged, if the next block
581    // needs to be read from the underlying handle.
582    fn try_advance(&mut self) -> Result<bool, Error> {
583        if self.item_index >= self.item_count {
584            if self.pos >= self.layer.data_offset() + self.layer.data_size {
585                self.key = KeyState::None;
586                return Ok(true);
587            }
588            let chunk_num = (self.pos / CHUNK_SIZE) as usize;
589            if !matches!(&self.buffer.buffer.chunk, Some((n, _)) if *n == chunk_num) {
590                let Some(chunk) = self.buffer.buffer.handle.try_read(self.pos as usize) else {
591                    return Ok(false);
592                };
593                self.buffer.buffer.chunk = Some((chunk_num, chunk));
594            }
595            self.buffer.pos = (self.pos % CHUNK_SIZE) as usize;
596            self.read_block_header()?;
597        }
598        self.deserialize_current_key()?;
599        Ok(true)
600    }
601}
602
603impl<'iter, K: Key, V: LayerValue> KeyOnlyIterator<'iter, K, V, SliceBuffer<'iter>> {
604    fn new_sync(layer: &'iter SyncPersistentLayer<K, V>, pos: u64) -> Self {
605        let slice = layer.object_handle.as_slice().expect("slice must be present");
606        Self::new(
607            &layer.data,
608            SliceBuffer { handle: layer.object_handle.as_ref(), slice },
609            pos as usize,
610            pos,
611        )
612    }
613
614    // Returns a new iterator for the block at `pos`.  `_other` exists for parity with the
615    // chunk-backed version; the whole layer is always available here.
616    fn reposition(&self, pos: u64, _other: Option<&Self>) -> Self {
617        Self::new(self.layer, self.buffer.buffer, pos as usize, pos)
618    }
619
620    fn advance(&mut self) -> Result<(), Error> {
621        if self.item_index >= self.item_count {
622            if self.pos >= self.layer.data_offset() + self.layer.data_size {
623                self.key = KeyState::None;
624                return Ok(());
625            }
626            self.buffer.pos = self.pos as usize;
627            self.read_block_header()?;
628        }
629        self.deserialize_current_key()
630    }
631}
632
633struct Iterator<'iter, K: Key, V: LayerValue, B> {
634    inner: KeyOnlyIterator<'iter, K, V, B>,
635    // The current item.
636    item: Option<Item<K, V>>,
637}
638
639impl<'iter, K: Key, V: LayerValue, B: LayerBuffer> Iterator<'iter, K, V, B> {
640    fn new(mut seek_iterator: KeyOnlyIterator<'iter, K, V, B>) -> Result<Self, Error> {
641        let item = seek_iterator.take_item()?;
642        Ok(Self { inner: seek_iterator, item })
643    }
644}
645
646impl<'iter, K: Key, V: LayerValue> LayerIterator<K, V>
647    for Iterator<'iter, K, V, ChunkBuffer<'iter>>
648{
649    async fn advance(&mut self) -> Result<(), Error> {
650        self.inner.advance().await?;
651        self.item = self.inner.take_item()?;
652        Ok(())
653    }
654
655    fn advance_dyn<'a>(&'a mut self) -> Result<Option<BoxFuture<'a, Result<(), Error>>>, Error> {
656        if self.inner.try_advance()? {
657            self.item = self.inner.take_item()?;
658            Ok(None)
659        } else {
660            Ok(Some(Box::pin(self.advance())))
661        }
662    }
663
664    fn get(&self) -> Option<ItemRef<'_, K, V>> {
665        self.item.as_ref().map(<&Item<K, V>>::into)
666    }
667}
668
669impl<'iter, K: Key, V: LayerValue> LayerIterator<K, V>
670    for Iterator<'iter, K, V, SliceBuffer<'iter>>
671{
672    async fn advance(&mut self) -> Result<(), Error> {
673        self.inner.advance()?;
674        self.item = self.inner.take_item()?;
675        Ok(())
676    }
677
678    fn advance_dyn<'a>(&'a mut self) -> Result<Option<BoxFuture<'a, Result<(), Error>>>, Error> {
679        self.inner.advance()?;
680        self.item = self.inner.take_item()?;
681        Ok(None)
682    }
683
684    fn get(&self) -> Option<ItemRef<'_, K, V>> {
685        self.item.as_ref().map(<&Item<K, V>>::into)
686    }
687}
688
689fn seek_table_size(version: Version, num_data_blocks: u64) -> Result<usize, Error> {
690    if num_data_blocks == 0 || version <= OLD_KEY_SERIALIZATION_VERSION {
691        // Ignore the seek table on older versions because AllocatorKey::get_leading_u64()
692        // changed from bytes to blocks.
693        return Ok(0);
694    }
695    let seek_table_size = (num_data_blocks as usize) * std::mem::size_of::<u64>();
696    if seek_table_size > MAX_SEEK_TABLE_SIZE {
697        return Err(anyhow!(FxfsError::NotSupported)).context("Seek table too large");
698    }
699    Ok(seek_table_size)
700}
701
702fn parse_seek_table(bytes: PtrByteSlice<'_>, num_data_blocks: u64) -> Result<Vec<u64>, Error> {
703    let mut seek_table = Vec::with_capacity(num_data_blocks as usize);
704    let mut prev = 0;
705    for chunk in bytes.iter_as::<[u8; 8]>() {
706        let next = u64::from_le_bytes(chunk);
707        // Should be in strict ascending order, otherwise something's broken, or we've gone off
708        // the end and we're reading zeroes.
709        if prev > next {
710            return Err(anyhow!(FxfsError::Inconsistent))
711                .context(format!("Seek table entry out of order, {prev:?} > {next:?}"));
712        }
713        prev = next;
714        seek_table.push(next);
715    }
716    Ok(seek_table)
717}
718
719async fn load_seek_table(
720    object_handle: &(impl ReadObjectHandle + 'static),
721    seek_table_offset: u64,
722    num_data_blocks: u64,
723    version: Version,
724) -> Result<Vec<u64>, Error> {
725    let seek_table_size = seek_table_size(version, num_data_blocks)?;
726    if seek_table_size == 0 {
727        return Ok(Vec::new());
728    }
729    let aligned_size =
730        object_handle.block_size().align_up(seek_table_size as u64).ok_or(FxfsError::TooBig)?
731            as usize;
732    let mut buffer = object_handle.allocate_buffer(aligned_size).await;
733    let bytes_read = object_handle
734        .read_aligned(seek_table_offset, buffer.as_mut())
735        .await
736        .context("Reading seek table blocks")?;
737    ensure!(bytes_read >= seek_table_size, "Short read");
738
739    parse_seek_table(buffer.subslice(0..seek_table_size).as_ptr_slice(), num_data_blocks)
740}
741
742const BLOOM_FILTER_READ_CHUNK_SIZE: usize = 1024 * 1024;
743
744fn bloom_filter_size(version: Version, layer_info: &LayerInfo) -> Result<usize, Error> {
745    if version != LATEST_VERSION || layer_info.bloom_filter_size_bytes == 0 {
746        // Ignore the bloom filter for layer files in outdated versions.  We don't know whether
747        // keys have changed formats or not (and therefore have different hash values), so we
748        // must ignore the bloom filter and always query the layer.
749        return Ok(0);
750    }
751    if layer_info.bloom_filter_size_bytes > MAX_BLOOM_FILTER_SIZE {
752        return Err(anyhow!(FxfsError::NotSupported)).context("Bloom filter too large");
753    }
754    Ok(layer_info.bloom_filter_size_bytes)
755}
756
757async fn load_bloom_filter<K: FuzzyHash>(
758    handle: &(impl ReadObjectHandle + 'static),
759    bloom_filter_offset: u64,
760    version: Version,
761    layer_info: &LayerInfo,
762) -> Result<Option<BloomFilterReader<K>>, Error> {
763    let size = bloom_filter_size(version, layer_info)?;
764    if size == 0 {
765        return Ok(None);
766    }
767    let aligned_size = handle.block_size().align_up(size as u64).ok_or(FxfsError::TooBig)? as usize;
768    let mut buffer = handle.allocate_buffer(aligned_size).await;
769    let reads = FuturesUnordered::new();
770    let mut offset = bloom_filter_offset;
771    for chunk in buffer.as_mut().chunks_mut(BLOOM_FILTER_READ_CHUNK_SIZE) {
772        let chunk_len = chunk.len() as u64;
773        reads.push(async move {
774            handle.read_aligned(offset, chunk).await.context("Failed to read")?;
775            Ok::<(), Error>(())
776        });
777        offset += chunk_len;
778    }
779    reads.try_collect::<()>().await?;
780    Ok(Some(BloomFilterReader::read(
781        buffer.subslice(0..size).as_ptr_slice(),
782        layer_info.bloom_filter_seed,
783        layer_info.bloom_filter_num_hashes,
784    )?))
785}
786
787struct SearchKey<'a, K: Key> {
788    key: &'a K,
789    buf: Vec<u8>,
790    cached_base: Option<u64>,
791}
792
793impl<'a, K: Key> SearchKey<'a, K> {
794    fn new(key: &'a K) -> Self {
795        Self { key, buf: Vec::new(), cached_base: None }
796    }
797
798    // Returns the key serialized relative to `base`, or None if the key sorts before any key that
799    // can be encoded relative to `base`.
800    fn serialized_with_base(&mut self, base: u64) -> Option<&[u8]> {
801        if self.key.get_leading_u64() < base {
802            return None;
803        }
804        if self.cached_base != Some(base) {
805            self.buf.clear();
806            self.key.serialize_key_with_base_into(&mut self.buf, base);
807            self.cached_base = Some(base);
808        }
809        Some(&self.buf)
810    }
811
812    fn compare<V: LayerValue, B: LayerBuffer>(
813        &mut self,
814        iter: &KeyOnlyIterator<'_, K, V, B>,
815    ) -> Result<Option<Ordering>, Error> {
816        match &iter.key {
817            KeyState::None => Ok(None),
818            KeyState::Deserialized(k) => Ok(Some(k.cmp_upper_bound(self.key))),
819            KeyState::InPlace => {
820                let Some(target) = self.serialized_with_base(iter.current_block_base_u64) else {
821                    return Ok(Some(Ordering::Greater));
822                };
823                Ok(Some(
824                    compare_keys(iter.buffer.as_bytes(), target)
825                        .map_err(|e| iter.corruption_error(e))?,
826                ))
827            }
828        }
829    }
830}
831
832impl<K: FuzzyHash> LayerData<K> {
833    fn new(
834        object_id: u64,
835        version: Version,
836        block_size: BlockSize,
837        layer_info: &LayerInfo,
838        seek_table: Vec<u64>,
839        bloom_filter: Option<BloomFilterReader<K>>,
840    ) -> Self {
841        let bloom_filter_stats = bloom_filter.as_ref().map(|b| b.stats());
842        Self {
843            object_id,
844            version,
845            block_size,
846            data_size: block_size * layer_info.num_data_blocks,
847            seek_table,
848            num_items: layer_info.num_items,
849            bloom_filter,
850            bloom_filter_stats,
851            close_event: Mutex::new(Some(Arc::new(DropEvent::new()))),
852        }
853    }
854
855    fn parse_header(
856        mut reader: PtrByteSlice<'_>,
857        handle_block_size: BlockSize,
858        total_size: u64,
859    ) -> Result<(Version, BlockSize, u64), Error> {
860        let version = Version::deserialize_from(&mut reader)?;
861        ensure!(version <= LATEST_VERSION, FxfsError::InvalidVersion);
862        let header = LayerHeader::deserialize_from_version(&mut reader, version)
863            .context("Failed to deserialize header")?;
864        if &header.magic != PERSISTENT_LAYER_MAGIC {
865            return Err(anyhow!(FxfsError::Inconsistent).context("Invalid layer file magic"));
866        }
867        let block_size = BlockSize::from_u64(header.block_size).ok_or_else(|| {
868            anyhow!(FxfsError::Inconsistent)
869                .context(format!("Invalid block size {}", header.block_size))
870        })?;
871        ensure!(block_size <= MAX_BLOCK_SIZE, FxfsError::NotSupported);
872        ensure!(block_size >= MIN_BLOCK_SIZE, FxfsError::NotSupported);
873        if !handle_block_size.is_aligned(block_size.get()) {
874            return Err(anyhow!(FxfsError::Inconsistent)).context(format!(
875                "{block_size} not a multiple of handle block size {handle_block_size}"
876            ));
877        }
878        if total_size < MINIMUM_LAYER_FILE_BLOCKS * block_size {
879            return Err(anyhow!(FxfsError::Inconsistent).context("Layer file too short"));
880        }
881        let last_block_offset = total_size
882            .checked_sub(block_size.get())
883            .ok_or(FxfsError::Inconsistent)
884            .context("Layer file unexpectedly short")?;
885        Ok((version, block_size, last_block_offset))
886    }
887
888    fn parse_layer_info(
889        last_block: PtrByteSlice<'_>,
890        version: Version,
891        block_size: BlockSize,
892        total_size: u64,
893    ) -> Result<(LayerInfo, u64, u64), Error> {
894        let bs = block_size.get() as usize;
895        let layer_info_len = u64::from_le_bytes(last_block.subslice(bs - 8..bs).read().unwrap());
896        let layer_info_offset = std::mem::size_of::<u64>()
897            .checked_add(layer_info_len as usize)
898            .and_then(|n| bs.checked_sub(n))
899            .ok_or(FxfsError::Inconsistent)
900            .context("Invalid layer info length")?;
901        let mut reader = last_block.subslice(layer_info_offset..bs);
902        let layer_info = LayerInfo::deserialize_from_version(&mut reader, version)
903            .context("Failed to deserialize LayerInfo")?;
904        if layer_info.num_items == 0 && layer_info.num_data_blocks > 0 {
905            return Err(anyhow!(FxfsError::Inconsistent))
906                .context("Invalid num_items/num_data_blocks");
907        }
908        let total_blocks = total_size / block_size;
909        let bloom_filter_blocks =
910            block_size.align_up_to_blocks(layer_info.bloom_filter_size_bytes as u64);
911        if layer_info.num_data_blocks.saturating_add(bloom_filter_blocks)
912            > total_blocks - MINIMUM_LAYER_FILE_BLOCKS
913        {
914            return Err(anyhow!(FxfsError::Inconsistent)).context("Invalid number of blocks");
915        }
916        let bloom_filter_offset = block_size * (NUM_HEADER_BLOCKS + layer_info.num_data_blocks);
917        let seek_offset =
918            block_size * (NUM_HEADER_BLOCKS + layer_info.num_data_blocks + bloom_filter_blocks);
919        Ok((layer_info, bloom_filter_offset, seek_offset))
920    }
921
922    async fn open(handle: &Arc<dyn LayerObject>) -> Result<Self, Error> {
923        let handle_block_size = handle.block_size();
924        let mut buffer = handle.allocate_buffer(handle_block_size.get() as usize).await;
925        handle.read_aligned(0, buffer.as_mut()).await.context("Failed to read first block")?;
926        let (version, block_size, last_block_offset) =
927            Self::parse_header(buffer.as_ptr_slice(), handle_block_size, handle.get_size())?;
928
929        let bs = block_size.get() as usize;
930        handle
931            .read_aligned(last_block_offset, buffer.subslice_mut(0..bs))
932            .await
933            .context("Failed to read layer info")?;
934        let (layer_info, bloom_filter_offset, seek_offset) = Self::parse_layer_info(
935            buffer.subslice(0..bs).as_ptr_slice(),
936            version,
937            block_size,
938            handle.get_size(),
939        )?;
940        std::mem::drop(buffer);
941
942        let bloom_filter = load_bloom_filter(handle, bloom_filter_offset, version, &layer_info)
943            .await
944            .context("Failed to load bloom filter")?;
945        let seek_table = load_seek_table(handle, seek_offset, layer_info.num_data_blocks, version)
946            .await
947            .context("Failed to load seek table")?;
948
949        Ok(Self::new(
950            handle.object_id(),
951            version,
952            block_size,
953            &layer_info,
954            seek_table,
955            bloom_filter,
956        ))
957    }
958
959    fn open_from_slice(handle: &Arc<dyn LayerObject>) -> Result<Self, Error> {
960        let slice = handle.as_slice().ok_or(FxfsError::InvalidArgs)?;
961        let io_or_corruption = |err: Error| -> Error {
962            if handle.has_io_error() { anyhow!(zx_status::Status::IO).context(err) } else { err }
963        };
964        let handle_block_size = handle.block_size();
965        let total_size = slice.len() as u64;
966        if total_size < handle_block_size.get() {
967            return Err(io_or_corruption(
968                anyhow!(FxfsError::Inconsistent).context("Layer file too short"),
969            ));
970        }
971        let (version, block_size, last_block_offset) = Self::parse_header(
972            slice[..handle_block_size.get() as usize].into(),
973            handle_block_size,
974            total_size,
975        )
976        .map_err(&io_or_corruption)?;
977
978        let bs = block_size.get() as usize;
979        let last_block = &slice[last_block_offset as usize..last_block_offset as usize + bs];
980        let (layer_info, bloom_filter_offset, seek_offset) =
981            Self::parse_layer_info(last_block.into(), version, block_size, total_size)
982                .map_err(&io_or_corruption)?;
983
984        let bf_size = bloom_filter_size(version, &layer_info)
985            .map_err(&io_or_corruption)
986            .context("Failed to load bloom filter")?;
987        let st_size = seek_table_size(version, layer_info.num_data_blocks)
988            .map_err(&io_or_corruption)
989            .context("Failed to load seek table")?;
990        if bf_size > 0 {
991            handle.prefetch(bloom_filter_offset..total_size);
992        } else if st_size > 0 {
993            handle.prefetch(seek_offset..total_size);
994        }
995
996        let bloom_filter = if bf_size > 0 {
997            let start = bloom_filter_offset as usize;
998            let end = start
999                .checked_add(bf_size)
1000                .filter(|&end| end <= slice.len())
1001                .ok_or_else(|| io_or_corruption(anyhow!(FxfsError::Inconsistent)))
1002                .context("Bloom filter out of bounds")?;
1003            Some(BloomFilterReader::from_bytes(
1004                &slice[start..end],
1005                layer_info.bloom_filter_seed,
1006                layer_info.bloom_filter_num_hashes,
1007            ))
1008        } else {
1009            None
1010        };
1011
1012        let seek_table = if st_size > 0 {
1013            let start = seek_offset as usize;
1014            let end = start
1015                .checked_add(st_size)
1016                .filter(|&end| end <= slice.len())
1017                .ok_or_else(|| io_or_corruption(anyhow!(FxfsError::Inconsistent)))
1018                .context("Seek table out of bounds")?;
1019            parse_seek_table(slice[start..end].into(), layer_info.num_data_blocks)
1020                .map_err(&io_or_corruption)
1021                .context("Failed to load seek table")?
1022        } else {
1023            Vec::new()
1024        };
1025
1026        if handle.has_io_error() {
1027            return Err(anyhow!(zx_status::Status::IO).context("I/O error while opening layer"));
1028        }
1029
1030        Ok(Self::new(
1031            handle.object_id(),
1032            version,
1033            block_size,
1034            &layer_info,
1035            seek_table,
1036            bloom_filter,
1037        ))
1038    }
1039}
1040
1041macro_rules! seek_impl {
1042    ($self:ident, $bound:ident $(, $await:tt)?) => {{
1043        let (key, excluded) = match $bound {
1044            Bound::Unbounded => {
1045                let mut iterator = $self.key_only_iterator($self.data_offset());
1046                iterator.advance()$(.$await)? .context("Unbounded seek advance")?;
1047                return Ok(Iterator::new(iterator)?);
1048            }
1049            Bound::Included(k) => (k, false),
1050            Bound::Excluded(k) => (k, true),
1051        };
1052        let first_data_block_index = $self.data_offset() / $self.data.block_size;
1053
1054        let (mut left_offset, mut right_offset) = if $self.data.seek_table.is_empty() {
1055            ($self.data_offset(), $self.data_offset() + $self.data.data_size)
1056        } else {
1057            // We are searching for a range here, as multiple items can have the same value in
1058            // this approximate search. Since the values in the seek table represent the first
1059            // key in each block (ordered by cmp_upper_bound), if the value equals the target
1060            // we must also search the block before it. The goal is for
1061            // table[left] < target < table[right].
1062            let target = key.get_leading_u64();
1063            let right_index =
1064                $self.data.seek_table.as_slice().partition_point(|&x| x <= target) as u64;
1065            if right_index == 0 {
1066                let mut iterator = $self.key_only_iterator($self.data_offset());
1067                iterator.advance()$(.$await)? .context("Initial seek advance")?;
1068                return Ok(Iterator::new(iterator)?);
1069            }
1070            // Since partition_point will find the index of the first place where the predicate
1071            // is false, we subtract 1 to get the index where it was last true.
1072            let left_index = $self.data.seek_table.as_slice()[..right_index as usize]
1073                .partition_point(|&x| x < target)
1074                .saturating_sub(1) as u64;
1075
1076            (
1077                (left_index + first_data_block_index) * $self.data.block_size,
1078                (right_index + first_data_block_index) * $self.data.block_size,
1079            )
1080        };
1081        let mut left = $self.key_only_iterator(left_offset);
1082        left.advance()$(.$await)? .context("Initial seek advance")?;
1083        let mut search_key = SearchKey::new(key);
1084        match search_key.compare(&left)? {
1085            Some(Ordering::Less) => {}
1086            Some(Ordering::Equal) if excluded => {
1087                left.advance()$(.$await)??;
1088                return Ok(Iterator::new(left)?);
1089            }
1090            _ => return Ok(Iterator::new(left)?),
1091        }
1092        let mut right = None;
1093        while right_offset - left_offset > $self.data.block_size {
1094            // Pick a block midway.
1095            let mid_offset =
1096                $self.data.block_size.align_down(left_offset + (right_offset - left_offset) / 2);
1097            let mut iterator = left.reposition(mid_offset, right.as_ref());
1098            iterator.advance()$(.$await)??;
1099            match search_key.compare(&iterator)?.context("Unexpected EOF")? {
1100                Ordering::Greater => {
1101                    right_offset = mid_offset;
1102                    right = Some(iterator);
1103                }
1104                Ordering::Equal => {
1105                    if excluded {
1106                        iterator.advance()$(.$await)??;
1107                    }
1108                    return Ok(Iterator::new(iterator)?);
1109                }
1110                Ordering::Less => {
1111                    left_offset = mid_offset;
1112                    left = iterator;
1113                }
1114            }
1115        }
1116
1117        // Finish the binary search on the block pointed to by `left`.
1118        match left.binary_search_block(&mut search_key)? {
1119            Some(true) if excluded => left.advance()$(.$await)??,
1120            Some(_) => {}
1121            // When we don't find an entry that is greater than or equal to the target in `left`,
1122            // we need to return with the first entry of the next block, which might already be
1123            // pointed to by `right`.  Otherwise, advance to the next block (or the end of the
1124            // layer).
1125            None => match right {
1126                Some(right) => return Ok(Iterator::new(right)?),
1127                None => left.advance()$(.$await)??,
1128            },
1129        }
1130        Ok(Iterator::new(left)?)
1131    }};
1132}
1133
1134fn page_size() -> BlockSize {
1135    #[cfg(target_os = "fuchsia")]
1136    {
1137        storage_units::page_size().into()
1138    }
1139    #[cfg(not(target_os = "fuchsia"))]
1140    {
1141        BlockSize::SIZE_4KIB
1142    }
1143}
1144
1145impl<K: Key, V: LayerValue> PersistentLayer<K, V> {
1146    pub async fn open(handle: impl LayerObject + 'static) -> Result<Arc<dyn Layer<K, V>>, Error> {
1147        Self::open_layer(Arc::new(handle)).await
1148    }
1149
1150    pub async fn open_layer(handle: Arc<dyn LayerObject>) -> Result<Arc<dyn Layer<K, V>>, Error> {
1151        let data = LayerData::open(&handle).await?;
1152        if handle.as_slice().is_some() && data.block_size <= page_size() {
1153            Ok(Arc::new(SyncPersistentLayer {
1154                object_handle: handle,
1155                data,
1156                _value_type: PhantomData,
1157            }) as Arc<dyn Layer<K, V>>)
1158        } else {
1159            Ok(Arc::new(PersistentLayer {
1160                object_handle: CachingObjectHandle::new(handle),
1161                data,
1162                _value_type: PhantomData,
1163            }) as Arc<dyn Layer<K, V>>)
1164        }
1165    }
1166
1167    pub async fn open_async(handle: Arc<dyn LayerObject>) -> Result<Arc<Self>, Error> {
1168        let data = LayerData::open(&handle).await?;
1169        Ok(Arc::new(PersistentLayer {
1170            object_handle: CachingObjectHandle::new(handle),
1171            data,
1172            _value_type: PhantomData,
1173        }))
1174    }
1175
1176    /// Opens a persistent layer backed by `handle`. If the layer is encrypted and the platform
1177    /// uses a pager, `unwrapped_key` is registered with the pager and dropped immediately.
1178    pub async fn open_handle(
1179        handle: DataObjectHandle<ObjectStore>,
1180        unwrapped_key: Option<UnwrappedKey>,
1181    ) -> Result<Arc<dyn Layer<K, V>>, Error> {
1182        let layer_object: Arc<dyn LayerObject> =
1183            if let Some(layer_pager) = handle.store().filesystem().layer_pager() {
1184                layer_pager.open_layer(handle, unwrapped_key).await?
1185            } else {
1186                Arc::new(handle)
1187            };
1188        Self::open_layer(layer_object).await
1189    }
1190
1191    fn data_offset(&self) -> u64 {
1192        self.data.data_offset()
1193    }
1194
1195    fn key_only_iterator(&self, pos: u64) -> KeyOnlyIterator<'_, K, V, ChunkBuffer<'_>> {
1196        KeyOnlyIterator::new_async(self, pos)
1197    }
1198
1199    async fn seek<'a>(
1200        &'a self,
1201        bound: Bound<&K>,
1202    ) -> Result<Iterator<'a, K, V, ChunkBuffer<'a>>, Error> {
1203        seek_impl!(self, bound, await)
1204    }
1205}
1206
1207impl<K: Key, V: LayerValue> SyncPersistentLayer<K, V> {
1208    pub fn open(handle: Arc<dyn LayerObject>) -> Result<Arc<Self>, Error> {
1209        let data = LayerData::open_from_slice(&handle)?;
1210        ensure!(data.block_size <= page_size(), FxfsError::NotSupported);
1211        Ok(Arc::new(Self { object_handle: handle, data, _value_type: PhantomData }))
1212    }
1213
1214    fn data_offset(&self) -> u64 {
1215        self.data.data_offset()
1216    }
1217
1218    fn key_only_iterator(&self, pos: u64) -> KeyOnlyIterator<'_, K, V, SliceBuffer<'_>> {
1219        KeyOnlyIterator::new_sync(self, pos)
1220    }
1221
1222    fn seek<'a>(&'a self, bound: Bound<&K>) -> Result<Iterator<'a, K, V, SliceBuffer<'a>>, Error> {
1223        seek_impl!(self, bound)
1224    }
1225}
1226
1227/// Unwraps the encryption key for `object_id` if a `LayerPager` is active on `store`.
1228async fn unwrap_layer_key(
1229    store: &ObjectStore,
1230    object_id: u64,
1231    crypt: &dyn Crypt,
1232) -> Result<Option<UnwrappedKey>, Error> {
1233    if store.filesystem().layer_pager().is_none() {
1234        return Ok(None);
1235    }
1236    let keys = store
1237        .get_keys(object_id)
1238        .await
1239        .with_context(|| format!("Failed to get keys for layer file {object_id}"))?;
1240    let (_, key) = keys
1241        .first()
1242        .ok_or_else(|| anyhow!(FxfsError::Inconsistent))
1243        .with_context(|| format!("Missing key for encrypted layer file {object_id}"))?;
1244    let wrapped_key = WrappedKey::from(key.clone());
1245    let unwrapped = crypt
1246        .unwrap_key(&wrapped_key, object_id)
1247        .await
1248        .with_context(|| format!("Failed to unwrap key for layer file {object_id}"))?;
1249    Ok(Some(unwrapped))
1250}
1251
1252/// Opens a persistent layer from a newly created or existing `DataObjectHandle`.
1253///
1254/// If the layer is encrypted and the platform uses a pager, `unwrapped_key` is registered with the
1255/// pager and dropped immediately.
1256pub async fn layer_from_handle<K: Key, V: LayerValue>(
1257    handle: DataObjectHandle<ObjectStore>,
1258    unwrapped_key: Option<UnwrappedKey>,
1259) -> Result<Arc<dyn Layer<K, V>>, Error> {
1260    PersistentLayer::open_handle(handle, unwrapped_key).await
1261}
1262
1263/// Opens persistent layers for `object_ids` from `store`.
1264///
1265/// Returns `(layers, total_size)` where `layers` is the vector of opened `Layer` trait objects and
1266/// `total_size` is the sum of the sizes in bytes of all opened layer objects.
1267pub async fn open_layers<K: Key, V: LayerValue>(
1268    store: &Arc<ObjectStore>,
1269    object_ids: impl IntoIterator<Item = u64>,
1270    crypt: Option<Arc<dyn Crypt>>,
1271) -> Result<(Vec<Arc<dyn Layer<K, V>>>, u64), Error> {
1272    let mut layers = Vec::new();
1273    let mut total_size = 0;
1274    for object_id in object_ids {
1275        let handle =
1276            ObjectStore::open_object(store, object_id, HandleOptions::default(), crypt.clone())
1277                .await
1278                .with_context(|| format!("Failed to open layer file {object_id}"))?;
1279        total_size += handle.get_size();
1280        let unwrapped_key = if let Some(crypt) = &crypt {
1281            unwrap_layer_key(store, object_id, crypt.as_ref()).await?
1282        } else {
1283            None
1284        };
1285        layers.push(PersistentLayer::open_handle(handle, unwrapped_key).await?);
1286    }
1287    Ok((layers, total_size))
1288}
1289
1290#[async_trait]
1291impl<K: Key, V: LayerValue> Layer<K, V> for PersistentLayer<K, V> {
1292    fn handle(&self) -> Option<&dyn LayerObject> {
1293        Some(self.object_handle.source())
1294    }
1295
1296    fn purge_cached_data(&self) {
1297        self.object_handle.purge();
1298    }
1299
1300    fn clear_cached_data(&self) {
1301        self.object_handle.clear();
1302    }
1303
1304    async fn seek<'a>(&'a self, bound: Bound<&K>) -> Result<BoxedLayerIterator<'a, K, V>, Error> {
1305        Ok(Box::new(PersistentLayer::seek(self, bound).await?))
1306    }
1307
1308    fn len(&self) -> usize {
1309        self.data.num_items
1310    }
1311
1312    fn maybe_contains_key(&self, key: &K) -> MaybeContainsKey {
1313        self.data.bloom_filter.as_ref().map_or(MaybeContainsKey::Maybe, |f| f.maybe_contains(key))
1314    }
1315
1316    fn has_bloom_filter(&self) -> bool {
1317        self.data.bloom_filter.is_some()
1318    }
1319
1320    async fn key_exists(&self, key: &K) -> Result<Existence, Error> {
1321        match &self.data.bloom_filter {
1322            Some(filter) => Ok(match filter.maybe_contains(key) {
1323                MaybeContainsKey::False => Existence::Missing,
1324                MaybeContainsKey::Maybe | MaybeContainsKey::RangeKeyTooLarge => {
1325                    Existence::MaybeExists
1326                }
1327            }),
1328            None => {
1329                let iter = self.seek(Bound::Included(key)).await?;
1330                Ok(iter.get().map_or(Existence::Missing, |i| {
1331                    if i.key.cmp_upper_bound(key).is_eq() {
1332                        Existence::Exists
1333                    } else {
1334                        Existence::Missing
1335                    }
1336                }))
1337            }
1338        }
1339    }
1340
1341    fn lock(&self) -> Option<Arc<DropEvent>> {
1342        self.data.close_event.lock().clone()
1343    }
1344
1345    async fn close(&self) {
1346        let listener = self.data.close_event.lock().take().expect("close already called").listen();
1347        listener.await;
1348        self.object_handle.source().close().await;
1349    }
1350
1351    fn get_version(&self) -> Version {
1352        return self.data.version;
1353    }
1354
1355    fn record_inspect_data(self: Arc<Self>, node: &fuchsia_inspect::Node) {
1356        node.record_uint("num_items", self.data.num_items as u64);
1357        node.record_bool("persistent", true);
1358        node.record_uint("size", self.object_handle.source().get_size());
1359        if let Some(stats) = self.data.bloom_filter_stats.as_ref() {
1360            node.record_child("bloom_filter", move |node| {
1361                node.record_uint("size", stats.size as u64);
1362                node.record_uint("num_hashes", stats.num_hashes as u64);
1363                node.record_uint("fill_percentage", stats.fill_percentage as u64);
1364            });
1365        }
1366    }
1367}
1368
1369#[async_trait]
1370impl<K: Key, V: LayerValue> Layer<K, V> for SyncPersistentLayer<K, V> {
1371    fn handle(&self) -> Option<&dyn LayerObject> {
1372        Some(&self.object_handle)
1373    }
1374
1375    fn purge_cached_data(&self) {
1376        self.object_handle.purge_cached_data();
1377    }
1378
1379    fn clear_cached_data(&self) {
1380        self.object_handle.purge_cached_data();
1381    }
1382
1383    async fn seek<'a>(&'a self, bound: Bound<&K>) -> Result<BoxedLayerIterator<'a, K, V>, Error> {
1384        Ok(Box::new(SyncPersistentLayer::seek(self, bound)?))
1385    }
1386
1387    fn len(&self) -> usize {
1388        self.data.num_items
1389    }
1390
1391    fn maybe_contains_key(&self, key: &K) -> MaybeContainsKey {
1392        self.data.bloom_filter.as_ref().map_or(MaybeContainsKey::Maybe, |f| f.maybe_contains(key))
1393    }
1394
1395    fn has_bloom_filter(&self) -> bool {
1396        self.data.bloom_filter.is_some()
1397    }
1398
1399    async fn key_exists(&self, key: &K) -> Result<Existence, Error> {
1400        match &self.data.bloom_filter {
1401            Some(filter) => Ok(match filter.maybe_contains(key) {
1402                MaybeContainsKey::False => Existence::Missing,
1403                MaybeContainsKey::Maybe | MaybeContainsKey::RangeKeyTooLarge => {
1404                    Existence::MaybeExists
1405                }
1406            }),
1407            None => {
1408                let iter = self.seek(Bound::Included(key))?;
1409                Ok(iter.get().map_or(Existence::Missing, |i| {
1410                    if i.key.cmp_upper_bound(key).is_eq() {
1411                        Existence::Exists
1412                    } else {
1413                        Existence::Missing
1414                    }
1415                }))
1416            }
1417        }
1418    }
1419
1420    fn lock(&self) -> Option<Arc<DropEvent>> {
1421        self.data.close_event.lock().clone()
1422    }
1423
1424    async fn close(&self) {
1425        let listener = self.data.close_event.lock().take().expect("close already called").listen();
1426        listener.await;
1427        self.object_handle.close().await;
1428    }
1429
1430    fn get_version(&self) -> Version {
1431        return self.data.version;
1432    }
1433
1434    fn record_inspect_data(self: Arc<Self>, node: &fuchsia_inspect::Node) {
1435        node.record_uint("num_items", self.data.num_items as u64);
1436        node.record_bool("persistent", true);
1437        node.record_uint("size", self.object_handle.get_size());
1438        if let Some(stats) = self.data.bloom_filter_stats.as_ref() {
1439            node.record_child("bloom_filter", move |node| {
1440                node.record_uint("size", stats.size as u64);
1441                node.record_uint("num_hashes", stats.num_hashes as u64);
1442                node.record_uint("fill_percentage", stats.fill_percentage as u64);
1443            });
1444        }
1445    }
1446}
1447
1448// This ensures that item_count can't be overflowed below.
1449const_assert!(MAX_BLOCK_SIZE.size() <= u16::MAX as u64 + 1);
1450
1451// -- Writer support --
1452
1453pub struct PersistentLayerWriter<W: WriteBytes, K: Key, V: LayerValue> {
1454    writer: W,
1455    version: Version,
1456    block_size: BlockSize,
1457    buf: Vec<u8>,
1458    buf_item_count: LayerWriterBufItemCount,
1459    item_count: usize,
1460    block_offsets: Vec<u16>,
1461    block_keys: Vec<u64>,
1462    bloom_filter: BloomFilterWriter<K>,
1463    _value: PhantomData<V>,
1464}
1465
1466impl<W: WriteBytes, K: Key, V: LayerValue> PersistentLayerWriter<W, K, V> {
1467    /// Creates a new writer that will serialize items to the object accessible via |object_handle|
1468    pub async fn new(writer: W, num_items: usize, block_size: BlockSize) -> Result<Self, Error> {
1469        Self::new_with_version(writer, num_items, block_size, LATEST_VERSION).await
1470    }
1471
1472    pub(crate) async fn new_with_version(
1473        mut writer: W,
1474        num_items: usize,
1475        block_size: BlockSize,
1476        version: Version,
1477    ) -> Result<Self, Error> {
1478        ensure!(block_size <= MAX_BLOCK_SIZE, FxfsError::NotSupported);
1479        ensure!(block_size >= MIN_BLOCK_SIZE, FxfsError::NotSupported);
1480
1481        // Write the header block.
1482        let header =
1483            LayerHeader { magic: PERSISTENT_LAYER_MAGIC.clone(), block_size: block_size.get() };
1484        let mut buf = vec![0u8; block_size.get() as usize];
1485        {
1486            let mut cursor = std::io::Cursor::new(&mut buf[..]);
1487            version.serialize_into(&mut cursor)?;
1488            header.serialize_into(&mut cursor)?;
1489        }
1490        writer.write_bytes(&buf[..]).await?;
1491
1492        let seed: u64 = rand::random();
1493        Ok(Self {
1494            writer,
1495            version,
1496            block_size,
1497            buf: Vec::new(),
1498            buf_item_count: LayerWriterBufItemCount(0),
1499            item_count: 0,
1500            block_offsets: Vec::new(),
1501            block_keys: Vec::new(),
1502            bloom_filter: BloomFilterWriter::new(seed, num_items),
1503            _value: PhantomData,
1504        })
1505    }
1506
1507    /// Writes `self.buf` out as a block.
1508    ///
1509    /// Blocks are fixed size, consisting of a 16-bit item count, data, zero padding
1510    /// and seek table at the end.
1511    async fn write_block(&mut self) -> Result<(), Error> {
1512        if *self.buf_item_count == 0 {
1513            return Ok(());
1514        }
1515        let seek_table_size = self.block_offsets.len() * PER_DATA_BLOCK_SEEK_ENTRY_SIZE;
1516        assert!(
1517            PER_DATA_BLOCK_HEADER_SIZE + seek_table_size + self.buf.len()
1518                <= self.block_size.get() as usize
1519        );
1520        let mut cursor = std::io::Cursor::new(vec![0u8; self.block_size.get() as usize]);
1521        cursor.write_u16::<LittleEndian>(*self.buf_item_count)?;
1522        cursor.write_all(&self.buf)?;
1523        cursor.set_position(self.block_size - seek_table_size as u64);
1524        // Write the seek table. Entries are 2 bytes each and items are always at least 10.
1525        for &offset in &self.block_offsets {
1526            cursor.write_u16::<LittleEndian>(offset)?;
1527        }
1528        self.writer.write_bytes(cursor.get_ref()).await?;
1529        debug!(item_count = *self.buf_item_count, byte_count = self.buf.len(); "wrote items");
1530        self.buf.clear();
1531        *self.buf_item_count = 0;
1532        self.block_offsets.clear();
1533        Ok(())
1534    }
1535
1536    // Assumes the writer is positioned to a new block.
1537    // Returns the size, in bytes, of the seek table.
1538    // Note that the writer will be positioned to exactly the end of the seek table, not to the end
1539    // of a block.
1540    async fn write_seek_table(&mut self) -> Result<usize, Error> {
1541        let keys = if self.version <= OLD_KEY_SERIALIZATION_VERSION {
1542            self.block_keys.get(1..).unwrap_or(&[])
1543        } else {
1544            &self.block_keys
1545        };
1546        if keys.len() == 0 {
1547            return Ok(0);
1548        }
1549        let size = keys.len() * std::mem::size_of::<u64>();
1550        self.buf.resize(size, 0);
1551        let mut len = 0;
1552        for key in keys {
1553            LittleEndian::write_u64(&mut self.buf[len..len + std::mem::size_of::<u64>()], *key);
1554            len += std::mem::size_of::<u64>();
1555        }
1556        self.writer.write_bytes(&self.buf).await?;
1557        Ok(size)
1558    }
1559
1560    // Assumes the writer is positioned to exactly the end of the seek table, which was
1561    // `seek_table_len` bytes.
1562    async fn write_info(
1563        &mut self,
1564        num_data_blocks: u64,
1565        bloom_filter_size_bytes: usize,
1566        seek_table_len: usize,
1567    ) -> Result<(), Error> {
1568        let block_size = self.writer.block_size().get() as usize;
1569        let layer_info = LayerInfo {
1570            num_items: self.item_count,
1571            num_data_blocks,
1572            bloom_filter_size_bytes,
1573            bloom_filter_seed: self.bloom_filter.seed(),
1574            bloom_filter_num_hashes: self.bloom_filter.num_hashes(),
1575        };
1576        self.buf.clear();
1577        layer_info.serialize_into(&mut self.buf)?;
1578        let layer_info_len = self.buf.len() as u64;
1579        self.buf.write_u64::<LittleEndian>(layer_info_len)?;
1580        let actual_len = self.buf.len();
1581
1582        // We want the LayerInfo to be at the end of the last block.  That might require creating a
1583        // new block if we don't have enough room.
1584        let avail_in_block =
1585            block_size - (seek_table_len as u64 % self.writer.block_size()) as usize;
1586        let to_skip = if avail_in_block < actual_len {
1587            block_size + avail_in_block - actual_len
1588        } else {
1589            avail_in_block - actual_len
1590        };
1591        self.buf.resize(to_skip + actual_len, 0);
1592        self.buf.copy_within(0..actual_len, to_skip);
1593        self.buf[..to_skip].fill(0);
1594        self.writer.write_bytes(&self.buf).await?;
1595        Ok(())
1596    }
1597
1598    // Assumes the writer is positioned to a new block.
1599    // Returns the size of the bloom filter, in bytes.
1600    async fn write_bloom_filter(&mut self) -> Result<usize, Error> {
1601        if self.data_blocks() == 0 || self.bloom_filter.serialized_size() == 0 {
1602            return Ok(0);
1603        }
1604        // TODO(https://fxbug.dev/323571978): Avoid bounce-buffering.
1605        let size =
1606            self.block_size.align_up(self.bloom_filter.serialized_size() as u64).unwrap() as usize;
1607        self.buf.resize(size, 0);
1608        let mut cursor = std::io::Cursor::new(&mut self.buf);
1609        self.bloom_filter.write(&mut cursor)?;
1610        self.writer.write_bytes(&self.buf).await?;
1611        Ok(self.bloom_filter.serialized_size())
1612    }
1613
1614    // Returns the bloom filter writer. Intended to be used for testing purposes, e.g., gain access
1615    // to the bloom filter to then corrupt it.
1616    #[cfg(test)]
1617    pub(crate) fn bloom_filter(&mut self) -> &mut BloomFilterWriter<K> {
1618        &mut self.bloom_filter
1619    }
1620
1621    fn serialize_item(&mut self, item: ItemRef<'_, K, V>) -> Result<(), Error> {
1622        if self.version <= OLD_KEY_SERIALIZATION_VERSION {
1623            item.key.serialize_into(&mut self.buf)?;
1624        } else {
1625            item.key.serialize_key_with_base_into(&mut self.buf, *self.block_keys.last().unwrap());
1626        }
1627        item.value.serialize_into(&mut self.buf)?;
1628        Ok(())
1629    }
1630
1631    fn data_blocks(&self) -> usize {
1632        self.block_keys.len()
1633    }
1634}
1635
1636impl<W: WriteBytes + Send, K: Key, V: LayerValue> LayerWriter<K, V>
1637    for PersistentLayerWriter<W, K, V>
1638{
1639    async fn write(&mut self, item: ItemRef<'_, K, V>) -> Result<(), Error> {
1640        // Note the length before we write this item.
1641        let len = self.buf.len();
1642        // Each data block's keys are delta-encoded relative to the leading u64 of that block's
1643        // first key (stored in `block_keys`). Record the base key for the first block here before
1644        // serializing; for subsequent blocks, `block_keys` is updated below when a block overflows.
1645        if self.block_keys.is_empty() {
1646            self.block_keys.push(item.key.get_leading_u64());
1647        }
1648        self.serialize_item(item)?;
1649
1650        let mut added_offset = false;
1651        // Never record the first item. The offset is always the same.
1652        if *self.buf_item_count > 0 {
1653            self.block_offsets.push(u16::try_from(len + PER_DATA_BLOCK_HEADER_SIZE).unwrap());
1654            added_offset = true;
1655        }
1656
1657        // If writing the item took us over a block, flush the bytes in the buffer prior to this
1658        // item.
1659        if PER_DATA_BLOCK_HEADER_SIZE
1660            + self.buf.len()
1661            + (self.block_offsets.len() * PER_DATA_BLOCK_SEEK_ENTRY_SIZE)
1662            > self.block_size.get() as usize - 1
1663        {
1664            if added_offset {
1665                // Drop the recently added offset from the list. The latest item will be the first
1666                // on the next block and have a known offset there.
1667                self.block_offsets.pop();
1668            }
1669            self.buf.truncate(len);
1670            self.write_block().await?;
1671
1672            // Start a new block with `item` as its first entry and re-serialize using the new base.
1673            self.block_keys.push(item.key.get_leading_u64());
1674            self.serialize_item(item)?;
1675        }
1676
1677        self.bloom_filter.insert(&item.key);
1678        *self.buf_item_count += 1;
1679        self.item_count += 1;
1680        Ok(())
1681    }
1682
1683    async fn complete(mut self) -> Result<u64, Error> {
1684        self.write_block().await?;
1685        let data_blocks = self.data_blocks() as u64;
1686        let bloom_filter_len = self.write_bloom_filter().await?;
1687        let seek_table_len = self.write_seek_table().await?;
1688        self.write_info(data_blocks, bloom_filter_len, seek_table_len).await?;
1689        self.writer.complete().await
1690    }
1691}
1692
1693/// Logs a warning if this object is dropped and the contained value isn't 0.
1694#[repr(transparent)]
1695struct LayerWriterBufItemCount(u16);
1696
1697impl Drop for LayerWriterBufItemCount {
1698    fn drop(&mut self) {
1699        debug_assert!(self.0 == 0, "Dropping unwritten items; did you forget to call complete?");
1700        if self.0 > 0 {
1701            warn!("Dropping unwritten items; did you forget to call complete?");
1702        }
1703    }
1704}
1705
1706impl std::ops::Deref for LayerWriterBufItemCount {
1707    type Target = u16;
1708    fn deref(&self) -> &u16 {
1709        &self.0
1710    }
1711}
1712
1713impl std::ops::DerefMut for LayerWriterBufItemCount {
1714    fn deref_mut(&mut self) -> &mut u16 {
1715        &mut self.0
1716    }
1717}
1718
1719#[cfg(test)]
1720mod tests {
1721    use super::{
1722        BlockSize, FxfsError, LayerData, NUM_HEADER_BLOCKS, PersistentLayer, PersistentLayerWriter,
1723        SyncPersistentLayer,
1724    };
1725    use crate::filesystem::MAX_BLOCK_SIZE;
1726    use crate::lsm_tree::LayerIterator;
1727    use crate::lsm_tree::testing::TestKey;
1728    use crate::lsm_tree::types::{
1729        Existence, Item, ItemRef, Layer, LayerWriter, MaybeContainsKey, OrdUpperBound,
1730    };
1731    use crate::object_handle::{
1732        LayerObject, ObjectHandle, ReadObjectHandle, WriteBytes, WriteObjectHandle,
1733    };
1734    use crate::object_store::AttributeId;
1735    use crate::object_store::allocator::AllocatorKey;
1736    use crate::object_store::extent::{Extent, MIN_BLOCK_SIZE};
1737    use crate::object_store::object_record::ObjectKey;
1738    use crate::round::round_up;
1739    use crate::serialized_types::OLD_KEY_SERIALIZATION_VERSION;
1740    use crate::testing::fake_object::{FakeObject, FakeObjectHandle};
1741    use crate::testing::writer::Writer;
1742    use anyhow::Error;
1743    use async_trait::async_trait;
1744    use std::fmt::Debug;
1745    use std::ops::{Bound, Range};
1746    use std::sync::Arc;
1747    use std::sync::atomic::{AtomicBool, Ordering};
1748    use storage_device::buffer::{BufferFuture, MutableBufferRef};
1749
1750    impl<W: WriteBytes> Debug for PersistentLayerWriter<W, i32, i32> {
1751        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
1752            f.debug_struct("rPersistentLayerWriter")
1753                .field("block_size", &self.block_size)
1754                .field("item_count", &*self.buf_item_count)
1755                .finish()
1756        }
1757    }
1758
1759    #[fuchsia::test]
1760    async fn test_iterate_after_write() {
1761        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
1762        const ITEM_COUNT: i32 = 10000;
1763
1764        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1765        {
1766            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1767                Writer::new(&handle).await,
1768                ITEM_COUNT as usize * 4,
1769                BLOCK_SIZE,
1770            )
1771            .await
1772            .expect("writer new");
1773            for i in 0..ITEM_COUNT {
1774                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
1775            }
1776            writer.complete().await.expect("flush failed");
1777        }
1778        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1779        let mut iterator = layer.seek(Bound::Unbounded).await.expect("seek failed");
1780        for i in 0..ITEM_COUNT {
1781            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1782            assert_eq!((key, value), (&i, &i));
1783            iterator.advance().await.expect("failed to advance");
1784        }
1785        assert!(iterator.get().is_none());
1786    }
1787
1788    #[fuchsia::test]
1789    async fn test_seek_after_write() {
1790        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
1791        const ITEM_COUNT: i32 = 5000;
1792
1793        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1794        {
1795            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1796                Writer::new(&handle).await,
1797                ITEM_COUNT as usize * 18,
1798                BLOCK_SIZE,
1799            )
1800            .await
1801            .expect("writer new");
1802            for i in 0..ITEM_COUNT {
1803                // Populate every other value as an item.
1804                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
1805            }
1806            writer.complete().await.expect("flush failed");
1807        }
1808        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1809        // Search for all values to check the in-between values.
1810        for i in 0..ITEM_COUNT * 2 {
1811            // We've written every other value, we expect to get either the exact value searched
1812            // for, or the next one after it. So round up to the nearest multiple of 2.
1813            let expected = round_up(i, 2).unwrap();
1814            let mut iterator = layer.seek(Bound::Included(&i)).await.expect("failed to seek");
1815            // We've written values up to (N-1)*2=2*N-2, so when looking for 2*N-1 we'll go off the
1816            // end of the layer and get back no item.
1817            if i >= (ITEM_COUNT * 2) - 1 {
1818                assert!(iterator.get().is_none());
1819            } else {
1820                let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1821                assert_eq!((key, value), (&expected, &expected));
1822            }
1823
1824            // Check that we can advance to the next item.
1825            iterator.advance().await.expect("failed to advance");
1826            // The highest value is 2*N-2, searching for 2*N-3 will find the last value, and
1827            // advancing will go off the end of the layer and return no item. If there was
1828            // previously no item, then it will latch and always return no item.
1829            if i >= (ITEM_COUNT * 2) - 3 {
1830                assert!(iterator.get().is_none());
1831            } else {
1832                let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1833                let next = expected + 2;
1834                assert_eq!((key, value), (&next, &next));
1835            }
1836        }
1837    }
1838
1839    #[fuchsia::test]
1840    async fn test_seek_unbounded() {
1841        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
1842        const ITEM_COUNT: i32 = 1000;
1843
1844        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1845        {
1846            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1847                Writer::new(&handle).await,
1848                ITEM_COUNT as usize * 18,
1849                BLOCK_SIZE,
1850            )
1851            .await
1852            .expect("writer new");
1853            for i in 0..ITEM_COUNT {
1854                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
1855            }
1856            writer.complete().await.expect("flush failed");
1857        }
1858        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1859        let mut iterator = layer.seek(Bound::Unbounded).await.expect("failed to seek");
1860        let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1861        assert_eq!((key, value), (&0, &0));
1862
1863        // Check that we can advance to the next item.
1864        iterator.advance().await.expect("failed to advance");
1865        let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1866        assert_eq!((key, value), (&1, &1));
1867    }
1868
1869    #[fuchsia::test]
1870    async fn test_zero_items() {
1871        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
1872
1873        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1874        {
1875            let writer = PersistentLayerWriter::<_, i32, i32>::new(
1876                Writer::new(&handle).await,
1877                0,
1878                BLOCK_SIZE,
1879            )
1880            .await
1881            .expect("writer new");
1882            writer.complete().await.expect("flush failed");
1883        }
1884
1885        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1886        let iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1887            .seek(Bound::Unbounded)
1888            .await
1889            .expect("seek failed");
1890        assert!(iterator.get().is_none())
1891    }
1892
1893    #[fuchsia::test]
1894    async fn test_one_item() {
1895        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
1896
1897        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
1898        {
1899            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1900                Writer::new(&handle).await,
1901                1,
1902                BLOCK_SIZE,
1903            )
1904            .await
1905            .expect("writer new");
1906            writer.write(Item::new(42, 42).as_item_ref()).await.expect("write failed");
1907            writer.complete().await.expect("flush failed");
1908        }
1909
1910        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1911        {
1912            let mut iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1913                .seek(Bound::Unbounded)
1914                .await
1915                .expect("seek failed");
1916            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1917            assert_eq!((key, value), (&42, &42));
1918            iterator.advance().await.expect("failed to advance");
1919            assert!(iterator.get().is_none())
1920        }
1921        {
1922            let mut iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1923                .seek(Bound::Included(&30))
1924                .await
1925                .expect("seek failed");
1926            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1927            assert_eq!((key, value), (&42, &42));
1928            iterator.advance().await.expect("failed to advance");
1929            assert!(iterator.get().is_none())
1930        }
1931        {
1932            let mut iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1933                .seek(Bound::Included(&42))
1934                .await
1935                .expect("seek failed");
1936            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1937            assert_eq!((key, value), (&42, &42));
1938            iterator.advance().await.expect("failed to advance");
1939            assert!(iterator.get().is_none())
1940        }
1941        {
1942            let iterator = (layer.as_ref() as &dyn Layer<i32, i32>)
1943                .seek(Bound::Included(&43))
1944                .await
1945                .expect("seek failed");
1946            assert!(iterator.get().is_none())
1947        }
1948    }
1949
1950    #[fuchsia::test]
1951    async fn test_large_block_size() {
1952        // At the upper end of the supported size.
1953        const BLOCK_SIZE: BlockSize = MAX_BLOCK_SIZE;
1954        // Items will be 18 bytes, so fill up a few pages.
1955        let item_count: i32 = ((BLOCK_SIZE.get() as i32) / 18) * 3;
1956
1957        let handle = FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
1958        {
1959            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
1960                Writer::new(&handle).await,
1961                item_count as usize * 18,
1962                BLOCK_SIZE,
1963            )
1964            .await
1965            .expect("writer new");
1966            // Use large values to force varint encoding to use consistent space.
1967            for i in 2000000000..(2000000000 + item_count) {
1968                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
1969            }
1970            writer.complete().await.expect("flush failed");
1971        }
1972
1973        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
1974        let mut iterator = layer.seek(Bound::Unbounded).await.expect("seek failed");
1975        for i in 2000000000..(2000000000 + item_count) {
1976            let ItemRef { key, value, .. } = iterator.get().expect("missing item");
1977            assert_eq!((key, value), (&i, &i));
1978            iterator.advance().await.expect("failed to advance");
1979        }
1980        assert!(iterator.get().is_none());
1981    }
1982
1983    #[fuchsia::test]
1984    async fn test_overlarge_block_size() {
1985        // At the upper end of the supported size.
1986        const BLOCK_SIZE: BlockSize = BlockSize::from_u64(MAX_BLOCK_SIZE.size() * 2).unwrap();
1987
1988        let handle = FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
1989        PersistentLayerWriter::<_, i32, i32>::new(Writer::new(&handle).await, 0, BLOCK_SIZE)
1990            .await
1991            .expect_err("Creating writer with overlarge block size.");
1992    }
1993
1994    #[fuchsia::test]
1995    async fn test_seek_bound_excluded() {
1996        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
1997        const ITEM_COUNT: i32 = 10000;
1998
1999        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
2000        {
2001            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2002                Writer::new(&handle).await,
2003                ITEM_COUNT as usize * 18,
2004                BLOCK_SIZE,
2005            )
2006            .await
2007            .expect("writer new");
2008            for i in 0..ITEM_COUNT {
2009                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
2010            }
2011            writer.complete().await.expect("flush failed");
2012        }
2013        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
2014
2015        for i in 9982..ITEM_COUNT {
2016            let mut iterator = layer.seek(Bound::Excluded(&i)).await.expect("failed to seek");
2017            let i_plus_one = i + 1;
2018            if i_plus_one < ITEM_COUNT {
2019                let ItemRef { key, value, .. } = iterator.get().expect("missing item");
2020
2021                assert_eq!((key, value), (&i_plus_one, &i_plus_one));
2022
2023                // Check that we can advance to the next item.
2024                iterator.advance().await.expect("failed to advance");
2025                let i_plus_two = i + 2;
2026                if i_plus_two < ITEM_COUNT {
2027                    let ItemRef { key, value, .. } = iterator.get().expect("missing item");
2028                    assert_eq!((key, value), (&i_plus_two, &i_plus_two));
2029                } else {
2030                    assert!(iterator.get().is_none());
2031                }
2032            } else {
2033                assert!(iterator.get().is_none());
2034            }
2035        }
2036    }
2037
2038    /// Generates extent records for a given object_id (of size 1).
2039    /// This produces a series of records with the same leading_u64.
2040    /// Returns the generated items and the next available object_id.
2041    fn generate_extents(
2042        object_id: u64,
2043        base_offset: u64,
2044        count: u64,
2045    ) -> (Vec<Item<ObjectKey, u64>>, u64) {
2046        let mut items = Vec::new();
2047        for i in 0..count {
2048            items.push(Item::new(
2049                ObjectKey::extent(
2050                    object_id,
2051                    AttributeId::TEST_ID,
2052                    (base_offset + i) * MIN_BLOCK_SIZE..(base_offset + i + 1) * MIN_BLOCK_SIZE,
2053                ),
2054                object_id,
2055            ));
2056        }
2057        (items, object_id + 1)
2058    }
2059
2060    /// Generates objects object_ids over a range.
2061    /// This produced a series of records with unique leading_u64.
2062    /// Returns the generated items and the next available value for sequencing.
2063    fn generate_objects(object_id_range: Range<u64>) -> (Vec<Item<ObjectKey, u64>>, u64) {
2064        let mut items = Vec::new();
2065        let end = object_id_range.end;
2066        for object_id in object_id_range {
2067            items.push(Item::new(ObjectKey::object(object_id), object_id));
2068        }
2069        (items, end)
2070    }
2071
2072    // Create a large spread of data across several blocks to ensure that no part of the range is
2073    // lost by the partial search using the layer seek table.
2074    #[fuchsia::test]
2075    async fn test_block_seek_duplicate_leading_u64() {
2076        // At the upper end of the supported size.
2077        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2078        const ITEMS_PER_PHASE: u64 = 50;
2079
2080        let mut to_find = Vec::new();
2081
2082        let handle = FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2083        {
2084            let mut items = Vec::new();
2085            // Make all values take up maximum space for varint encoding.
2086            let mut object_id = u32::MAX as u64 + 1;
2087
2088            // First fill the front with duplicate object IDs, then look at the start,
2089            // middle and end of the range.
2090            {
2091                let base_extent_offset = 0;
2092                let (mut generated, next_object_id) =
2093                    generate_extents(object_id, base_extent_offset, ITEMS_PER_PHASE * 3);
2094                items.append(&mut generated);
2095                let count = ITEMS_PER_PHASE * 3;
2096                to_find.push(ObjectKey::extent(
2097                    object_id,
2098                    AttributeId::TEST_ID,
2099                    base_extent_offset * MIN_BLOCK_SIZE..(base_extent_offset + 1) * MIN_BLOCK_SIZE,
2100                ));
2101                to_find.push(ObjectKey::extent(
2102                    object_id,
2103                    AttributeId::TEST_ID,
2104                    (base_extent_offset + count / 2) * MIN_BLOCK_SIZE
2105                        ..(base_extent_offset + count / 2 + 1) * MIN_BLOCK_SIZE,
2106                ));
2107                to_find.push(ObjectKey::extent(
2108                    object_id,
2109                    AttributeId::TEST_ID,
2110                    (base_extent_offset + count - 1) * MIN_BLOCK_SIZE
2111                        ..(base_extent_offset + count) * MIN_BLOCK_SIZE,
2112                ));
2113                object_id = next_object_id;
2114            }
2115
2116            // Add some filler of all different leading u64.
2117            {
2118                let (mut generated, next_object_id) =
2119                    generate_objects(object_id..object_id + ITEMS_PER_PHASE * 3);
2120                items.append(&mut generated);
2121                object_id = next_object_id;
2122            }
2123
2124            // Fill the middle with duplicate object IDs, then look at the start,
2125            // middle and end of the range.
2126            {
2127                let base_extent_offset = 1000;
2128                let (mut generated, next_object_id) =
2129                    generate_extents(object_id, base_extent_offset, ITEMS_PER_PHASE * 3);
2130                items.append(&mut generated);
2131                let count = ITEMS_PER_PHASE * 3;
2132                to_find.push(ObjectKey::extent(
2133                    object_id,
2134                    AttributeId::TEST_ID,
2135                    base_extent_offset * MIN_BLOCK_SIZE..(base_extent_offset + 1) * MIN_BLOCK_SIZE,
2136                ));
2137                to_find.push(ObjectKey::extent(
2138                    object_id,
2139                    AttributeId::TEST_ID,
2140                    (base_extent_offset + count / 2) * MIN_BLOCK_SIZE
2141                        ..(base_extent_offset + count / 2 + 1) * MIN_BLOCK_SIZE,
2142                ));
2143                to_find.push(ObjectKey::extent(
2144                    object_id,
2145                    AttributeId::TEST_ID,
2146                    (base_extent_offset + count - 1) * MIN_BLOCK_SIZE
2147                        ..(base_extent_offset + count) * MIN_BLOCK_SIZE,
2148                ));
2149                object_id = next_object_id;
2150            }
2151
2152            // Add some filler of all different leading u64.
2153            {
2154                let (mut generated, next_object_id) =
2155                    generate_objects(object_id..object_id + ITEMS_PER_PHASE * 3);
2156                items.append(&mut generated);
2157                object_id = next_object_id;
2158            }
2159
2160            // Fill the end with duplicate object IDs, then look at the start,
2161            // middle and end of the range.
2162            {
2163                let base_extent_offset = 2000;
2164                let (mut generated, _) =
2165                    generate_extents(object_id, base_extent_offset, ITEMS_PER_PHASE * 3);
2166                items.append(&mut generated);
2167                let count = ITEMS_PER_PHASE * 3;
2168                to_find.push(ObjectKey::extent(
2169                    object_id,
2170                    AttributeId::TEST_ID,
2171                    base_extent_offset * MIN_BLOCK_SIZE..(base_extent_offset + 1) * MIN_BLOCK_SIZE,
2172                ));
2173                to_find.push(ObjectKey::extent(
2174                    object_id,
2175                    AttributeId::TEST_ID,
2176                    (base_extent_offset + count / 2) * MIN_BLOCK_SIZE
2177                        ..(base_extent_offset + count / 2 + 1) * MIN_BLOCK_SIZE,
2178                ));
2179                to_find.push(ObjectKey::extent(
2180                    object_id,
2181                    AttributeId::TEST_ID,
2182                    (base_extent_offset + count - 1) * MIN_BLOCK_SIZE
2183                        ..(base_extent_offset + count) * MIN_BLOCK_SIZE,
2184                ));
2185            }
2186
2187            // Sort items by cmp_upper_bound!
2188            items.sort_by(|a, b| a.key.cmp_upper_bound(&b.key));
2189
2190            let mut writer = PersistentLayerWriter::<_, ObjectKey, u64>::new(
2191                Writer::new(&handle).await,
2192                (3 * BLOCK_SIZE) as usize,
2193                BLOCK_SIZE,
2194            )
2195            .await
2196            .expect("writer new");
2197
2198            for item in items {
2199                writer.write(item.as_item_ref()).await.expect("write failed");
2200            }
2201
2202            writer.complete().await.expect("flush failed");
2203        }
2204
2205        let layer = PersistentLayer::<ObjectKey, u64>::open(handle).await.expect("new failed");
2206        for target in to_find {
2207            let iterator = layer.seek(Bound::Included(&target)).await.expect("failed to seek");
2208            let ItemRef { key, .. } = iterator.get().expect("missing item");
2209            assert_eq!(&target, key);
2210        }
2211    }
2212
2213    #[fuchsia::test]
2214    async fn test_two_seek_blocks() {
2215        // At the upper end of the supported size.
2216        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2217        const ITEMS_PER_PHASE: u64 = 50;
2218        const ITEM_COUNT: u64 = ITEMS_PER_PHASE * ((BLOCK_SIZE.size() / 8) + 2);
2219
2220        let mut to_find = Vec::new();
2221
2222        let handle = FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2223        {
2224            let mut writer = PersistentLayerWriter::<_, TestKey, u64>::new(
2225                Writer::new(&handle).await,
2226                ITEM_COUNT as usize * 18,
2227                BLOCK_SIZE,
2228            )
2229            .await
2230            .expect("writer new");
2231
2232            // Make all values take up maximum space for varint encoding.
2233            let initial_value = u32::MAX as u64 + 1;
2234            for i in 0..ITEM_COUNT {
2235                writer
2236                    .write(
2237                        Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
2238                            .as_item_ref(),
2239                    )
2240                    .await
2241                    .expect("write failed");
2242            }
2243            // Look at the start middle and end.
2244            to_find.push(TestKey(initial_value..initial_value));
2245            let middle = initial_value + ITEM_COUNT / 2;
2246            to_find.push(TestKey(middle..middle));
2247            let end = initial_value + ITEM_COUNT - 1;
2248            to_find.push(TestKey(end..end));
2249
2250            writer.complete().await.expect("flush failed");
2251        }
2252
2253        let layer = PersistentLayer::<TestKey, u64>::open(handle).await.expect("new failed");
2254        for target in to_find {
2255            let iterator = layer.seek(Bound::Included(&target)).await.expect("failed to seek");
2256            let ItemRef { key, .. } = iterator.get().expect("missing item");
2257            assert_eq!(&target, key);
2258        }
2259    }
2260
2261    // Verifies behaviour around creating full seek blocks, to ensure that it is able to be opened
2262    // and parsed afterward.
2263    #[fuchsia::test]
2264    async fn test_full_seek_block() {
2265        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2266        const ITEMS_PER_PHASE: u64 = 50;
2267
2268        // How many entries there are in a seek table block.
2269        const SEEK_TABLE_ENTRIES: u64 = BLOCK_SIZE.size() / 8;
2270
2271        // Number of entries to fill a seek block would need one more block of entries, but we're
2272        // starting low here on purpose to do a range and make sure we hit the size we are
2273        // interested in.
2274        const START_ENTRIES_COUNT: u64 = ITEMS_PER_PHASE * SEEK_TABLE_ENTRIES;
2275
2276        for entries in START_ENTRIES_COUNT..START_ENTRIES_COUNT + (ITEMS_PER_PHASE * 2) {
2277            let handle =
2278                FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2279            {
2280                let mut writer = PersistentLayerWriter::<_, TestKey, u64>::new(
2281                    Writer::new(&handle).await,
2282                    entries as usize,
2283                    BLOCK_SIZE,
2284                )
2285                .await
2286                .expect("writer new");
2287
2288                // Make all values take up maximum space for varint encoding.
2289                let initial_value = u32::MAX as u64 + 1;
2290                for i in 0..entries {
2291                    writer
2292                        .write(
2293                            Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
2294                                .as_item_ref(),
2295                        )
2296                        .await
2297                        .expect("write failed");
2298                }
2299
2300                writer.complete().await.expect("flush failed");
2301            }
2302            PersistentLayer::<TestKey, u64>::open(handle).await.expect("new failed");
2303        }
2304    }
2305
2306    #[fuchsia::test]
2307    async fn test_ignore_bloom_filter_on_older_versions() {
2308        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2309        const ITEM_COUNT: u64 = 250;
2310
2311        let old_version_handle =
2312            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2313        let current_version_handle =
2314            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2315        // Make all values take up maximum space for varint encoding.
2316        let initial_value = u32::MAX as u64 + 1;
2317        {
2318            let mut old_version_writer =
2319                PersistentLayerWriter::<_, TestKey, u64>::new_with_version(
2320                    Writer::new(&old_version_handle).await,
2321                    ITEM_COUNT as usize,
2322                    BLOCK_SIZE,
2323                    OLD_KEY_SERIALIZATION_VERSION,
2324                )
2325                .await
2326                .expect("writer new");
2327            let mut current_version_writer = PersistentLayerWriter::<_, TestKey, u64>::new(
2328                Writer::new(&current_version_handle).await,
2329                ITEM_COUNT as usize,
2330                BLOCK_SIZE,
2331            )
2332            .await
2333            .expect("writer new");
2334
2335            for i in 0..ITEM_COUNT {
2336                old_version_writer
2337                    .write(
2338                        Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
2339                            .as_item_ref(),
2340                    )
2341                    .await
2342                    .expect("write failed");
2343                current_version_writer
2344                    .write(
2345                        Item::new(TestKey(initial_value + i..initial_value + i), initial_value)
2346                            .as_item_ref(),
2347                    )
2348                    .await
2349                    .expect("write failed");
2350            }
2351
2352            old_version_writer.complete().await.expect("flush failed");
2353            current_version_writer.complete().await.expect("flush failed");
2354        }
2355
2356        let old_layer =
2357            PersistentLayer::<TestKey, u64>::open(old_version_handle).await.expect("open failed");
2358        let current_layer = PersistentLayer::<TestKey, u64>::open(current_version_handle)
2359            .await
2360            .expect("open failed");
2361        assert!(!old_layer.has_bloom_filter());
2362        assert!(current_layer.has_bloom_filter());
2363
2364        // Verify seeking works in both layers (including before the first block's key).
2365        let iter = old_layer.seek(Bound::Included(&TestKey(0..0))).await.expect("seek failed");
2366        let item = iter.get().expect("missing item");
2367        assert_eq!(item.key.0.start, initial_value);
2368
2369        let iter = current_layer.seek(Bound::Included(&TestKey(0..0))).await.expect("seek failed");
2370        let item = iter.get().expect("missing item");
2371        assert_eq!(item.key.0.start, initial_value);
2372
2373        let iter = old_layer.seek(Bound::Unbounded).await.expect("seek failed");
2374        let item = iter.get().expect("missing item");
2375        assert_eq!(item.key.0.start, initial_value);
2376
2377        let iter = current_layer.seek(Bound::Unbounded).await.expect("seek failed");
2378        let item = iter.get().expect("missing item");
2379        assert_eq!(item.key.0.start, initial_value);
2380
2381        let target_val = initial_value + ITEM_COUNT / 2;
2382        let iter = old_layer
2383            .seek(Bound::Included(&TestKey(target_val..target_val)))
2384            .await
2385            .expect("seek failed");
2386        let item = iter.get().expect("missing item");
2387        assert_eq!(item.key.0.start, target_val);
2388
2389        let iter = current_layer
2390            .seek(Bound::Included(&TestKey(target_val..target_val)))
2391            .await
2392            .expect("seek failed");
2393        let item = iter.get().expect("missing item");
2394        assert_eq!(item.key.0.start, target_val);
2395    }
2396
2397    #[fuchsia::test]
2398    async fn test_allocator_key_older_version_seek() {
2399        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2400        const ITEM_COUNT: u64 = 100;
2401
2402        let old_version_handle =
2403            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2404        let current_version_handle =
2405            FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2406        let step = MIN_BLOCK_SIZE.get();
2407        {
2408            let mut old_version_writer =
2409                PersistentLayerWriter::<_, AllocatorKey, i64>::new_with_version(
2410                    Writer::new(&old_version_handle).await,
2411                    ITEM_COUNT as usize,
2412                    BLOCK_SIZE,
2413                    OLD_KEY_SERIALIZATION_VERSION,
2414                )
2415                .await
2416                .expect("writer new");
2417            let mut current_version_writer = PersistentLayerWriter::<_, AllocatorKey, i64>::new(
2418                Writer::new(&current_version_handle).await,
2419                ITEM_COUNT as usize,
2420                BLOCK_SIZE,
2421            )
2422            .await
2423            .expect("writer new");
2424
2425            for i in 0..ITEM_COUNT {
2426                let key = AllocatorKey { device_range: Extent(i * step..(i + 1) * step) };
2427                old_version_writer
2428                    .write(Item::new(key.clone(), i as i64).as_item_ref())
2429                    .await
2430                    .expect("write failed");
2431                current_version_writer
2432                    .write(Item::new(key, i as i64).as_item_ref())
2433                    .await
2434                    .expect("write failed");
2435            }
2436
2437            old_version_writer.complete().await.expect("flush failed");
2438            current_version_writer.complete().await.expect("flush failed");
2439        }
2440
2441        let old_layer = PersistentLayer::<AllocatorKey, i64>::open(old_version_handle)
2442            .await
2443            .expect("open failed");
2444        let current_layer = PersistentLayer::<AllocatorKey, i64>::open(current_version_handle)
2445            .await
2446            .expect("open failed");
2447
2448        let target_idx = ITEM_COUNT / 2;
2449        let target_key =
2450            AllocatorKey { device_range: Extent(target_idx * step..(target_idx + 1) * step) };
2451
2452        let iter = old_layer.seek(Bound::Included(&target_key)).await.expect("seek failed");
2453        let item = iter.get().expect("missing item");
2454        assert_eq!(item.key, &target_key);
2455
2456        let iter = current_layer.seek(Bound::Included(&target_key)).await.expect("seek failed");
2457        let item = iter.get().expect("missing item");
2458        assert_eq!(item.key, &target_key);
2459    }
2460
2461    #[fuchsia::test]
2462    async fn test_small_layer_has_bloom_filter() {
2463        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_8KIB;
2464        const ITEM_COUNT: i32 = 10;
2465
2466        let handle = FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2467        {
2468            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2469                Writer::new(&handle).await,
2470                ITEM_COUNT as usize,
2471                BLOCK_SIZE,
2472            )
2473            .await
2474            .expect("writer new");
2475            for i in 0..ITEM_COUNT {
2476                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
2477            }
2478            writer.complete().await.expect("flush failed");
2479        }
2480        let layer =
2481            PersistentLayer::<i32, i32>::open_async(Arc::new(handle)).await.expect("new failed");
2482        assert_eq!(layer.data.data_size, BLOCK_SIZE.get());
2483        assert!(layer.has_bloom_filter());
2484        let mut missing_count = 0;
2485        for i in 0..ITEM_COUNT {
2486            assert_eq!(
2487                layer.key_exists(&(i * 2)).await.expect("key_exists failed"),
2488                Existence::MaybeExists
2489            );
2490            if layer.key_exists(&(i * 2 + 1)).await.expect("key_exists failed")
2491                == Existence::Missing
2492            {
2493                missing_count += 1;
2494            }
2495        }
2496        assert!(missing_count > ITEM_COUNT / 2);
2497    }
2498
2499    #[fuchsia::test]
2500    async fn test_key_exists_with_bloom_filter() {
2501        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2502        const ITEM_COUNT: i32 = 10000;
2503
2504        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
2505        {
2506            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2507                Writer::new(&handle).await,
2508                ITEM_COUNT as usize,
2509                BLOCK_SIZE,
2510            )
2511            .await
2512            .expect("writer new");
2513            for i in 0..ITEM_COUNT {
2514                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
2515            }
2516            writer.complete().await.expect("flush failed");
2517        }
2518        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("new failed");
2519        assert!(layer.has_bloom_filter());
2520
2521        for i in 0..ITEM_COUNT {
2522            // With a bloom filter, we expect MaybeExists for present keys.
2523            assert_eq!(
2524                layer.key_exists(&(i * 2)).await.expect("key_exists failed"),
2525                Existence::MaybeExists
2526            );
2527        }
2528
2529        // For missing keys, we expect Missing, but might get MaybeExists due to false positives.
2530        // We can at least assert it's NOT Exists.
2531        let mut missing_count = 0;
2532        for i in 0..ITEM_COUNT {
2533            let result = layer.key_exists(&(i * 2 + 1)).await.expect("key_exists failed");
2534            assert_ne!(result, Existence::Exists);
2535            if result == Existence::Missing {
2536                missing_count += 1;
2537            }
2538        }
2539        // We expect mostly Missing.
2540        assert!(missing_count > ITEM_COUNT / 2);
2541    }
2542
2543    #[fuchsia::test]
2544    async fn test_load_large_bloom_filter_multi_chunk() {
2545        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2546        // Sizing for 600_000 items creates a 2 MiB bloom filter (exceeding 1 MiB chunk size).
2547        const ESTIMATED_ITEMS: usize = 600_000;
2548        const WRITTEN_ITEMS: i32 = 2000;
2549
2550        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
2551        {
2552            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2553                Writer::new(&handle).await,
2554                ESTIMATED_ITEMS,
2555                BLOCK_SIZE,
2556            )
2557            .await
2558            .expect("writer new");
2559            for i in 0..WRITTEN_ITEMS {
2560                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
2561            }
2562            writer.complete().await.expect("flush failed");
2563        }
2564        let layer = PersistentLayer::<i32, i32>::open(handle).await.expect("open failed");
2565        assert!(layer.has_bloom_filter());
2566
2567        for i in 0..WRITTEN_ITEMS {
2568            assert_eq!(layer.maybe_contains_key(&(i * 2)), MaybeContainsKey::Maybe);
2569        }
2570        let mut false_count = 0;
2571        for i in 0..WRITTEN_ITEMS {
2572            if layer.maybe_contains_key(&(i * 2 + 1)) == MaybeContainsKey::False {
2573                false_count += 1;
2574            }
2575        }
2576        assert!(false_count > WRITTEN_ITEMS / 2);
2577    }
2578
2579    #[fuchsia::test]
2580    async fn test_clear_cached_data() {
2581        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2582        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
2583        {
2584            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2585                Writer::new(&handle).await,
2586                100,
2587                BLOCK_SIZE,
2588            )
2589            .await
2590            .expect("writer new");
2591            writer.write(Item::new(1, 1).as_item_ref()).await.expect("write failed");
2592            writer.complete().await.expect("flush failed");
2593        }
2594        let layer =
2595            PersistentLayer::<i32, i32>::open_async(Arc::new(handle)).await.expect("open failed");
2596        let iter = layer.seek(Bound::Unbounded).await.expect("seek failed");
2597        assert_eq!(iter.get().map(|i| (*i.key, *i.value)), Some((1, 1)));
2598        drop(iter);
2599
2600        assert!(layer.object_handle.try_read(BLOCK_SIZE.get() as usize).is_some());
2601
2602        layer.clear_cached_data();
2603
2604        assert!(layer.object_handle.try_read(BLOCK_SIZE.get() as usize).is_none());
2605    }
2606
2607    struct SliceLayerObject {
2608        handle: FakeObjectHandle,
2609        slice: Vec<u8>,
2610        io_error: AtomicBool,
2611        purged: AtomicBool,
2612        closed: AtomicBool,
2613    }
2614
2615    impl ObjectHandle for SliceLayerObject {
2616        fn object_id(&self) -> u64 {
2617            self.handle.object_id()
2618        }
2619        fn block_size(&self) -> BlockSize {
2620            self.handle.block_size()
2621        }
2622        fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
2623            self.handle.allocate_buffer(size)
2624        }
2625    }
2626
2627    #[async_trait]
2628    impl ReadObjectHandle for SliceLayerObject {
2629        async fn read_aligned(
2630            &self,
2631            offset: u64,
2632            buf: MutableBufferRef<'_>,
2633        ) -> Result<usize, Error> {
2634            self.handle.read_aligned(offset, buf).await
2635        }
2636        fn get_size(&self) -> u64 {
2637            self.handle.get_size()
2638        }
2639    }
2640
2641    #[async_trait]
2642    impl LayerObject for SliceLayerObject {
2643        fn as_slice(&self) -> Option<&[u8]> {
2644            Some(&self.slice)
2645        }
2646        fn has_io_error(&self) -> bool {
2647            self.io_error.load(Ordering::SeqCst)
2648        }
2649        fn purge_cached_data(&self) {
2650            self.purged.store(true, Ordering::SeqCst);
2651        }
2652        async fn close(&self) {
2653            self.closed.store(true, Ordering::SeqCst);
2654        }
2655    }
2656
2657    #[fuchsia::test]
2658    async fn test_sync_persistent_layer() {
2659        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2660        const ITEM_COUNT: i32 = 1000;
2661
2662        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
2663        {
2664            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2665                Writer::new(&handle).await,
2666                ITEM_COUNT as usize,
2667                BLOCK_SIZE,
2668            )
2669            .await
2670            .expect("writer new");
2671            for i in 0..ITEM_COUNT {
2672                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
2673            }
2674            writer.complete().await.expect("flush failed");
2675        }
2676
2677        let size = handle.get_size() as usize;
2678        let mut buf = handle.allocate_buffer(size).await;
2679        handle.read_aligned(0, buf.as_mut()).await.expect("read failed");
2680        let slice = buf.subslice(..).to_vec();
2681        drop(buf);
2682        let slice_obj = Arc::new(SliceLayerObject {
2683            handle,
2684            slice: slice.clone(),
2685            io_error: AtomicBool::new(false),
2686            purged: AtomicBool::new(false),
2687            closed: AtomicBool::new(false),
2688        });
2689
2690        let layer: Arc<dyn Layer<i32, i32>> =
2691            SyncPersistentLayer::<i32, i32>::open(slice_obj.clone()).expect("open failed");
2692        assert!(layer.has_bloom_filter());
2693        assert_eq!(layer.len(), ITEM_COUNT as usize);
2694
2695        // Unbounded iteration should complete synchronously (advance_dyn returns Ok(None)).
2696        let mut iter = layer.seek(Bound::Unbounded).await.expect("seek failed");
2697        for i in 0..ITEM_COUNT {
2698            let item = iter.get().expect("expected item");
2699            assert_eq!(*item.key, i * 2);
2700            assert_eq!(*item.value, i * 2);
2701            let fut = iter.advance_dyn().expect("advance_dyn failed");
2702            assert!(fut.is_none(), "SyncPersistentLayer iterator must advance synchronously");
2703        }
2704        assert!(iter.get().is_none());
2705
2706        // Seek Included and Excluded.
2707        let iter = layer.seek(Bound::Included(&500)).await.expect("seek included failed");
2708        assert_eq!(*iter.get().expect("expected item").key, 500);
2709
2710        let iter = layer.seek(Bound::Excluded(&500)).await.expect("seek excluded failed");
2711        assert_eq!(*iter.get().expect("expected item").key, 502);
2712
2713        let iter = layer.seek(Bound::Included(&501)).await.expect("seek non-existent failed");
2714        assert_eq!(*iter.get().expect("expected item").key, 502);
2715
2716        // Verify purge_cached_data delegates to LayerObject::purge_cached_data.
2717        assert!(!slice_obj.purged.load(Ordering::SeqCst));
2718        layer.purge_cached_data();
2719        assert!(slice_obj.purged.load(Ordering::SeqCst));
2720
2721        // Verify close delegates to LayerObject::close.
2722        assert!(!slice_obj.closed.load(Ordering::SeqCst));
2723        layer.close().await;
2724        assert!(slice_obj.closed.load(Ordering::SeqCst));
2725
2726        // Simulate zero-filled data block on disk corruption vs pager I/O error.
2727        let mut zeroed_slice = slice;
2728        let bs = BLOCK_SIZE.get() as usize;
2729        zeroed_slice[bs..bs * 2].fill(0);
2730        let zeroed_obj = Arc::new(SliceLayerObject {
2731            handle: FakeObjectHandle::new(Arc::new(FakeObject::new())),
2732            slice: zeroed_slice,
2733            io_error: AtomicBool::new(false),
2734            purged: AtomicBool::new(false),
2735            closed: AtomicBool::new(false),
2736        });
2737        // Write valid header/footer into the underlying FakeObjectHandle so LayerData::open
2738        // succeeds.
2739        let mut wbuf = zeroed_obj.handle.allocate_buffer(zeroed_obj.slice.len()).await;
2740        wbuf.as_mut_ptr_slice().copy_from_slice(&zeroed_obj.slice);
2741        zeroed_obj.handle.write_or_append(Some(0), wbuf.as_ref()).await.unwrap();
2742        drop(wbuf);
2743        let zeroed_layer =
2744            PersistentLayer::<i32, i32>::open_layer(zeroed_obj.clone()).await.expect("open failed");
2745
2746        // When `has_io_error()` is false, corruption returns `FxfsError::Inconsistent`
2747        // (`ZX_ERR_IO_DATA_INTEGRITY`).
2748        let err = zeroed_layer.seek(Bound::Unbounded).await.err().expect("seek should fail");
2749        assert!(FxfsError::Inconsistent.matches(&err), "expected Inconsistent, got {err:?}");
2750
2751        // When `has_io_error()` is true (signaled by `SUPPLY_ZEROES_ON_ERROR`), it returns
2752        // `zx_status::Status::IO` (`ZX_ERR_IO`).
2753        zeroed_obj.io_error.store(true, Ordering::SeqCst);
2754        let err = zeroed_layer.seek(Bound::Unbounded).await.err().expect("seek should fail");
2755        assert_eq!(
2756            err.root_cause().downcast_ref::<zx_status::Status>(),
2757            Some(&zx_status::Status::IO)
2758        );
2759    }
2760
2761    #[fuchsia::test]
2762    async fn test_open_from_slice() {
2763        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2764        const ITEM_COUNT: i32 = 500;
2765
2766        // 1. Handle without `as_slice()` returns `InvalidArgs`.
2767        let non_slice_handle: Arc<dyn LayerObject> =
2768            Arc::new(FakeObjectHandle::new(Arc::new(FakeObject::new())));
2769        let err = LayerData::<i32>::open_from_slice(&non_slice_handle)
2770            .err()
2771            .expect("open_from_slice should fail without slice");
2772        assert!(FxfsError::InvalidArgs.matches(&err));
2773
2774        // 2. Populated layer (with bloom filter and multiple data/seek table blocks) matches
2775        //    `LayerData::open`.
2776        let handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
2777        {
2778            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2779                Writer::new(&handle).await,
2780                ITEM_COUNT as usize,
2781                BLOCK_SIZE,
2782            )
2783            .await
2784            .expect("writer new");
2785            for i in 0..ITEM_COUNT {
2786                writer.write(Item::new(i * 2, i * 2).as_item_ref()).await.expect("write failed");
2787            }
2788            writer.complete().await.expect("flush failed");
2789        }
2790        let size = handle.get_size() as usize;
2791        let mut buf = handle.allocate_buffer(size).await;
2792        handle.read_aligned(0, buf.as_mut()).await.expect("read failed");
2793        let valid_slice = buf.subslice(..).to_vec();
2794        drop(buf);
2795
2796        let make_slice_obj = |slice: Vec<u8>, io_error: bool| -> Arc<dyn LayerObject> {
2797            Arc::new(SliceLayerObject {
2798                handle: FakeObjectHandle::new(Arc::new(FakeObject::new())),
2799                slice,
2800                io_error: AtomicBool::new(io_error),
2801                purged: AtomicBool::new(false),
2802                closed: AtomicBool::new(false),
2803            })
2804        };
2805
2806        let async_handle: Arc<dyn LayerObject> = Arc::new(handle);
2807        let expected_data = LayerData::<i32>::open(&async_handle).await.expect("open failed");
2808        let slice_data =
2809            LayerData::<i32>::open_from_slice(&make_slice_obj(valid_slice.clone(), false))
2810                .expect("open_from_slice failed");
2811        assert_eq!(slice_data.version, expected_data.version);
2812        assert_eq!(slice_data.block_size, expected_data.block_size);
2813        assert_eq!(slice_data.data_size, expected_data.data_size);
2814        assert_eq!(slice_data.seek_table, expected_data.seek_table);
2815        assert_eq!(slice_data.num_items, expected_data.num_items);
2816        assert!(slice_data.bloom_filter.is_some());
2817        for k in [0, 1, 250, 251, 998, 999] {
2818            assert_eq!(
2819                slice_data.bloom_filter.as_ref().unwrap().maybe_contains(&k),
2820                expected_data.bloom_filter.as_ref().unwrap().maybe_contains(&k)
2821            );
2822        }
2823
2824        // 3. Valid slice when `has_io_error()` is true fails with `zx_status::Status::IO`.
2825        let err = LayerData::<i32>::open_from_slice(&make_slice_obj(valid_slice.clone(), true))
2826            .err()
2827            .expect("open_from_slice should fail on io_error");
2828        assert_eq!(
2829            err.root_cause().downcast_ref::<zx_status::Status>(),
2830            Some(&zx_status::Status::IO)
2831        );
2832
2833        // 4. Empty (0-item) layer without bloom filter or seek table succeeds.
2834        let empty_handle = FakeObjectHandle::new(Arc::new(FakeObject::new()));
2835        {
2836            let writer = PersistentLayerWriter::<_, i32, i32>::new(
2837                Writer::new(&empty_handle).await,
2838                0,
2839                BLOCK_SIZE,
2840            )
2841            .await
2842            .expect("writer new");
2843            writer.complete().await.expect("flush failed");
2844        }
2845        let empty_size = empty_handle.get_size() as usize;
2846        let mut buf = empty_handle.allocate_buffer(empty_size).await;
2847        empty_handle.read_aligned(0, buf.as_mut()).await.expect("read failed");
2848        let empty_slice = buf.subslice(..).to_vec();
2849        drop(buf);
2850        let empty_data = LayerData::<i32>::open_from_slice(&make_slice_obj(empty_slice, false))
2851            .expect("open_from_slice on empty layer failed");
2852        assert_eq!(empty_data.num_items, 0);
2853        assert!(empty_data.seek_table.is_empty());
2854        assert!(empty_data.bloom_filter.is_none());
2855
2856        // 5. Corruption cases return `FxfsError::Inconsistent` when `has_io_error()` is false, and
2857        //    `zx_status::Status::IO` when `has_io_error()` is true.
2858        let bs = BLOCK_SIZE.get() as usize;
2859
2860        // 5a. Truncated slice (< block_size).
2861        let truncated = vec![0u8; bs / 2];
2862
2863        // 5b. Invalid magic in header (after 4-byte Version prefix).
2864        let mut bad_magic = valid_slice.clone();
2865        bad_magic[4..12].fill(0);
2866
2867        // 5c. Invalid LayerInfo length in last block.
2868        let mut bad_layer_info = valid_slice.clone();
2869        let len = bad_layer_info.len();
2870        bad_layer_info[len - 8..len].copy_from_slice(&u64::MAX.to_le_bytes());
2871
2872        // 5d. Out-of-order seek table entries.
2873        let mut bad_seek_table = valid_slice.clone();
2874        let num_data_blocks = (slice_data.data_size / BLOCK_SIZE) as usize;
2875        assert!(num_data_blocks >= 2);
2876        let bf_blocks = BLOCK_SIZE
2877            .align_up_to_blocks(slice_data.bloom_filter_stats.as_ref().unwrap().size as u64)
2878            as usize;
2879        let seek_offset = (NUM_HEADER_BLOCKS as usize + num_data_blocks + bf_blocks) * bs;
2880        bad_seek_table[seek_offset..seek_offset + 8].copy_from_slice(&100u64.to_le_bytes());
2881        bad_seek_table[seek_offset + 8..seek_offset + 16].copy_from_slice(&50u64.to_le_bytes());
2882
2883        for corrupted in [truncated, bad_magic, bad_layer_info, bad_seek_table] {
2884            let err = LayerData::<i32>::open_from_slice(&make_slice_obj(corrupted.clone(), false))
2885                .err()
2886                .expect("expected corruption error");
2887            assert!(FxfsError::Inconsistent.matches(&err), "expected Inconsistent, got {err:?}");
2888
2889            let err = LayerData::<i32>::open_from_slice(&make_slice_obj(corrupted, true))
2890                .err()
2891                .expect("expected I/O error");
2892            assert_eq!(
2893                err.root_cause().downcast_ref::<zx_status::Status>(),
2894                Some(&zx_status::Status::IO)
2895            );
2896        }
2897    }
2898
2899    #[fuchsia::test]
2900    async fn test_layer_block_size_gt_4k_falls_back_to_async_persistent_layer() {
2901        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_8KIB;
2902        let handle = FakeObjectHandle::new_with_block_size(Arc::new(FakeObject::new()), BLOCK_SIZE);
2903        {
2904            let mut writer = PersistentLayerWriter::<_, i32, i32>::new(
2905                Writer::new(&handle).await,
2906                10,
2907                BLOCK_SIZE,
2908            )
2909            .await
2910            .expect("writer new");
2911            for i in 0..10 {
2912                writer.write(Item::new(i, i).as_item_ref()).await.expect("write failed");
2913            }
2914            writer.complete().await.expect("flush failed");
2915        }
2916
2917        let size = handle.get_size() as usize;
2918        let mut buf = handle.allocate_buffer(size).await;
2919        handle.read_aligned(0, buf.as_mut()).await.expect("read failed");
2920        let slice = buf.subslice(..).to_vec();
2921        drop(buf);
2922        let slice_obj = Arc::new(SliceLayerObject {
2923            handle,
2924            slice,
2925            io_error: AtomicBool::new(false),
2926            purged: AtomicBool::new(false),
2927            closed: AtomicBool::new(false),
2928        });
2929
2930        // SyncPersistentLayer::open must reject layers with block_size > 4KiB.
2931        assert!(SyncPersistentLayer::<i32, i32>::open(slice_obj.clone()).is_err());
2932
2933        // PersistentLayer::open_layer must fall back to async PersistentLayer and succeed.
2934        let layer = PersistentLayer::<i32, i32>::open_layer(slice_obj).await.expect("open_layer");
2935        let mut iter = layer.seek(Bound::Unbounded).await.expect("seek");
2936        for i in 0..10 {
2937            assert_eq!(*iter.get().expect("item").key, i);
2938            iter.advance().await.expect("advance");
2939        }
2940        assert!(iter.get().is_none());
2941    }
2942}