Skip to main content

fxfs/object_store/
allocator.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! # The Allocator
6//!
7//! The allocator in Fxfs is filesystem-wide entity responsible for managing the allocation of
8//! regions of the device to "owners" (which are `ObjectStore`).
9//!
10//! Allocations are tracked in an LSMTree with coalescing used to merge neighboring allocations
11//! with the same properties (owner and reference count). As of writing, reference counting is not
12//! used. (Reference counts are intended for future use if/when snapshot support is implemented.)
13//!
14//! There are a number of important implementation features of the allocator that warrant further
15//! documentation.
16//!
17//! ## Byte limits
18//!
19//! Fxfs is a multi-volume filesystem. Fuchsia with fxblob currently uses two primary volumes -
20//! an unencrypted volume for blob storage and an encrypted volume for data storage.
21//! Byte limits ensure that no one volume can consume all available storage. This is important
22//! as software updates must always be possible (blobs) and conversely configuration data should
23//! always be writable (data).
24//!
25//! ## Reservation tracking
26//!
27//! Fxfs on Fuchsia leverages write-back caching which allows us to buffer writes in RAM until
28//! memory pressure, an explicit flush or a file close requires us to persist data to storage.
29//!
30//! To ensure that we do not over-commit in such cases (e.g. by writing many files to RAM only to
31//! find out tha there is insufficient disk to store them all), the allocator includes a simple
32//! reservation tracking mechanism.
33//!
34//! Reservation tracking is implemented hierarchically such that a reservation can portion out
35//! sub-reservations, each of which may be "reserved" or "forgotten" when it comes time to actually
36//! allocate space.
37//!
38//! ## Fixed locations
39//!
40//! The only fixed location files in Fxfs are the first 512kiB extents of the two superblocks that
41//! exist as the first things on the disk (i.e. The first 1MiB). The allocator manages these
42//! locations, but does so using a 'mark_allocated' method distinct from all other allocations in
43//! which the location is left up to the allocator.
44//!
45//! ## Deallocated unusable regions
46//!
47//! It is not legal to reuse a deallocated disk region until after a flush. Transactions
48//! are not guaranteed to be persisted until after a successful flush so any reuse of
49//! a region before then followed by power loss may lead to corruption.
50//!
51//! e.g. Consider if we deallocate a file, reuse its extent for another file, then crash after
52//! writing to the new file but not yet flushing the journal. At next mount we will have lost the
53//! transaction despite overwriting the original file's data, leading to inconsistency errors (data
54//! corruption).
55//!
56//! These regions are currently tracked in RAM in the allocator.
57//!
58//! ## Allocated but uncommitted regions
59//!
60//! These are allocated regions that are not (yet) persisted to disk. They are regular
61//! file allocations, but are not stored on persistent storage until their transaction is committed
62//! and safely flushed to disk.
63//!
64//! ## TRIMed unusable regions
65//!
66//! We periodically TRIM unallocated regions to give the SSD controller insight into which
67//! parts of the device contain data. We must avoid using temporary TRIM allocations that are held
68//! while we perform these operations.
69//!
70//! ## Volume deletion
71//!
72//! We make use of an optimisation in the case where an entire volume is deleted. In such cases,
73//! rather than individually deallocate all disk regions associated with that volume, we make
74//! note of the deletion and perform special merge operation on the next LSMTree compaction that
75//! filters out allocations for the deleted volume.
76//!
77//! This is designed to make dropping of volumes significantly cheaper, but it does add some
78//! additional complexity if implementing an allocator that implements data structures to track
79//! free space (rather than just allocated space).
80//!
81//! ## Image generation
82//!
83//! The Fuchsia build process requires building an initial filesystem image. In the case of
84//! fxblob-based boards, this is an Fxfs filesystem containing a volume with the base set of
85//! blobs required to bootstrap the system. When we build such an image, we want it to be as compact
86//! as possible as we're potentially packaging it up for distribution. To that end, our allocation
87//! strategy (or at least the strategy used for image generation) should prefer to allocate from the
88//! start of the device wherever possible.
89pub mod merge;
90pub mod strategy;
91
92use crate::drop_event::DropEvent;
93use crate::errors::FxfsError;
94use crate::filesystem::{ApplyContext, ApplyMode, FxFilesystem, JournalingObject, SyncOptions};
95use crate::log::*;
96use crate::lsm_tree::skip_list_layer::SkipListLayer;
97use crate::lsm_tree::types::{
98    FuzzyHash, Item, ItemRef, Layer, LayerIterator, LayerKey, MergeType, OrdLowerBound,
99    OrdUpperBound, SortByU64, Value,
100};
101use crate::lsm_tree::{LSMTree, Query, compact_with_iterator, layer_from_handle, open_layers};
102use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, ReadObjectHandle};
103use crate::object_store::object_manager::ReservationUpdate;
104use crate::object_store::transaction::{
105    AllocatorMutation, AssocObj, LockKey, Mutation, Options, ReservationOptions, Transaction,
106    WriteGuard, lock_keys,
107};
108use crate::object_store::{
109    DataObjectHandle, DirectWriter, Extent, HandleOptions, ObjectStore, ReservedId,
110};
111use crate::range::RangeExt;
112use crate::round::round_div;
113use crate::serialized_types::{
114    DEFAULT_MAX_SERIALIZED_RECORD_SIZE, LATEST_VERSION, Version, Versioned, VersionedLatest,
115};
116use anyhow::{Context, Error, anyhow, bail, ensure};
117use async_trait::async_trait;
118use either::Either::{Left, Right};
119use event_listener::EventListener;
120use fprint::TypeFingerprint;
121use fuchsia_inspect::HistogramProperty;
122use fuchsia_sync::Mutex;
123use futures::FutureExt;
124use futures::future::BoxFuture;
125use fxfs_macros::SerializeKey;
126use merge::{filter_marked_for_deletion, filter_tombstones, merge};
127use serde::{Deserialize, Serialize};
128use std::borrow::Borrow;
129use std::collections::{BTreeMap, HashSet, VecDeque};
130use std::hash::Hash;
131use std::marker::PhantomData;
132use std::num::{NonZero, Saturating};
133use std::ops::Range;
134use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
135use std::sync::{Arc, Weak};
136use storage_units::BlockSize;
137
138/// This trait is implemented by things that own reservations.
139pub trait ReservationOwner: Send + Sync {
140    /// Report that bytes are being released from the reservation back to the the |ReservationOwner|
141    /// where |owner_object_id| is the owner under the root object store associated with the
142    /// reservation.
143    fn release_reservation(&self, owner_object_id: Option<u64>, amount: u64);
144}
145
146/// A reservation guarantees that when it comes time to actually allocate, it will not fail due to
147/// lack of space.  Sub-reservations (a.k.a. holds) are possible which effectively allows part of a
148/// reservation to be set aside until it's time to commit.  Reservations do offer some
149/// thread-safety, but some responsibility is born by the caller: e.g. calling `forget` and
150/// `reserve` at the same time from different threads is unsafe. Reservations are have an
151/// |owner_object_id| which associates it with an object under the root object store that the
152/// reservation is accounted against.
153pub struct ReservationImpl<T: Borrow<U>, U: ReservationOwner + ?Sized> {
154    owner: T,
155    owner_object_id: Option<u64>,
156    inner: Mutex<ReservationInner>,
157    phantom: PhantomData<U>,
158}
159
160#[derive(Debug, Default)]
161struct ReservationInner {
162    // Amount currently held by this reservation.
163    amount: u64,
164
165    // Amount reserved by sub-reservations.
166    reserved: u64,
167}
168
169impl<T: Borrow<U>, U: ReservationOwner + ?Sized> std::fmt::Debug for ReservationImpl<T, U> {
170    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171        self.inner.lock().fmt(f)
172    }
173}
174
175impl<T: Borrow<U> + Clone + Send + Sync, U: ReservationOwner + ?Sized> ReservationImpl<T, U> {
176    pub fn new(owner: T, owner_object_id: Option<u64>, amount: u64) -> Self {
177        Self {
178            owner,
179            owner_object_id,
180            inner: Mutex::new(ReservationInner { amount, reserved: 0 }),
181            phantom: PhantomData,
182        }
183    }
184
185    pub fn owner(&self) -> &T {
186        &self.owner
187    }
188
189    pub fn owner_object_id(&self) -> Option<u64> {
190        self.owner_object_id
191    }
192
193    /// Returns the total amount of the reservation, not accounting for anything that might be held.
194    pub fn amount(&self) -> u64 {
195        self.inner.lock().amount
196    }
197
198    /// Adds more to the reservation.
199    pub fn add(&self, amount: u64) {
200        self.inner.lock().amount += amount;
201    }
202
203    /// Returns the entire amount of the reservation.  The caller is responsible for maintaining
204    /// consistency, i.e. updating counters, etc, and there can be no sub-reservations (an assert
205    /// will fire otherwise).
206    pub fn forget(&self) -> u64 {
207        let mut inner = self.inner.lock();
208        assert_eq!(inner.reserved, 0);
209        std::mem::take(&mut inner.amount)
210    }
211
212    /// Takes some of the reservation.  The caller is responsible for maintaining consistency,
213    /// i.e. updating counters, etc.  This will assert that the amount being forgotten does not
214    /// exceed the available reservation amount; the caller should ensure that this is the case.
215    pub fn forget_some(&self, amount: u64) {
216        let mut inner = self.inner.lock();
217        inner.amount -= amount;
218        assert!(inner.reserved <= inner.amount);
219    }
220
221    /// Returns a partial amount of the reservation. |amount| is passed the |limit| and should
222    /// return the amount, which can be zero.
223    fn reserve_with(&self, amount: impl FnOnce(u64) -> u64) -> ReservationImpl<&Self, Self> {
224        let mut inner = self.inner.lock();
225        let taken = amount(inner.amount - inner.reserved);
226        inner.reserved += taken;
227        ReservationImpl::new(self, self.owner_object_id, taken)
228    }
229
230    /// Reserves *exactly* amount if possible.
231    pub fn reserve(&self, amount: u64) -> Option<ReservationImpl<&Self, Self>> {
232        let mut inner = self.inner.lock();
233        if inner.amount - inner.reserved < amount {
234            None
235        } else {
236            inner.reserved += amount;
237            Some(ReservationImpl::new(self, self.owner_object_id, amount))
238        }
239    }
240
241    /// Commits a previously reserved amount from this reservation.  The caller is responsible for
242    /// ensuring the amount was reserved.
243    pub fn commit(&self, amount: u64) {
244        let mut inner = self.inner.lock();
245        inner.reserved -= amount;
246        inner.amount -= amount;
247    }
248
249    /// Returns some of the reservation.
250    pub fn give_back(&self, amount: u64) {
251        self.owner.borrow().release_reservation(self.owner_object_id, amount);
252        let mut inner = self.inner.lock();
253        inner.amount -= amount;
254        assert!(inner.reserved <= inner.amount);
255    }
256
257    /// Moves `amount` from this reservation to another reservation.
258    pub fn move_to<V: Borrow<W> + Clone + Send + Sync, W: ReservationOwner + ?Sized>(
259        &self,
260        other: &ReservationImpl<V, W>,
261        amount: u64,
262    ) {
263        assert_eq!(self.owner_object_id, other.owner_object_id());
264        let mut inner = self.inner.lock();
265        if let Some(amount) = inner.amount.checked_sub(amount) {
266            inner.amount = amount;
267        } else {
268            std::mem::drop(inner);
269            panic!("Insufficient reservation space");
270        }
271        other.add(amount);
272    }
273}
274
275impl<T: Borrow<U>, U: ReservationOwner + ?Sized> Drop for ReservationImpl<T, U> {
276    fn drop(&mut self) {
277        let inner = self.inner.get_mut();
278        assert_eq!(inner.reserved, 0);
279        let owner_object_id = self.owner_object_id;
280        if inner.amount > 0 {
281            self.owner
282                .borrow()
283                .release_reservation(owner_object_id, std::mem::take(&mut inner.amount));
284        }
285    }
286}
287
288impl<T: Borrow<U> + Send + Sync, U: ReservationOwner + ?Sized> ReservationOwner
289    for ReservationImpl<T, U>
290{
291    fn release_reservation(&self, owner_object_id: Option<u64>, amount: u64) {
292        // Sub-reservations should belong to the same owner (or lack thereof).
293        assert_eq!(owner_object_id, self.owner_object_id);
294        let mut inner = self.inner.lock();
295        assert!(inner.reserved >= amount, "{} >= {}", inner.reserved, amount);
296        inner.reserved -= amount;
297    }
298}
299
300pub type Reservation = ReservationImpl<Arc<dyn ReservationOwner>, dyn ReservationOwner>;
301
302pub type Hold<'a> = ReservationImpl<&'a Reservation, Reservation>;
303
304/// Our allocator implementation tracks extents with a reference count.  At time of writing, these
305/// reference counts should never exceed 1, but that might change with snapshots and clones.
306pub type AllocatorKey = AllocatorKeyV32;
307
308#[derive(
309    Clone,
310    Debug,
311    Deserialize,
312    Eq,
313    Hash,
314    Ord,
315    PartialEq,
316    PartialOrd,
317    Serialize,
318    TypeFingerprint,
319    SerializeKey,
320    Versioned,
321)]
322#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
323pub struct AllocatorKeyV32 {
324    pub device_range: Extent,
325}
326
327impl SortByU64 for AllocatorKey {
328    fn get_leading_u64(&self) -> u64 {
329        self.device_range.end / crate::object_store::extent::MIN_BLOCK_SIZE
330    }
331}
332
333const EXTENT_HASH_BUCKET_SIZE: BlockSize = BlockSize::SIZE_1MIB;
334
335pub struct AllocatorKeyPartitionIterator {
336    device_range: Range<u64>,
337}
338
339impl Iterator for AllocatorKeyPartitionIterator {
340    type Item = u64;
341
342    fn next(&mut self) -> Option<Self::Item> {
343        if self.device_range.start >= self.device_range.end {
344            None
345        } else {
346            let start = self.device_range.start;
347            self.device_range.start = start.saturating_add(EXTENT_HASH_BUCKET_SIZE.get());
348            let end = std::cmp::min(self.device_range.start, self.device_range.end);
349            let key = AllocatorKey { device_range: Extent(start..end) };
350            let hash = crate::stable_hash::stable_hash(key);
351            Some(hash)
352        }
353    }
354
355    fn size_hint(&self) -> (usize, Option<usize>) {
356        let len = if self.device_range.start >= self.device_range.end {
357            0
358        } else {
359            let diff = self.device_range.end - self.device_range.start;
360            let count = EXTENT_HASH_BUCKET_SIZE.align_up_to_blocks(diff);
361            usize::try_from(count).unwrap_or(usize::MAX)
362        };
363        (len, Some(len))
364    }
365}
366
367impl ExactSizeIterator for AllocatorKeyPartitionIterator {}
368
369impl FuzzyHash for AllocatorKey {
370    fn fuzzy_hash(&self) -> impl ExactSizeIterator<Item = u64> {
371        AllocatorKeyPartitionIterator {
372            device_range: EXTENT_HASH_BUCKET_SIZE.align_down(self.device_range.start)
373                ..EXTENT_HASH_BUCKET_SIZE.align_up(self.device_range.end).unwrap_or(u64::MAX),
374        }
375    }
376
377    fn is_range_key(&self) -> bool {
378        true
379    }
380}
381
382impl AllocatorKey {
383    /// Returns a search key for `merge_into` that finds any touching predecessor to coalesce with.
384    ///
385    /// Extents in the tree are sorted by `cmp_upper_bound` as `(end, -start)`:
386    ///
387    /// ```text
388    /// Tree:       [  Predecessor  ) [ Key to insert )
389    /// Offsets:    X              10                20
390    ///
391    /// Search key:                 | (10..10)
392    /// ```
393    ///
394    /// Searching with `10..10` has end=10, len=0. Because shorter extents sort earlier when
395    /// ends match, `10..10` sorts before any valid extent `X..10` (len > 0). This positions the
396    /// iterator at `X..10` so it can be merged with `10..20`.
397    pub fn lower_bound_for_merge_into(&self) -> AllocatorKey {
398        AllocatorKey { device_range: self.device_range.key_for_merge_into() }
399    }
400}
401
402impl LayerKey for AllocatorKey {
403    fn merge_type(&self) -> MergeType {
404        MergeType::OptimizedMerge
405    }
406
407    fn next_key(&self) -> Option<Self> {
408        Some(Self { device_range: Extent::search_key_from_offset(self.device_range.end) })
409    }
410
411    fn search_key(&self) -> Option<Self> {
412        Some(Self { device_range: self.device_range.search_key() })
413    }
414
415    fn is_search_key(&self) -> bool {
416        self.device_range.is_search_key()
417    }
418
419    fn overlaps(&self, other: &Self) -> bool {
420        self.device_range.overlaps(&other.device_range)
421    }
422}
423
424impl OrdUpperBound for AllocatorKey {
425    fn cmp_upper_bound(&self, other: &AllocatorKey) -> std::cmp::Ordering {
426        // Defer to cmp_upper_bound ordering provided by Extent type which
427        // uses (end, len) to order ranges.
428        self.device_range.cmp_upper_bound(&other.device_range)
429    }
430}
431
432impl OrdLowerBound for AllocatorKey {
433    fn cmp_lower_bound(&self, other: &AllocatorKey) -> std::cmp::Ordering {
434        // The ordering over range.end is significant here as it is used in
435        // the heap ordering that feeds into our merge function and
436        // a total ordering over range lets us remove a symmetry case from
437        // the allocator merge function.
438        self.device_range.cmp(&other.device_range)
439    }
440}
441
442/// Allocations are "owned" by a single ObjectStore and are reference counted
443/// (for future snapshot/clone support).
444pub type AllocatorValue = AllocatorValueV32;
445impl Value for AllocatorValue {
446    const DELETED_MARKER: Self = Self::None;
447}
448
449#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, TypeFingerprint, Versioned)]
450#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
451pub enum AllocatorValueV32 {
452    // Tombstone variant indicating an extent is no longer allocated.
453    None,
454    // Used when we know there are no possible allocations below us in the stack.
455    // This is currently all the time. We used to have a related Delta type but
456    // it has been removed due to correctness issues (https://fxbug.dev/42179428).
457    Abs { count: u64, owner_object_id: u64 },
458}
459
460pub type AllocatorItem = Item<AllocatorKey, AllocatorValue>;
461
462/// Serialized information about the allocator.
463pub type AllocatorInfo = AllocatorInfoV32;
464
465#[derive(Debug, Default, Clone, Deserialize, Serialize, TypeFingerprint, Versioned)]
466pub struct AllocatorInfoV32 {
467    /// Holds the set of layer file object_id for the LSM tree (newest first).
468    pub layers: Vec<u64>,
469    /// Maps from owner_object_id to bytes allocated.
470    pub allocated_bytes: BTreeMap<u64, u64>,
471    /// Set of owner_object_id that we should ignore if found in layer files.  For now, this should
472    /// always be empty on-disk because we always do full compactions.
473    pub marked_for_deletion: HashSet<u64>,
474    /// The limit for the number of allocates bytes per `owner_object_id` whereas the value. If
475    /// there is no limit present here for an `owner_object_id` assume it is max u64.
476    pub limit_bytes: BTreeMap<u64, u64>,
477}
478
479const MAX_ALLOCATOR_INFO_SERIALIZED_SIZE: usize = 131_072;
480
481/// Computes the target maximum extent size based on the block size of the allocator.
482pub fn max_extent_size_for_block_size(block_size: BlockSize) -> u64 {
483    // Each block in an extent contains an 8-byte checksum (which due to varint encoding is 9
484    // bytes), and a given extent record must be no larger DEFAULT_MAX_SERIALIZED_RECORD_SIZE.  We
485    // also need to leave a bit of room (arbitrarily, 64 bytes) for the rest of the extent's
486    // metadata.
487    block_size * ((DEFAULT_MAX_SERIALIZED_RECORD_SIZE - 64) / 9)
488}
489
490#[derive(Default)]
491struct AllocatorCounters {
492    num_flushes: u64,
493    last_flush_time: Option<std::time::SystemTime>,
494}
495
496pub struct Allocator {
497    filesystem: Weak<FxFilesystem>,
498    block_size: BlockSize,
499    device_size: u64,
500    object_id: u64,
501    max_extent_size_bytes: u64,
502    tree: LSMTree<AllocatorKey, AllocatorValue>,
503    // A list of allocations which are temporary; i.e. they are not actually stored in the LSM tree,
504    // but we still don't want to be able to allocate over them.  This layer is merged into the
505    // allocator's LSM tree whilst reading it, so the allocations appear to exist in the LSM tree.
506    // This is used in a few places, for example to hold back allocations that have been added to a
507    // transaction but are not yet committed yet, or to prevent the allocation of a deleted extent
508    // until the device is flushed.
509    temporary_allocations: Arc<SkipListLayer<AllocatorKey, AllocatorValue>>,
510    inner: Mutex<Inner>,
511    allocation_mutex: futures::lock::Mutex<()>,
512    counters: Mutex<AllocatorCounters>,
513    maximum_offset: AtomicU64,
514    allocations_allowed: AtomicBool,
515}
516
517/// Tracks the different stages of byte allocations for an individual owner.
518#[derive(Debug, Default, PartialEq)]
519struct ByteTracking {
520    /// This value is the up-to-date count of the number of allocated bytes per owner_object_id
521    /// whereas the value in `Info::allocated_bytes` is the value as it was when we last flushed.
522    /// This field should be regarded as *untrusted*; it can be invalid due to filesystem
523    /// inconsistencies, and this is why it is `Saturating<u64>` rather than just `u64`.  Any
524    /// computations that use this value should typically propagate `Saturating` so that it is clear
525    /// the value is *untrusted*.
526    allocated_bytes: Saturating<u64>,
527
528    /// This value is the number of bytes allocated to uncommitted allocations.
529    /// (Bytes allocated, but not yet persisted to disk)
530    uncommitted_allocated_bytes: u64,
531
532    /// This value is the number of bytes allocated to reservations.
533    reserved_bytes: u64,
534
535    /// Committed deallocations that we cannot use until they are flushed to the device.  Each entry
536    /// in this list is the log file offset at which it was committed and an array of deallocations
537    /// that occurred at that time.
538    committed_deallocated_bytes: u64,
539}
540
541impl ByteTracking {
542    // Returns the total number of bytes that are taken either from reservations, allocations or
543    // uncommitted allocations.
544    fn used_bytes(&self) -> Saturating<u64> {
545        self.allocated_bytes + Saturating(self.uncommitted_allocated_bytes + self.reserved_bytes)
546    }
547
548    // Returns the amount that is not available to be allocated, which includes actually allocated
549    // bytes, bytes that have been allocated for a transaction but the transaction hasn't committed
550    // yet, and bytes that have been deallocated, but the device hasn't been flushed yet so we can't
551    // reuse those bytes yet.
552    fn unavailable_bytes(&self) -> Saturating<u64> {
553        self.allocated_bytes
554            + Saturating(self.uncommitted_allocated_bytes)
555            + Saturating(self.committed_deallocated_bytes)
556    }
557
558    // Like `unavailable_bytes`, but treats as available the bytes which have been deallocated and
559    // require a device flush to be reused.
560    fn unavailable_after_sync_bytes(&self) -> Saturating<u64> {
561        self.allocated_bytes + Saturating(self.uncommitted_allocated_bytes)
562    }
563}
564
565#[derive(Debug)]
566struct CommittedDeallocation {
567    // The offset at which this deallocation was committed.
568    log_file_offset: u64,
569    // The device range being deallocated.
570    range: Range<u64>,
571    // The owning object id which originally allocated it.
572    owner_object_id: u64,
573}
574
575struct Inner {
576    info: AllocatorInfo,
577
578    /// The allocator can only be opened if there have been no allocations and it has not already
579    /// been opened or initialized.
580    opened: bool,
581
582    /// When we allocate a range from RAM, we add it to Allocator::temporary_allocations.
583    /// This layer is added to layer_set in rebuild_strategy and take_for trim so we don't assume
584    /// the range is available.
585    /// If we apply the mutation, we move it from `temporary_allocations` to the LSMTree.
586    /// If we drop the mutation, we just delete it from `temporary_allocations` and call `free`.
587    ///
588    /// We need to be very careful about races when we move the allocation into the LSMTree.
589    /// A layer_set is a snapshot in time of a set of layers. Say:
590    ///  1. `rebuild_strategy` takes a layer_set that includes the mutable layer.
591    ///  2. A compaction operation seals that mutable layer and creates a new mutable layer.
592    ///     Note that the layer_set in rebuild_strategy doesn't have this new mutable layer.
593    ///  3. An apply_mutation operation adds the allocation to the new mutable layer.
594    ///     It then removes the allocation from `temporary_allocations`.
595    ///  4. `rebuild_strategy` iterates the layer_set, missing both the temporary mutation AND
596    ///     the record in the new mutable layer, making the allocated range available for double
597    ///     allocation and future filesystem corruption.
598    ///
599    /// We don't have (or want) a means to lock compctions during rebuild_strategy operations so
600    /// to avoid this scenario, we can't remove from temporary_allocations when we apply a mutation.
601    /// Instead we add them to dropped_temporary_allocations and make the actual removals from
602    /// `temporary_allocations` while holding the allocator lock. Because rebuild_strategy only
603    /// runs with this lock held, this guarantees that we don't remove entries from temporary
604    /// mutations while also iterating over it.
605    ///
606    /// A related issue happens when we deallocate a range. We use temporary_allocations this time
607    /// to prevent reuse until after the deallocation has been successfully flushed.
608    /// In this scenario we don't want to call 'free()' until the range is ready to use again.
609    dropped_temporary_allocations: Vec<Range<u64>>,
610
611    /// The per-owner counters for bytes at various stages of the data life-cycle. From initial
612    /// reservation through until the bytes are unallocated and eventually uncommitted.
613    owner_bytes: BTreeMap<u64, ByteTracking>,
614
615    /// This value is the number of bytes allocated to reservations but not tracked as part of a
616    /// particular volume.
617    unattributed_reserved_bytes: u64,
618
619    /// Committed deallocations that we cannot use until they are flushed to the device.
620    committed_deallocated: VecDeque<CommittedDeallocation>,
621
622    /// Bytes which are currently being trimmed.  These can still be allocated from, but the
623    /// allocation will block until the current batch of trimming is finished.
624    trim_reserved_bytes: u64,
625
626    /// While a trim is being performed, this listener is set.  When the current batch of extents
627    /// being trimmed have been released (and trim_reserved_bytes is 0), this is signaled.
628    /// This should only be listened to while the allocation_mutex is held.
629    trim_listener: Option<EventListener>,
630
631    /// This controls how we allocate our free space to manage fragmentation.
632    strategy: strategy::BestFit,
633
634    /// Tracks the number of allocations of size 1,2,...63,>=64.
635    allocation_size_histogram: [u64; 64],
636    /// Tracks which size bucket triggers rebuild_strategy.
637    rebuild_strategy_trigger_histogram: [u64; 64],
638
639    /// This is distinct from the set contained in `info`.  New entries are inserted *after* a
640    /// device has been flushed (it is not safe to reuse the space taken by a deleted volume prior
641    /// to this) and are removed after a major compaction.
642    marked_for_deletion: HashSet<u64>,
643
644    /// The set of volumes deleted that are waiting for a sync.
645    volumes_deleted_pending_sync: HashSet<u64>,
646}
647
648impl Inner {
649    fn allocated_bytes(&self) -> Saturating<u64> {
650        let mut total = Saturating(0);
651        for (_, bytes) in &self.owner_bytes {
652            total += bytes.allocated_bytes;
653        }
654        total
655    }
656
657    fn uncommitted_allocated_bytes(&self) -> u64 {
658        self.owner_bytes.values().map(|x| &x.uncommitted_allocated_bytes).sum()
659    }
660
661    fn reserved_bytes(&self) -> u64 {
662        self.owner_bytes.values().map(|x| &x.reserved_bytes).sum::<u64>()
663            + self.unattributed_reserved_bytes
664    }
665
666    fn owner_id_limit_bytes(&self, owner_object_id: u64) -> u64 {
667        match self.info.limit_bytes.get(&owner_object_id) {
668            Some(v) => *v,
669            None => u64::MAX,
670        }
671    }
672
673    fn owner_id_bytes_left(&self, owner_object_id: u64) -> u64 {
674        let limit = self.owner_id_limit_bytes(owner_object_id);
675        let used = self.owner_bytes.get(&owner_object_id).map_or(Saturating(0), |b| b.used_bytes());
676        (Saturating(limit) - used).0
677    }
678
679    // Returns the amount that is not available to be allocated, which includes actually allocated
680    // bytes, bytes that have been allocated for a transaction but the transaction hasn't committed
681    // yet, and bytes that have been deallocated, but the device hasn't been flushed yet so we can't
682    // reuse those bytes yet.
683    fn unavailable_bytes(&self) -> Saturating<u64> {
684        let mut total = Saturating(0);
685        for (_, bytes) in &self.owner_bytes {
686            total += bytes.unavailable_bytes();
687        }
688        total
689    }
690
691    // Returns the total number of bytes that are taken either from reservations, allocations or
692    // uncommitted allocations.
693    fn used_bytes(&self) -> Saturating<u64> {
694        let mut total = Saturating(0);
695        for (_, bytes) in &self.owner_bytes {
696            total += bytes.used_bytes();
697        }
698        total + Saturating(self.unattributed_reserved_bytes)
699    }
700
701    // Like `unavailable_bytes`, but treats as available the bytes which have been deallocated and
702    // require a device flush to be reused.
703    fn unavailable_after_sync_bytes(&self) -> Saturating<u64> {
704        let mut total = Saturating(0);
705        for (_, bytes) in &self.owner_bytes {
706            total += bytes.unavailable_after_sync_bytes();
707        }
708        total
709    }
710
711    // Returns the number of bytes which will be available after the current batch of trimming
712    // completes.
713    fn bytes_available_not_being_trimmed(&self, device_size: u64) -> Result<u64, Error> {
714        device_size
715            .checked_sub(
716                (self.unavailable_after_sync_bytes() + Saturating(self.trim_reserved_bytes)).0,
717            )
718            .ok_or_else(|| anyhow!(FxfsError::Inconsistent))
719    }
720
721    fn add_reservation(&mut self, owner_object_id: Option<u64>, amount: u64) {
722        match owner_object_id {
723            Some(owner) => self.owner_bytes.entry(owner).or_default().reserved_bytes += amount,
724            None => self.unattributed_reserved_bytes += amount,
725        };
726    }
727
728    fn remove_reservation(&mut self, owner_object_id: Option<u64>, amount: u64) {
729        match owner_object_id {
730            Some(owner) => {
731                let owner_entry = self.owner_bytes.entry(owner).or_default();
732                assert!(
733                    owner_entry.reserved_bytes >= amount,
734                    "{} >= {}",
735                    owner_entry.reserved_bytes,
736                    amount
737                );
738                owner_entry.reserved_bytes -= amount;
739            }
740            None => {
741                assert!(
742                    self.unattributed_reserved_bytes >= amount,
743                    "{} >= {}",
744                    self.unattributed_reserved_bytes,
745                    amount
746                );
747                self.unattributed_reserved_bytes -= amount
748            }
749        };
750    }
751}
752
753/// A container for a set of extents which are known to be free and can be trimmed.  Returned by
754/// `take_for_trimming`.
755pub struct TrimmableExtents<'a> {
756    allocator: &'a Allocator,
757    extents: Vec<Range<u64>>,
758    // The allocator can subscribe to this event to wait until these extents are dropped.  This way,
759    // we don't fail an allocation attempt if blocks are tied up for trimming; rather, we just wait
760    // until the batch is finished with and then proceed.
761    _drop_event: DropEvent,
762}
763
764impl<'a> TrimmableExtents<'a> {
765    pub fn extents(&self) -> &Vec<Range<u64>> {
766        &self.extents
767    }
768
769    // Also returns an EventListener which is signaled when this is dropped.
770    fn new(allocator: &'a Allocator) -> (Self, EventListener) {
771        let drop_event = DropEvent::new();
772        let listener = drop_event.listen();
773        (Self { allocator, extents: vec![], _drop_event: drop_event }, listener)
774    }
775
776    fn add_extent(&mut self, extent: Range<u64>) {
777        self.extents.push(extent);
778    }
779}
780
781impl<'a> Drop for TrimmableExtents<'a> {
782    fn drop(&mut self) {
783        let mut inner = self.allocator.inner.lock();
784        for device_range in std::mem::take(&mut self.extents) {
785            inner.strategy.free(device_range.clone()).expect("drop trim extent");
786            self.allocator
787                .temporary_allocations
788                .erase(&AllocatorKey { device_range: Extent(device_range) });
789        }
790        inner.trim_reserved_bytes = 0;
791    }
792}
793
794impl Allocator {
795    pub fn new(filesystem: Arc<FxFilesystem>, object_id: u64) -> Allocator {
796        let block_size = filesystem.block_size();
797        // We expect device size to be a multiple of block size. Throw away any tail.
798        let device_size = block_size.align_down(filesystem.device().size());
799        if device_size != filesystem.device().size() {
800            warn!("Device size is not block aligned. Rounding down.");
801        }
802        let max_extent_size_bytes = max_extent_size_for_block_size(block_size);
803        let mut strategy = strategy::BestFit::default();
804        strategy.free(0..device_size).expect("new fs");
805        Allocator {
806            filesystem: Arc::downgrade(&filesystem),
807            block_size,
808            device_size,
809            object_id,
810            max_extent_size_bytes,
811            tree: LSMTree::new(merge, None),
812            temporary_allocations: SkipListLayer::new(1024),
813            inner: Mutex::new(Inner {
814                info: AllocatorInfo::default(),
815                opened: false,
816                dropped_temporary_allocations: Vec::new(),
817                owner_bytes: BTreeMap::new(),
818                unattributed_reserved_bytes: 0,
819                committed_deallocated: VecDeque::new(),
820                trim_reserved_bytes: 0,
821                trim_listener: None,
822                strategy,
823                allocation_size_histogram: [0; 64],
824                rebuild_strategy_trigger_histogram: [0; 64],
825                marked_for_deletion: HashSet::new(),
826                volumes_deleted_pending_sync: HashSet::new(),
827            }),
828            allocation_mutex: futures::lock::Mutex::new(()),
829            counters: Mutex::new(AllocatorCounters::default()),
830            maximum_offset: AtomicU64::new(0),
831            allocations_allowed: AtomicBool::new(filesystem.options().image_builder_mode.is_none()),
832        }
833    }
834
835    pub fn tree(&self) -> &LSMTree<AllocatorKey, AllocatorValue> {
836        &self.tree
837    }
838
839    /// Enables allocations.
840    /// This is only valid to call if the allocator was created in image builder mode.
841    pub fn enable_allocations(&self) {
842        self.allocations_allowed.store(true, Ordering::SeqCst);
843    }
844
845    /// Returns an iterator that yields all allocations, filtering out tombstones and any
846    /// owner_object_id that have been marked as deleted.  If `committed_marked_for_deletion` is
847    /// true, then filter using the committed volumes marked for deletion rather than the in-memory
848    /// copy which excludes volumes that have been deleted but there hasn't been a sync yet.
849    pub async fn filter<'a>(
850        &self,
851        iter: impl LayerIterator<AllocatorKey, AllocatorValue> + 'a,
852        committed_marked_for_deletion: bool,
853    ) -> Result<impl LayerIterator<AllocatorKey, AllocatorValue> + 'a, Error> {
854        let marked_for_deletion = {
855            let inner = self.inner.lock();
856            if committed_marked_for_deletion {
857                &inner.info.marked_for_deletion
858            } else {
859                &inner.marked_for_deletion
860            }
861            .clone()
862        };
863        let iter =
864            filter_marked_for_deletion(filter_tombstones(iter).await?, marked_for_deletion).await?;
865        Ok(iter)
866    }
867
868    /// A histogram of allocation request sizes.
869    /// The index into the array is 'number of blocks'.
870    /// The last bucket is a catch-all for larger allocation requests.
871    pub fn allocation_size_histogram(&self) -> [u64; 64] {
872        self.inner.lock().allocation_size_histogram
873    }
874
875    /// Creates a new (empty) allocator.
876    pub async fn create(&self, transaction: &mut Transaction<'_>) -> Result<(), Error> {
877        // Mark the allocator as opened before creating the file because creating a new
878        // transaction requires a reservation.
879        assert_eq!(std::mem::replace(&mut self.inner.lock().opened, true), false);
880
881        let filesystem = self.filesystem.upgrade().unwrap();
882        let root_store = filesystem.root_store();
883        ObjectStore::create_object_with_id(
884            &root_store,
885            transaction,
886            ReservedId::new(&root_store, NonZero::new(self.object_id()).unwrap()),
887            HandleOptions::default(),
888            None,
889        )?;
890        root_store.update_last_object_id(self.object_id());
891        Ok(())
892    }
893
894    // Opens the allocator.  This is not thread-safe; this should be called prior to
895    // replaying the allocator's mutations.
896    pub async fn open(self: &Arc<Self>) -> Result<(), Error> {
897        let filesystem = self.filesystem.upgrade().unwrap();
898        let root_store = filesystem.root_store();
899
900        self.inner.lock().strategy = strategy::BestFit::default();
901
902        let handle =
903            ObjectStore::open_object(&root_store, self.object_id, HandleOptions::default(), None)
904                .await
905                .context("Failed to open allocator object")?;
906
907        if handle.get_size() > 0 {
908            let serialized_info = handle
909                .contents(MAX_ALLOCATOR_INFO_SERIALIZED_SIZE)
910                .await
911                .context("Failed to read AllocatorInfo")?;
912            let mut cursor = std::io::Cursor::new(serialized_info);
913            let (info, _version) = AllocatorInfo::deserialize_with_version(&mut cursor)
914                .context("Failed to deserialize AllocatorInfo")?;
915
916            let (layers, total_size) = open_layers(&root_store, info.layers.iter().cloned(), None)
917                .await
918                .context("Failed to open allocator layer file")?;
919
920            {
921                let mut inner = self.inner.lock();
922
923                // Check allocated_bytes fits within the device.
924                let mut device_bytes = self.device_size;
925                for (&owner_object_id, &bytes) in &info.allocated_bytes {
926                    ensure!(
927                        bytes <= device_bytes,
928                        anyhow!(FxfsError::Inconsistent).context(format!(
929                            "Allocated bytes exceeds device size: {:?}",
930                            info.allocated_bytes
931                        ))
932                    );
933                    device_bytes -= bytes;
934
935                    inner.owner_bytes.entry(owner_object_id).or_default().allocated_bytes =
936                        Saturating(bytes);
937                }
938
939                inner.info = info;
940            }
941
942            self.tree.append_open_layers(layers);
943            self.filesystem
944                .upgrade()
945                .unwrap()
946                .object_manager()
947                .update_layer_size(self.object_id, total_size);
948        }
949
950        Ok(())
951    }
952
953    pub async fn on_replay_complete(self: &Arc<Self>) -> Result<(), Error> {
954        // We can assume the device has been flushed.
955        {
956            let mut inner = self.inner.lock();
957            inner.volumes_deleted_pending_sync.clear();
958            inner.marked_for_deletion = inner.info.marked_for_deletion.clone();
959        }
960
961        // Build free extent structure from disk. For now, we expect disks to have *some* free
962        // space at all times. This may change if we ever support mounting of read-only
963        // redistributable filesystem images.
964        if !self.rebuild_strategy().await.context("Build free extents")? {
965            if self.filesystem.upgrade().unwrap().options().read_only {
966                info!("Device contains no free space (read-only mode).");
967            } else {
968                info!("Device contains no free space.");
969                return Err(FxfsError::Inconsistent)
970                    .context("Device appears to contain no free space");
971            }
972        }
973
974        assert_eq!(std::mem::replace(&mut self.inner.lock().opened, true), false);
975        Ok(())
976    }
977
978    /// Walk all allocations to generate the set of free regions between allocations.
979    /// It is safe to re-run this on live filesystems but it should not be called concurrently
980    /// with allocations, trims or other rebuild_strategy invocations -- use allocation_mutex.
981    /// Returns true if the rebuild made changes to either the free ranges or overflow markers.
982    async fn rebuild_strategy(self: &Arc<Self>) -> Result<bool, Error> {
983        let mut changed = false;
984        let mut layer_set = self.tree.empty_layer_set();
985        layer_set.layers.push((self.temporary_allocations.clone() as Arc<dyn Layer<_, _>>).into());
986        self.tree.add_all_layers_to_layer_set(&mut layer_set);
987
988        let overflow_markers = self.inner.lock().strategy.overflow_markers();
989        self.inner.lock().strategy.reset_overflow_markers();
990
991        let mut to_add = Vec::new();
992        let mut merger = layer_set.merger();
993        let mut iter = self.filter(merger.query(Query::FullScan).await?, false).await?;
994        let mut last_offset = 0;
995        while last_offset < self.device_size {
996            let next_range = match iter.get() {
997                None => {
998                    assert!(last_offset <= self.device_size);
999                    let range = last_offset..self.device_size;
1000                    last_offset = self.device_size;
1001                    iter.advance().await?;
1002                    range
1003                }
1004                Some(ItemRef { key, .. }) => {
1005                    let device_range = &key.device_range;
1006                    if device_range.end < last_offset {
1007                        iter.advance().await?;
1008                        continue;
1009                    }
1010                    if device_range.start <= last_offset {
1011                        last_offset = device_range.end;
1012                        iter.advance().await?;
1013                        continue;
1014                    }
1015                    let range = last_offset..device_range.start;
1016                    last_offset = device_range.end;
1017                    iter.advance().await?;
1018                    range
1019                }
1020            };
1021            to_add.push(next_range);
1022            // Avoid taking a lock on inner for every free range.
1023            if to_add.len() > 100 {
1024                let mut inner = self.inner.lock();
1025                for range in to_add.drain(..) {
1026                    changed |= inner.strategy.force_free(range)?;
1027                }
1028            }
1029        }
1030        let mut inner = self.inner.lock();
1031        for range in to_add {
1032            changed |= inner.strategy.force_free(range)?;
1033        }
1034        if overflow_markers != inner.strategy.overflow_markers() {
1035            changed = true;
1036        }
1037        Ok(changed)
1038    }
1039
1040    /// Collects up to `extents_per_batch` free extents of size up to `max_extent_size` from
1041    /// `offset`.  The extents will be reserved.
1042    /// Note that only one `FreeExtents` can exist for the allocator at any time.
1043    pub async fn take_for_trimming(
1044        &self,
1045        offset: u64,
1046        max_extent_size: usize,
1047        extents_per_batch: usize,
1048    ) -> Result<TrimmableExtents<'_>, Error> {
1049        let _guard = self.allocation_mutex.lock().await;
1050
1051        let (mut result, listener) = TrimmableExtents::new(self);
1052        if offset >= self.device_size {
1053            return Ok(result);
1054        }
1055        let mut bytes = 0;
1056
1057        // We can't just use self.strategy here because it doesn't necessarily hold all
1058        // free extent metadata in RAM.
1059        let mut layer_set = self.tree.empty_layer_set();
1060        layer_set.layers.push((self.temporary_allocations.clone() as Arc<dyn Layer<_, _>>).into());
1061        self.tree.add_all_layers_to_layer_set(&mut layer_set);
1062        let mut merger = layer_set.merger();
1063        let mut iter = self
1064            .filter(
1065                merger
1066                    .query(Query::FullRange(&AllocatorKey {
1067                        device_range: Extent::search_key_from_offset(offset),
1068                    }))
1069                    .await?,
1070                false,
1071            )
1072            .await?;
1073        let mut last_offset = offset;
1074        'outer: while last_offset < self.device_size {
1075            let mut range = match iter.get() {
1076                None => {
1077                    assert!(last_offset <= self.device_size);
1078                    let range = last_offset..self.device_size;
1079                    last_offset = self.device_size;
1080                    iter.advance().await?;
1081                    range
1082                }
1083                Some(ItemRef { key: AllocatorKey { device_range, .. }, .. }) => {
1084                    if device_range.end <= last_offset {
1085                        iter.advance().await?;
1086                        continue;
1087                    }
1088                    if device_range.start <= last_offset {
1089                        last_offset = device_range.end;
1090                        iter.advance().await?;
1091                        continue;
1092                    }
1093                    let range = last_offset..device_range.start;
1094                    last_offset = device_range.end;
1095                    iter.advance().await?;
1096                    range
1097                }
1098            };
1099            if range.start < offset {
1100                continue;
1101            }
1102
1103            // 'range' is based on the on-disk LSM tree. We need to check against any uncommitted
1104            // allocations and remove temporarily allocate the range for ourselves.
1105            let mut inner = self.inner.lock();
1106
1107            while range.start < range.end {
1108                let prefix =
1109                    range.start..std::cmp::min(range.start + max_extent_size as u64, range.end);
1110                range = prefix.end..range.end;
1111                bytes += prefix.length()?;
1112                // We can assume the following are safe because we've checked both LSM tree and
1113                // temporary_allocations while holding the lock.
1114                inner.strategy.remove(prefix.clone());
1115                self.temporary_allocations.insert(AllocatorItem {
1116                    key: AllocatorKey { device_range: Extent(prefix.clone()) },
1117                    value: AllocatorValue::Abs { owner_object_id: INVALID_OBJECT_ID, count: 1 },
1118                })?;
1119                result.add_extent(prefix);
1120                if result.extents.len() == extents_per_batch {
1121                    break 'outer;
1122                }
1123            }
1124            if result.extents.len() == extents_per_batch {
1125                break 'outer;
1126            }
1127        }
1128        {
1129            let mut inner = self.inner.lock();
1130
1131            ensure!(inner.trim_reserved_bytes == 0, FxfsError::AlreadyBound);
1132            inner.trim_listener = Some(listener);
1133            inner.trim_reserved_bytes = bytes;
1134            debug_assert!(
1135                (Saturating(inner.trim_reserved_bytes) + inner.unavailable_bytes()).0
1136                    <= self.device_size
1137            );
1138        }
1139        Ok(result)
1140    }
1141
1142    /// Returns all objects that exist in the parent store that pertain to this allocator.
1143    pub fn parent_objects(&self) -> Vec<u64> {
1144        // The allocator tree needs to store a file for each of the layers in the tree, so we return
1145        // those, since nothing else references them.
1146        self.inner.lock().info.layers.clone()
1147    }
1148
1149    /// Returns all the current owner byte limits (in pairs of `(owner_object_id, bytes)`).
1150    pub fn owner_byte_limits(&self) -> Vec<(u64, u64)> {
1151        self.inner.lock().info.limit_bytes.iter().map(|(k, v)| (*k, *v)).collect()
1152    }
1153
1154    /// Returns (allocated_bytes, byte_limit) for the given owner.
1155    pub fn owner_allocation_info(&self, owner_object_id: u64) -> (u64, Option<u64>) {
1156        let inner = self.inner.lock();
1157        (
1158            inner.owner_bytes.get(&owner_object_id).map(|b| b.used_bytes().0).unwrap_or(0u64),
1159            inner.info.limit_bytes.get(&owner_object_id).copied(),
1160        )
1161    }
1162
1163    /// Returns owner bytes debug information.
1164    pub fn owner_bytes_debug(&self) -> String {
1165        format!("{:?}", self.inner.lock().owner_bytes)
1166    }
1167
1168    fn needs_sync(&self) -> bool {
1169        // TODO(https://fxbug.dev/42178048): This will only trigger if *all* free space is taken up with
1170        // committed deallocated bytes, but we might want to trigger a sync if we're low and there
1171        // happens to be a lot of deallocated bytes as that might mean we can fully satisfy
1172        // allocation requests.
1173        let inner = self.inner.lock();
1174        inner.unavailable_bytes().0 >= self.device_size
1175    }
1176
1177    fn is_system_store(&self, owner_object_id: u64) -> bool {
1178        self.filesystem.upgrade().unwrap().object_manager().is_system_store(owner_object_id)
1179    }
1180
1181    /// Updates the accounting to track that a byte reservation has been moved out of an owner to
1182    /// the unattributed pool.
1183    pub fn disown_reservation(&self, old_owner_object_id: Option<u64>, amount: u64) {
1184        if old_owner_object_id.is_none() || amount == 0 {
1185            return;
1186        }
1187        // These 2 mutations should behave as though they're a single atomic mutation.
1188        let mut inner = self.inner.lock();
1189        inner.remove_reservation(old_owner_object_id, amount);
1190        inner.add_reservation(None, amount);
1191    }
1192
1193    /// Creates a lazy inspect node named `str` under `parent` which will yield statistics for the
1194    /// allocator when queried.
1195    pub fn track_statistics(self: &Arc<Self>, parent: &fuchsia_inspect::Node, name: &str) {
1196        let this = Arc::downgrade(self);
1197        parent.record_lazy_child(name, move || {
1198            let this_clone = this.clone();
1199            async move {
1200                let inspector = fuchsia_inspect::Inspector::default();
1201                if let Some(this) = this_clone.upgrade() {
1202                    let counters = this.counters.lock();
1203                    let root = inspector.root();
1204                    root.record_uint("max_extent_size_bytes", this.max_extent_size_bytes);
1205                    root.record_uint("bytes_total", this.device_size);
1206                    let (allocated, reserved, used, unavailable) = {
1207                        // TODO(https://fxbug.dev/42069513): Push-back or rate-limit to prevent DoS.
1208                        let inner = this.inner.lock();
1209                        (
1210                            inner.allocated_bytes().0,
1211                            inner.reserved_bytes(),
1212                            inner.used_bytes().0,
1213                            inner.unavailable_bytes().0,
1214                        )
1215                    };
1216                    root.record_uint("bytes_allocated", allocated);
1217                    root.record_uint("bytes_reserved", reserved);
1218                    root.record_uint("bytes_used", used);
1219                    root.record_uint("bytes_unavailable", unavailable);
1220
1221                    // TODO(https://fxbug.dev/42068224): Post-compute rather than manually computing
1222                    // metrics.
1223                    if let Some(x) = round_div(100 * allocated, this.device_size) {
1224                        root.record_uint("bytes_allocated_percent", x);
1225                    }
1226                    if let Some(x) = round_div(100 * reserved, this.device_size) {
1227                        root.record_uint("bytes_reserved_percent", x);
1228                    }
1229                    if let Some(x) = round_div(100 * used, this.device_size) {
1230                        root.record_uint("bytes_used_percent", x);
1231                    }
1232                    if let Some(x) = round_div(100 * unavailable, this.device_size) {
1233                        root.record_uint("bytes_unavailable_percent", x);
1234                    }
1235
1236                    root.record_uint("num_flushes", counters.num_flushes);
1237                    if let Some(last_flush_time) = counters.last_flush_time.as_ref() {
1238                        root.record_uint(
1239                            "last_flush_time_ms",
1240                            last_flush_time
1241                                .duration_since(std::time::UNIX_EPOCH)
1242                                .unwrap_or(std::time::Duration::ZERO)
1243                                .as_millis()
1244                                .try_into()
1245                                .unwrap_or(0u64),
1246                        );
1247                    }
1248
1249                    let data = this.allocation_size_histogram();
1250                    let alloc_sizes = root.create_uint_linear_histogram(
1251                        "allocation_size_histogram",
1252                        fuchsia_inspect::LinearHistogramParams {
1253                            floor: 1,
1254                            step_size: 1,
1255                            buckets: 64,
1256                        },
1257                    );
1258                    for (i, count) in data.iter().enumerate() {
1259                        if i != 0 {
1260                            alloc_sizes.insert_multiple(i as u64, *count as usize);
1261                        }
1262                    }
1263                    root.record(alloc_sizes);
1264
1265                    let data = this.inner.lock().rebuild_strategy_trigger_histogram;
1266                    let triggers = root.create_uint_linear_histogram(
1267                        "rebuild_strategy_triggers",
1268                        fuchsia_inspect::LinearHistogramParams {
1269                            floor: 1,
1270                            step_size: 1,
1271                            buckets: 64,
1272                        },
1273                    );
1274                    for (i, count) in data.iter().enumerate() {
1275                        if i != 0 {
1276                            triggers.insert_multiple(i as u64, *count as usize);
1277                        }
1278                    }
1279                    root.record(triggers);
1280
1281                    let allocator_ref = this.clone();
1282                    root.record_child("lsm_tree", move |node| {
1283                        allocator_ref.tree.record_inspect_data(node);
1284                    });
1285                }
1286                Ok(inspector)
1287            }
1288            .boxed()
1289        });
1290    }
1291
1292    /// Returns the offset of the first byte which has not been used by the allocator since its
1293    /// creation.
1294    /// NB: This does *not* take into account existing allocations.  This is only reliable when the
1295    /// allocator was created from scratch, without any pre-existing allocations.
1296    pub fn maximum_offset(&self) -> u64 {
1297        self.maximum_offset.load(Ordering::Relaxed)
1298    }
1299}
1300
1301impl Drop for Allocator {
1302    fn drop(&mut self) {
1303        let inner = self.inner.lock();
1304        // Uncommitted and reserved should be released back using RAII, so they should be zero.
1305        assert_eq!(inner.uncommitted_allocated_bytes(), 0);
1306        assert_eq!(inner.reserved_bytes(), 0);
1307    }
1308}
1309
1310#[fxfs_trace::trace]
1311impl Allocator {
1312    /// Returns the object ID for the allocator.
1313    pub fn object_id(&self) -> u64 {
1314        self.object_id
1315    }
1316
1317    /// Returns information about the allocator such as the layer files storing persisted
1318    /// allocations.
1319    pub fn info(&self) -> AllocatorInfo {
1320        self.inner.lock().info.clone()
1321    }
1322
1323    fn reservation_description(&self, reservation: &Reservation) -> String {
1324        let metadata_info = self.filesystem.upgrade().and_then(|fs| {
1325            let om = fs.object_manager();
1326            if om.is_metadata_reservation(reservation) {
1327                Some((om.borrowed_metadata_space(), om.max_store_reservation()))
1328            } else {
1329                None
1330            }
1331        });
1332        match metadata_info {
1333            Some((borrowed, max_store_reservation)) => {
1334                format!(
1335                    "reservation with {} bytes available (borrowed metadata space: {}, max store \
1336                    reservation: {})",
1337                    reservation.amount(),
1338                    borrowed,
1339                    max_store_reservation
1340                )
1341            }
1342            None => {
1343                format!("reservation with {} bytes available", reservation.amount())
1344            }
1345        }
1346    }
1347
1348    /// Tries to allocate enough space for |object_range| in the specified object and returns the
1349    /// device range allocated.
1350    /// The allocated range may be short (e.g. due to fragmentation), in which case the caller can
1351    /// simply call allocate again until they have enough blocks.
1352    ///
1353    /// We also store the object store ID of the store that the allocation should be assigned to so
1354    /// that we have a means to delete encrypted stores without needing the encryption key.
1355    #[trace]
1356    pub async fn allocate(
1357        self: &Arc<Self>,
1358        transaction: &mut Transaction<'_>,
1359        owner_object_id: u64,
1360        mut len: u64,
1361    ) -> Result<Range<u64>, Error> {
1362        ensure!(self.allocations_allowed.load(Ordering::SeqCst), FxfsError::Unavailable);
1363        assert!(self.block_size.is_aligned(len));
1364        len = std::cmp::min(len, self.max_extent_size_bytes);
1365        debug_assert_ne!(owner_object_id, INVALID_OBJECT_ID);
1366
1367        let requested_len = len;
1368
1369        // Make sure we have space reserved before we try and find the space.
1370        let reservation = if let Some(reservation) =
1371            transaction.allocator_reservation(owner_object_id)
1372        {
1373            match reservation.owner_object_id {
1374                // If there is no owner, this must be a system store that we're allocating for.
1375                None => assert!(self.is_system_store(owner_object_id)),
1376                // If it has an owner, it should not be different than the allocating owner.
1377                Some(res_owner_object_id) => assert_eq!(owner_object_id, res_owner_object_id),
1378            };
1379            // Reservation limits aren't necessarily a multiple of the block size.
1380            let r = reservation
1381                .reserve_with(|limit| std::cmp::min(len, self.block_size.align_down(limit)));
1382            len = r.amount();
1383            Left(r)
1384        } else {
1385            assert!(
1386                !transaction.metadata_reservation.is_borrowed()
1387                    || self.filesystem.upgrade().unwrap().options().image_builder_mode.is_some(),
1388                "Allocations for non-system stores are not allowed in Borrowed transactions"
1389            );
1390            let mut inner = self.inner.lock();
1391            assert!(inner.opened);
1392            // Do not exceed the limit for the owner or the device.
1393            let device_used = inner.used_bytes();
1394            let owner_bytes_left = inner.owner_id_bytes_left(owner_object_id);
1395            // We must take care not to use up space that might be reserved.
1396            let limit =
1397                std::cmp::min(owner_bytes_left, (Saturating(self.device_size) - device_used).0);
1398            len = self.block_size.align_down(std::cmp::min(len, limit));
1399            let owner_entry = inner.owner_bytes.entry(owner_object_id).or_default();
1400            owner_entry.reserved_bytes += len;
1401            Right(ReservationImpl::<_, Self>::new(&**self, Some(owner_object_id), len))
1402        };
1403
1404        if len == 0 {
1405            if let Some(reservation) = transaction.allocator_reservation(owner_object_id) {
1406                bail!(anyhow!(FxfsError::NoSpace).context(format!(
1407                    "Failed to allocate {} bytes for owner {} from {}",
1408                    requested_len,
1409                    owner_object_id,
1410                    self.reservation_description(reservation),
1411                )));
1412            } else {
1413                let inner = self.inner.lock();
1414                bail!(anyhow!(FxfsError::NoSpace).context(format!(
1415                    "Failed to allocate {} bytes for owner {} (owner_bytes_left: {}, device_used: \
1416                    {}, device_size: {})",
1417                    requested_len,
1418                    owner_object_id,
1419                    inner.owner_id_bytes_left(owner_object_id),
1420                    inner.used_bytes(),
1421                    self.device_size
1422                )));
1423            }
1424        }
1425
1426        // If volumes have been deleted, flush the device so that we can use any of the freed space.
1427        let volumes_deleted = {
1428            let inner = self.inner.lock();
1429            (!inner.volumes_deleted_pending_sync.is_empty())
1430                .then(|| inner.volumes_deleted_pending_sync.clone())
1431        };
1432
1433        if let Some(volumes_deleted) = volumes_deleted {
1434            // No locks are held here, so in theory, there could be unnecessary syncs, but it
1435            // should be sufficiently rare that it won't matter.
1436            self.filesystem
1437                .upgrade()
1438                .unwrap()
1439                .sync(SyncOptions {
1440                    flush_device: true,
1441                    precondition: Some(Box::new(|| {
1442                        !self.inner.lock().volumes_deleted_pending_sync.is_empty()
1443                    })),
1444                    ..Default::default()
1445                })
1446                .await?;
1447
1448            {
1449                let mut inner = self.inner.lock();
1450                for owner_id in volumes_deleted {
1451                    inner.volumes_deleted_pending_sync.remove(&owner_id);
1452                    inner.marked_for_deletion.insert(owner_id);
1453                }
1454            }
1455
1456            let _guard = self.allocation_mutex.lock().await;
1457            self.rebuild_strategy().await?;
1458        }
1459
1460        #[allow(clippy::never_loop)] // Loop used as a for {} else {}.
1461        let _guard = 'sync: loop {
1462            // Cap number of sync attempts before giving up on finding free space.
1463            for _ in 0..10 {
1464                {
1465                    let guard = self.allocation_mutex.lock().await;
1466
1467                    if !self.needs_sync() {
1468                        break 'sync guard;
1469                    }
1470                }
1471
1472                // All the free space is currently tied up with deallocations, so we need to sync
1473                // and flush the device to free that up.
1474                //
1475                // We can't hold the allocation lock whilst we sync here because the allocation lock
1476                // is also taken in apply_mutations, which is called when journal locks are held,
1477                // and we call sync here which takes those same locks, so it would have the
1478                // potential to result in a deadlock.  Sync holds its own lock to guard against
1479                // multiple syncs occurring at the same time, and we can supply a precondition that
1480                // is evaluated under that lock to ensure we don't sync twice if we don't need to.
1481                self.filesystem
1482                    .upgrade()
1483                    .unwrap()
1484                    .sync(SyncOptions {
1485                        flush_device: true,
1486                        precondition: Some(Box::new(|| self.needs_sync())),
1487                        ..Default::default()
1488                    })
1489                    .await?;
1490            }
1491            bail!(
1492                anyhow!(FxfsError::NoSpace).context("Sync failed to yield sufficient free space.")
1493            );
1494        };
1495
1496        let mut trim_listener = None;
1497        {
1498            let mut inner = self.inner.lock();
1499            inner.allocation_size_histogram[std::cmp::min(63, len / self.block_size) as usize] += 1;
1500
1501            // If trimming would be the reason that this allocation gets cut short, wait for
1502            // trimming to complete before proceeding.
1503            let avail = self
1504                .device_size
1505                .checked_sub(inner.unavailable_bytes().0)
1506                .ok_or(FxfsError::Inconsistent)?;
1507            let free_and_not_being_trimmed =
1508                inner.bytes_available_not_being_trimmed(self.device_size)?;
1509            if free_and_not_being_trimmed < std::cmp::min(len, avail) {
1510                debug_assert!(inner.trim_reserved_bytes > 0);
1511                trim_listener = std::mem::take(&mut inner.trim_listener);
1512            }
1513        }
1514
1515        if let Some(listener) = trim_listener {
1516            listener.await;
1517        }
1518
1519        let result = loop {
1520            {
1521                let mut inner = self.inner.lock();
1522
1523                // While we know rebuild_strategy and take_for_trim are not running (we hold guard),
1524                // apply temporary_allocation removals.
1525                for device_range in inner.dropped_temporary_allocations.drain(..) {
1526                    self.temporary_allocations
1527                        .erase(&AllocatorKey { device_range: Extent(device_range) });
1528                }
1529
1530                match inner.strategy.allocate(len) {
1531                    Err(FxfsError::NotFound) => {
1532                        // Overflow. Fall through and rebuild
1533                        inner.rebuild_strategy_trigger_histogram
1534                            [std::cmp::min(63, (len / self.block_size) as usize)] += 1;
1535                    }
1536                    Err(err) => {
1537                        error!(err:%; "Likely filesystem corruption.");
1538                        return Err(err.into());
1539                    }
1540                    Ok(x) => {
1541                        break x;
1542                    }
1543                }
1544            }
1545            // We've run out of extents of the requested length in RAM but there
1546            // exists more of this size on device. Rescan device and circle back.
1547            // We already hold the allocation_mutex, so exclusive access is guaranteed.
1548            if !self.rebuild_strategy().await? {
1549                error!("Cannot find additional free space. Corruption?");
1550                return Err(FxfsError::Inconsistent.into());
1551            }
1552        };
1553
1554        debug!(device_range:? = result; "allocate");
1555
1556        let len = result.length().unwrap();
1557        let reservation_owner = reservation.either(
1558            // Left means we got an outside reservation.
1559            |l| {
1560                l.forget_some(len);
1561                l.owner_object_id()
1562            },
1563            |r| {
1564                r.forget_some(len);
1565                r.owner_object_id()
1566            },
1567        );
1568
1569        {
1570            let mut inner = self.inner.lock();
1571            let owner_entry = inner.owner_bytes.entry(owner_object_id).or_default();
1572            owner_entry.uncommitted_allocated_bytes += len;
1573            // If the reservation has an owner, ensure they are the same.
1574            assert_eq!(owner_object_id, reservation_owner.unwrap_or(owner_object_id));
1575            inner.remove_reservation(reservation_owner, len);
1576            self.temporary_allocations.insert(AllocatorItem {
1577                key: AllocatorKey { device_range: Extent(result.clone()) },
1578                value: AllocatorValue::Abs { owner_object_id, count: 1 },
1579            })?;
1580        }
1581
1582        let mutation =
1583            AllocatorMutation::Allocate { device_range: result.clone().into(), owner_object_id };
1584        assert!(transaction.add(self.object_id(), Mutation::Allocator(mutation)).is_none());
1585
1586        Ok(result)
1587    }
1588
1589    /// Marks the given device range as allocated.  The main use case for this at this time is for
1590    /// the super-block which needs to be at a fixed location on the device.
1591    #[trace]
1592    pub fn mark_allocated(
1593        &self,
1594        transaction: &mut Transaction<'_>,
1595        owner_object_id: u64,
1596        device_range: Range<u64>,
1597    ) -> Result<(), Error> {
1598        debug_assert_ne!(owner_object_id, INVALID_OBJECT_ID);
1599        {
1600            let len = device_range.length().map_err(|_| FxfsError::InvalidArgs)?;
1601            let reservation = transaction.allocator_reservation(owner_object_id);
1602
1603            let mut inner = self.inner.lock();
1604            let device_used = inner.used_bytes();
1605            let owner_id_bytes_left = inner.owner_id_bytes_left(owner_object_id);
1606            let owner_entry = inner.owner_bytes.entry(owner_object_id).or_default();
1607            ensure!(
1608                device_range.end <= self.device_size
1609                    && (Saturating(self.device_size) - device_used).0 >= len
1610                    && owner_id_bytes_left >= len,
1611                anyhow!(FxfsError::NoSpace).context(format!(
1612                    "Failed to allocate {} bytes at {:?} for owner {} (owner_bytes_left: {}, \
1613                    device_used: {}, device_size: {})",
1614                    len,
1615                    device_range,
1616                    owner_object_id,
1617                    owner_id_bytes_left,
1618                    device_used,
1619                    self.device_size
1620                ))
1621            );
1622            if let Some(reservation) = reservation {
1623                // The transaction takes ownership of this hold.
1624                reservation
1625                    .reserve(len)
1626                    .ok_or_else(|| {
1627                        anyhow!(FxfsError::NoSpace).context(format!(
1628                            "Failed to reserve {} bytes at {:?} from {}",
1629                            len,
1630                            device_range,
1631                            self.reservation_description(reservation),
1632                        ))
1633                    })?
1634                    .forget();
1635            } else {
1636                assert!(
1637                    !transaction.metadata_reservation.is_borrowed()
1638                        || self
1639                            .filesystem
1640                            .upgrade()
1641                            .unwrap()
1642                            .options()
1643                            .image_builder_mode
1644                            .is_some(),
1645                    "Allocations for non-system stores are not allowed in Borrowed transactions"
1646                );
1647            }
1648            owner_entry.uncommitted_allocated_bytes += len;
1649            inner.strategy.remove(device_range.clone());
1650            self.temporary_allocations.insert(AllocatorItem {
1651                key: AllocatorKey { device_range: Extent(device_range.clone()) },
1652                value: AllocatorValue::Abs { owner_object_id, count: 1 },
1653            })?;
1654        }
1655        let mutation =
1656            AllocatorMutation::Allocate { device_range: device_range.into(), owner_object_id };
1657        transaction.add(self.object_id(), Mutation::Allocator(mutation));
1658        Ok(())
1659    }
1660
1661    /// Sets the limits for an owner object in terms of usage.
1662    pub fn set_bytes_limit(
1663        &self,
1664        transaction: &mut Transaction<'_>,
1665        owner_object_id: u64,
1666        bytes: u64,
1667    ) -> Result<(), Error> {
1668        // System stores cannot be given limits.
1669        assert!(!self.is_system_store(owner_object_id));
1670        transaction.add(
1671            self.object_id(),
1672            Mutation::Allocator(AllocatorMutation::SetLimit { owner_object_id, bytes }),
1673        );
1674        Ok(())
1675    }
1676
1677    /// Gets the bytes limit for an owner object.
1678    pub fn get_owner_bytes_limit(&self, owner_object_id: u64) -> Option<u64> {
1679        self.inner.lock().info.limit_bytes.get(&owner_object_id).copied()
1680    }
1681
1682    /// Gets the number of bytes currently used by allocations, reservations or uncommitted
1683    /// allocations.
1684    pub fn get_owner_bytes_used(&self, owner_object_id: u64) -> u64 {
1685        self.inner.lock().owner_bytes.get(&owner_object_id).map_or(0, |info| info.used_bytes().0)
1686    }
1687
1688    /// Deallocates the given device range for the specified object.
1689    #[trace]
1690    pub async fn deallocate(
1691        &self,
1692        transaction: &mut Transaction<'_>,
1693        owner_object_id: u64,
1694        dealloc_range: Range<u64>,
1695    ) -> Result<u64, Error> {
1696        debug!(device_range:? = dealloc_range; "deallocate");
1697        ensure!(dealloc_range.is_valid(), FxfsError::InvalidArgs);
1698        // We don't currently support sharing of allocations (value.count always equals 1), so as
1699        // long as we can assume the deallocated range is actually allocated, we can avoid device
1700        // access.
1701        let deallocated = dealloc_range.end - dealloc_range.start;
1702        let mutation = AllocatorMutation::Deallocate {
1703            device_range: dealloc_range.clone().into(),
1704            owner_object_id,
1705        };
1706        transaction.add(self.object_id(), Mutation::Allocator(mutation));
1707
1708        let _guard = self.allocation_mutex.lock().await;
1709
1710        // We use `dropped_temporary_allocations` to defer removals from `temporary_allocations` in
1711        // places where we can't execute async code or take locks.
1712        //
1713        // It's important we don't ever remove entries from `temporary_allocations` without
1714        // holding the `allocation_mutex` lock or else we may end up with an inconsistent view of
1715        // available disk space when we combine temporary_allocations with the LSMTree.
1716        // This is normally done in `allocate()` but we also need to apply these here because
1717        // `temporary_allocations` is also used to track deallocated space until it has been
1718        // flushed (see comment below). A user may allocate and then deallocate space before calling
1719        // allocate() a second time, so if we do not clean up here, we may end up with the same
1720        // range in temporary_allocations twice (once for allocate, once for deallocate).
1721        let mut inner = self.inner.lock();
1722        for device_range in inner.dropped_temporary_allocations.drain(..) {
1723            self.temporary_allocations.erase(&AllocatorKey { device_range: Extent(device_range) });
1724        }
1725
1726        // We can't reuse deallocated space immediately because failure to successfully flush will
1727        // mean that on next mount, we may find this space is still assigned to the deallocated
1728        // region. To avoid immediate reuse, we hold these regions in 'temporary_allocations' until
1729        // after a successful flush so we know the region is safe to reuse.
1730        self.temporary_allocations
1731            .insert(AllocatorItem {
1732                key: AllocatorKey { device_range: Extent(dealloc_range.clone()) },
1733                value: AllocatorValue::Abs { owner_object_id, count: 1 },
1734            })
1735            .context("tracking deallocated")?;
1736
1737        Ok(deallocated)
1738    }
1739
1740    /// Marks allocations associated with a given |owner_object_id| for deletion.
1741    ///
1742    /// This is used as part of deleting encrypted volumes (ObjectStore) without having the keys.
1743    ///
1744    /// MarkForDeletion mutations eventually manipulates allocator metadata (AllocatorInfo) instead
1745    /// of the mutable layer but we must be careful not to do this too early and risk premature
1746    /// reuse of extents.
1747    ///
1748    /// Replay is not guaranteed until the *device* gets flushed, so we cannot reuse the deleted
1749    /// extents until we've flushed the device.
1750    ///
1751    /// TODO(b/316827348): Consider removing the use of mark_for_deletion in AllocatorInfo and
1752    /// just compacting?
1753    ///
1754    /// After an allocator.flush() (i.e. a major compaction), we know that there is no data left
1755    /// in the layer files for this owner_object_id and we are able to clear `marked_for_deletion`.
1756    pub fn mark_for_deletion(&self, transaction: &mut Transaction<'_>, owner_object_id: u64) {
1757        // Note that because the actual time of deletion (the next major compaction) is undefined,
1758        // |owner_object_id| should not be reused after this call.
1759        transaction.add(
1760            self.object_id(),
1761            Mutation::Allocator(AllocatorMutation::MarkForDeletion(owner_object_id)),
1762        );
1763    }
1764
1765    /// Called when the device has been flush and indicates what the journal log offset was when
1766    /// that happened.
1767    pub fn did_flush_device(&self, flush_log_offset: u64) {
1768        // First take out the deallocations that we now know to be flushed.  The list is maintained
1769        // in order, so we can stop on the first entry that we find that should not be unreserved
1770        // yet.
1771        #[allow(clippy::never_loop)] // Loop used as a for {} else {}.
1772        let deallocs = 'deallocs_outer: loop {
1773            let mut inner = self.inner.lock();
1774            for (index, dealloc) in inner.committed_deallocated.iter().enumerate() {
1775                if dealloc.log_file_offset >= flush_log_offset {
1776                    let mut deallocs = inner.committed_deallocated.split_off(index);
1777                    // Swap because we want the opposite of what split_off does.
1778                    std::mem::swap(&mut inner.committed_deallocated, &mut deallocs);
1779                    break 'deallocs_outer deallocs;
1780                }
1781            }
1782            break std::mem::take(&mut inner.committed_deallocated);
1783        };
1784
1785        // Now we can free those elements.
1786        let mut inner = self.inner.lock();
1787        let mut totals = BTreeMap::<u64, u64>::new();
1788        for dealloc in deallocs {
1789            *(totals.entry(dealloc.owner_object_id).or_default()) +=
1790                dealloc.range.length().unwrap();
1791            inner.strategy.free(dealloc.range.clone()).expect("dealloced ranges");
1792            self.temporary_allocations.erase(&AllocatorKey { device_range: Extent(dealloc.range) });
1793        }
1794
1795        // This *must* come after we've removed the records from reserved reservations because the
1796        // allocator uses this value to decide whether or not a device-flush is required and it must
1797        // be possible to find free space if it thinks no device-flush is required.
1798        for (owner_object_id, total) in totals {
1799            match inner.owner_bytes.get_mut(&owner_object_id) {
1800                Some(counters) => counters.committed_deallocated_bytes -= total,
1801                None => {
1802                    // This should only be possible if the volume has been deleted and a sync is
1803                    // pending.
1804                    assert!(inner.volumes_deleted_pending_sync.contains(&owner_object_id));
1805                }
1806            }
1807        }
1808    }
1809
1810    /// Returns a reservation that can be used later, or None if there is insufficient space. The
1811    /// |owner_object_id| indicates which object in the root object store the reservation is for.
1812    pub fn reserve(
1813        self: Arc<Self>,
1814        owner_object_id: Option<u64>,
1815        amount: u64,
1816    ) -> Option<Reservation> {
1817        {
1818            let mut inner = self.inner.lock();
1819
1820            let device_free = (Saturating(self.device_size) - inner.used_bytes()).0;
1821
1822            let limit = match owner_object_id {
1823                Some(id) => std::cmp::min(inner.owner_id_bytes_left(id), device_free),
1824                None => device_free,
1825            };
1826            if limit < amount {
1827                return None;
1828            }
1829            inner.add_reservation(owner_object_id, amount);
1830        }
1831        Some(Reservation::new(self, owner_object_id, amount))
1832    }
1833
1834    /// Like reserve, but takes a callback is passed the |limit| and should return the amount,
1835    /// which can be zero.
1836    pub fn reserve_with(
1837        self: Arc<Self>,
1838        owner_object_id: Option<u64>,
1839        amount: impl FnOnce(u64) -> u64,
1840    ) -> Reservation {
1841        let amount = {
1842            let mut inner = self.inner.lock();
1843
1844            let device_free = (Saturating(self.device_size) - inner.used_bytes()).0;
1845
1846            let amount = amount(match owner_object_id {
1847                Some(id) => std::cmp::min(inner.owner_id_bytes_left(id), device_free),
1848                None => device_free,
1849            });
1850
1851            inner.add_reservation(owner_object_id, amount);
1852
1853            amount
1854        };
1855
1856        Reservation::new(self, owner_object_id, amount)
1857    }
1858
1859    /// Returns the total number of allocated bytes.
1860    pub fn get_allocated_bytes(&self) -> u64 {
1861        self.inner.lock().allocated_bytes().0
1862    }
1863
1864    /// Returns the size of bytes available to allocate.
1865    pub fn get_disk_bytes(&self) -> u64 {
1866        self.device_size
1867    }
1868
1869    /// Returns the total number of allocated bytes per owner_object_id.
1870    /// Note that this is quite an expensive operation as it copies the collection.
1871    /// This is intended for use in fsck() and friends, not general use code.
1872    pub fn get_owner_allocated_bytes(&self) -> BTreeMap<u64, u64> {
1873        self.inner.lock().owner_bytes.iter().map(|(k, v)| (*k, v.allocated_bytes.0)).collect()
1874    }
1875
1876    /// Returns the number of allocated and reserved bytes.
1877    pub fn get_used_bytes(&self) -> Saturating<u64> {
1878        let inner = self.inner.lock();
1879        inner.used_bytes()
1880    }
1881
1882    pub async fn flush(&self) -> Result<Version, Error> {
1883        let filesystem = self.filesystem.upgrade().unwrap();
1884        let object_manager = filesystem.object_manager();
1885        let earliest_version = self.tree.get_earliest_version();
1886        if !object_manager.needs_flush(self.object_id()) && earliest_version == LATEST_VERSION {
1887            // Early exit, but still return the earliest version used by a struct in the tree
1888            return Ok(earliest_version);
1889        }
1890
1891        let fs = self.filesystem.upgrade().unwrap();
1892        let mut flusher = Flusher::new(self, &fs).await;
1893        let (new_layer_file, info) = flusher.start().await?;
1894        flusher.finish(new_layer_file, info).await
1895    }
1896}
1897
1898impl ReservationOwner for Allocator {
1899    fn release_reservation(&self, owner_object_id: Option<u64>, amount: u64) {
1900        self.inner.lock().remove_reservation(owner_object_id, amount);
1901    }
1902}
1903
1904#[async_trait]
1905impl JournalingObject for Allocator {
1906    fn apply_mutation(
1907        &self,
1908        mutation: Mutation,
1909        context: &ApplyContext<'_, '_>,
1910        _assoc_obj: AssocObj<'_>,
1911    ) -> Result<(), Error> {
1912        match mutation {
1913            Mutation::Allocator(AllocatorMutation::MarkForDeletion(owner_object_id)) => {
1914                let mut inner = self.inner.lock();
1915                inner.owner_bytes.remove(&owner_object_id);
1916
1917                // We use `info.marked_for_deletion` to track the committed state and
1918                // `inner.marked_for_deletion` to track volumes marked for deletion *after* we have
1919                // flushed the device.  It is not safe to use extents belonging to deleted volumes
1920                // until after we have flushed the device.
1921                inner.info.marked_for_deletion.insert(owner_object_id);
1922                inner.volumes_deleted_pending_sync.insert(owner_object_id);
1923
1924                inner.info.limit_bytes.remove(&owner_object_id);
1925            }
1926            Mutation::Allocator(AllocatorMutation::Allocate { device_range, owner_object_id }) => {
1927                self.maximum_offset.fetch_max(device_range.end, Ordering::Relaxed);
1928                let item = AllocatorItem {
1929                    key: AllocatorKey { device_range: Extent(device_range.0.clone()) },
1930                    value: AllocatorValue::Abs { count: 1, owner_object_id },
1931                };
1932                let len = item.key.device_range.length().unwrap();
1933                let lower_bound = item.key.lower_bound_for_merge_into();
1934                self.tree.merge_into(item, &lower_bound);
1935                let reservation = if let ApplyMode::Live(transaction) = context.mode {
1936                    transaction.allocator_reservation(owner_object_id)
1937                } else {
1938                    None
1939                };
1940                let mut inner = self.inner.lock();
1941                let entry = inner.owner_bytes.entry(owner_object_id).or_default();
1942                entry.allocated_bytes += len;
1943                if context.mode.is_live() {
1944                    entry.uncommitted_allocated_bytes -= len;
1945                    // Note that we cannot drop entries from temporary_allocations without holding
1946                    // the allocation_mutex as it may introduce races. We instead add the range to
1947                    // a Vec that can be applied later when we hold the lock (See comment on
1948                    // `dropped_temporary_allocations` above).
1949                    inner.dropped_temporary_allocations.push(device_range.0);
1950                    if let Some(reservation) = reservation {
1951                        reservation.commit(len);
1952                    }
1953                }
1954            }
1955            Mutation::Allocator(AllocatorMutation::Deallocate {
1956                device_range,
1957                owner_object_id,
1958            }) => {
1959                let item = AllocatorItem {
1960                    key: AllocatorKey { device_range: Extent(device_range.0) },
1961                    value: AllocatorValue::None,
1962                };
1963                let len = item.key.device_range.length().unwrap();
1964                let reservation = if let ApplyMode::Live(transaction) = context.mode {
1965                    transaction.allocator_reservation(owner_object_id)
1966                } else {
1967                    None
1968                };
1969
1970                {
1971                    let mut inner = self.inner.lock();
1972                    {
1973                        let entry = inner.owner_bytes.entry(owner_object_id).or_default();
1974                        entry.allocated_bytes -= len;
1975                        if context.mode.is_live() {
1976                            entry.committed_deallocated_bytes += len;
1977                        }
1978                    }
1979                    if context.mode.is_live() {
1980                        inner.committed_deallocated.push_back(CommittedDeallocation {
1981                            log_file_offset: context.checkpoint.file_offset,
1982                            range: (*item.key.device_range).clone(),
1983                            owner_object_id,
1984                        });
1985                    }
1986                    if let Some(reservation) = reservation {
1987                        inner.add_reservation(reservation.owner_object_id(), len);
1988                        reservation.add(len);
1989                    }
1990                }
1991                let lower_bound = item.key.lower_bound_for_merge_into();
1992                self.tree.merge_into(item, &lower_bound);
1993            }
1994            Mutation::Allocator(AllocatorMutation::SetLimit { owner_object_id, bytes }) => {
1995                // Journal replay is ordered and each of these calls is idempotent. So the last one
1996                // will be respected, it doesn't matter if the value is already set, or gets changed
1997                // multiple times during replay. When it gets opened it will be merged in with the
1998                // snapshot.
1999                self.inner.lock().info.limit_bytes.insert(owner_object_id, bytes);
2000            }
2001            Mutation::BeginFlush => {
2002                self.tree.seal();
2003                // Transfer our running count for allocated_bytes so that it gets written to the new
2004                // info file when flush completes.
2005                let mut inner = self.inner.lock();
2006                let allocated_bytes =
2007                    inner.owner_bytes.iter().map(|(k, v)| (*k, v.allocated_bytes.0)).collect();
2008                inner.info.allocated_bytes = allocated_bytes;
2009            }
2010            Mutation::EndFlush(_) => {}
2011            _ => bail!("unexpected mutation: {:?}", mutation),
2012        }
2013        Ok(())
2014    }
2015
2016    fn drop_mutation(&self, mutation: Mutation, transaction: &Transaction<'_>) {
2017        match mutation {
2018            Mutation::Allocator(AllocatorMutation::Allocate { device_range, owner_object_id }) => {
2019                let len = device_range.length().unwrap();
2020                let reservation = transaction.allocator_reservation(owner_object_id);
2021                let mut inner = self.inner.lock();
2022                inner
2023                    .owner_bytes
2024                    .entry(owner_object_id)
2025                    .or_default()
2026                    .uncommitted_allocated_bytes -= len;
2027                if let Some(reservation) = reservation {
2028                    let res_owner = reservation.owner_object_id();
2029                    inner.add_reservation(res_owner, len);
2030                    reservation.release_reservation(res_owner, len);
2031                }
2032                inner.strategy.free(device_range.0.clone()).expect("drop mutaton");
2033                self.temporary_allocations
2034                    .erase(&AllocatorKey { device_range: Extent(device_range.0) });
2035            }
2036            Mutation::Allocator(AllocatorMutation::Deallocate { device_range, .. }) => {
2037                self.temporary_allocations
2038                    .erase(&AllocatorKey { device_range: Extent(device_range.0) });
2039            }
2040            _ => {}
2041        }
2042    }
2043
2044    async fn flush(&self, _reason: crate::filesystem::FlushReason) -> Result<Version, Error> {
2045        self.flush().await
2046    }
2047}
2048
2049// The merger is unable to merge extents that exist like the following:
2050//
2051//     |----- +1 -----|
2052//                    |----- -1 -----|
2053//                    |----- +2 -----|
2054//
2055// It cannot coalesce them because it has to emit the +1 record so that it can move on and merge the
2056// -1 and +2 records. To address this, we add another stage that applies after merging which
2057// coalesces records after they have been emitted.  This is a bit simpler than merging because the
2058// records cannot overlap, so it's just a question of merging adjacent records if they happen to
2059// have the same delta and object_id.
2060
2061pub struct CoalescingIterator<I> {
2062    iter: I,
2063    item: Option<AllocatorItem>,
2064}
2065
2066impl<I: LayerIterator<AllocatorKey, AllocatorValue>> CoalescingIterator<I> {
2067    pub async fn new(iter: I) -> Result<CoalescingIterator<I>, Error> {
2068        let mut iter = Self { iter, item: None };
2069        iter.advance().await?;
2070        Ok(iter)
2071    }
2072}
2073
2074impl<I: LayerIterator<AllocatorKey, AllocatorValue>> LayerIterator<AllocatorKey, AllocatorValue>
2075    for CoalescingIterator<I>
2076{
2077    async fn advance(&mut self) -> Result<(), Error> {
2078        self.item = self.iter.get().map(|x| x.cloned());
2079        if self.item.is_none() {
2080            return Ok(());
2081        }
2082        let left = self.item.as_mut().unwrap();
2083        loop {
2084            self.iter.advance().await?;
2085            match self.iter.get() {
2086                None => return Ok(()),
2087                Some(right) => {
2088                    // The two records cannot overlap.
2089                    ensure!(
2090                        left.key.device_range.end <= right.key.device_range.start,
2091                        FxfsError::Inconsistent
2092                    );
2093                    // We can only coalesce records if they are touching and have the same value.
2094                    if left.key.device_range.end < right.key.device_range.start
2095                        || left.value != *right.value
2096                    {
2097                        return Ok(());
2098                    }
2099                    left.key.device_range.end = right.key.device_range.end;
2100                }
2101            }
2102        }
2103    }
2104
2105    fn advance_dyn<'a>(&'a mut self) -> Result<Option<BoxFuture<'a, Result<(), Error>>>, Error> {
2106        Ok(Some(Box::pin(self.advance())))
2107    }
2108
2109    fn get(&self) -> Option<ItemRef<'_, AllocatorKey, AllocatorValue>> {
2110        self.item.as_ref().map(|x| x.as_item_ref())
2111    }
2112}
2113
2114struct Flusher<'a> {
2115    allocator: &'a Allocator,
2116    fs: &'a Arc<FxFilesystem>,
2117    _guard: WriteGuard<'a>,
2118}
2119
2120impl<'a> Flusher<'a> {
2121    async fn new(allocator: &'a Allocator, fs: &'a Arc<FxFilesystem>) -> Self {
2122        let keys = lock_keys![LockKey::flush(allocator.object_id())];
2123        Self { allocator, fs, _guard: fs.lock_manager().write_lock(keys).await }
2124    }
2125
2126    fn txn_options() -> Options<'static> {
2127        Options {
2128            skip_journal_checks: true,
2129            reservation: ReservationOptions::Borrowed,
2130            ..Default::default()
2131        }
2132    }
2133
2134    async fn start(&mut self) -> Result<(DataObjectHandle<ObjectStore>, AllocatorInfo), Error> {
2135        let root_store = self.fs.root_store();
2136        let mut transaction = root_store.new_transaction(lock_keys![], Self::txn_options()).await?;
2137        let layer_object_handle = ObjectStore::create_object(
2138            &root_store,
2139            &mut transaction,
2140            HandleOptions { skip_journal_checks: true, ..Default::default() },
2141            None,
2142        )
2143        .await?;
2144        root_store.add_to_graveyard(&mut transaction, layer_object_handle.object_id());
2145        // It's important that this transaction does not include any allocations because we use
2146        // BeginFlush as a snapshot point for mutations to the tree: other allocator mutations
2147        // within this transaction might get applied before seal (which would be OK), but they could
2148        // equally get applied afterwards (since Transaction makes no guarantees about the order in
2149        // which mutations are applied whilst committing), in which case they'd get lost on replay
2150        // because the journal will only send mutations that follow this transaction.
2151        transaction.add(self.allocator.object_id(), Mutation::BeginFlush);
2152        let info = transaction
2153            .commit_with_callback(|_| {
2154                // We must capture `info` as it is when we start flushing. Subsequent transactions
2155                // can end up modifying `info` and we shouldn't capture those here.
2156                self.allocator.inner.lock().info.clone()
2157            })
2158            .await?;
2159        Ok((layer_object_handle, info))
2160    }
2161
2162    async fn finish(
2163        self,
2164        layer_object_handle: DataObjectHandle<ObjectStore>,
2165        mut info: AllocatorInfo,
2166    ) -> Result<Version, Error> {
2167        let txn_options = Self::txn_options();
2168
2169        let layer_set = self.allocator.tree.immutable_layer_set();
2170        let total_len = layer_set.sum_len();
2171        {
2172            let start_time = std::time::Instant::now();
2173            let merged_layer_count = layer_set.layers.len();
2174            let mut merger = layer_set.merger();
2175            let iter = self.allocator.filter(merger.query(Query::FullScan).await?, true).await?;
2176            let iter = CoalescingIterator::new(iter).await?;
2177            let bytes_written = compact_with_iterator(
2178                iter,
2179                total_len,
2180                DirectWriter::new(&layer_object_handle, txn_options).await,
2181                layer_object_handle.block_size(),
2182                Some(self.fs.journal().get_compaction_yielder()),
2183            )
2184            .await?;
2185
2186            self.allocator.tree.report_compaction_metrics(
2187                bytes_written,
2188                start_time.elapsed(),
2189                merged_layer_count,
2190            );
2191        }
2192
2193        let root_store = self.fs.root_store();
2194
2195        // Both of these forward-declared variables need to outlive the transaction.
2196        let object_handle;
2197        let reservation_update;
2198        let mut transaction = root_store
2199            .new_transaction(
2200                lock_keys![LockKey::object(
2201                    root_store.store_object_id(),
2202                    self.allocator.object_id()
2203                )],
2204                txn_options,
2205            )
2206            .await?;
2207        let mut serialized_info = Vec::new();
2208
2209        debug!(oid = layer_object_handle.object_id(); "new allocator layer file");
2210        object_handle = ObjectStore::open_object(
2211            &root_store,
2212            self.allocator.object_id(),
2213            HandleOptions::default(),
2214            None,
2215        )
2216        .await?;
2217
2218        // Move all the existing layers to the graveyard.
2219        for object_id in &info.layers {
2220            root_store.add_to_graveyard(&mut transaction, *object_id);
2221        }
2222
2223        // Write out updated info.
2224
2225        // After successfully flushing, all the stores that were marked for deletion at the time of
2226        // the BeginFlush transaction, no longer need to be marked for deletion.  There can be
2227        // stores that have been deleted since the BeginFlush transaction, but they will be covered
2228        // by a MarkForDeletion mutation.
2229        let marked_for_deletion = std::mem::take(&mut info.marked_for_deletion);
2230
2231        info.layers = vec![layer_object_handle.object_id()];
2232
2233        info.serialize_with_version(&mut serialized_info)?;
2234
2235        let mut buf = object_handle.allocate_buffer(serialized_info.len()).await;
2236        buf.copy_from_slice(&serialized_info);
2237        object_handle.txn_write(&mut transaction, 0u64, buf.as_ref()).await?;
2238
2239        reservation_update = ReservationUpdate::new(layer_object_handle.get_size());
2240
2241        // It's important that EndFlush is in the same transaction that we write AllocatorInfo,
2242        // because we use EndFlush to make the required adjustments to allocated_bytes.
2243        transaction.add_with_object(
2244            self.allocator.object_id(),
2245            Mutation::EndFlush(0),
2246            AssocObj::Borrowed(&reservation_update),
2247        );
2248        root_store.remove_from_graveyard(&mut transaction, layer_object_handle.object_id());
2249
2250        let layers = vec![layer_from_handle(layer_object_handle, None).await?];
2251        transaction
2252            .commit_with_callback(|_| {
2253                self.allocator.tree.set_layers(layers);
2254
2255                // At this point we've committed the new layers to disk so we can start using them.
2256                // This means we can also switch to the new AllocatorInfo which clears
2257                // marked_for_deletion.
2258                let mut inner = self.allocator.inner.lock();
2259                inner.info.layers = info.layers;
2260                for owner_id in marked_for_deletion {
2261                    inner.marked_for_deletion.remove(&owner_id);
2262                    inner.info.marked_for_deletion.remove(&owner_id);
2263                }
2264            })
2265            .await?;
2266
2267        // Now close the layers and purge them.
2268        for layer in layer_set.layers {
2269            let object_id = layer.handle().map(|h| h.object_id());
2270            layer.close_layer().await;
2271            if let Some(object_id) = object_id {
2272                root_store.tombstone_object(object_id, txn_options, None).await?;
2273            }
2274        }
2275
2276        let mut counters = self.allocator.counters.lock();
2277        counters.num_flushes += 1;
2278        counters.last_flush_time = Some(std::time::SystemTime::now());
2279        // Return the earliest version used by a struct in the tree
2280        Ok(self.allocator.tree.get_earliest_version())
2281    }
2282}
2283
2284#[cfg(test)]
2285mod tests {
2286    use crate::filesystem::{FxFilesystem, FxFilesystemBuilder, OpenFxFilesystem};
2287    use crate::fsck::fsck;
2288    use crate::lsm_tree::skip_list_layer::SkipListLayer;
2289    use crate::lsm_tree::types::{FuzzyHash as _, Item, ItemRef, LayerIterator, LayerKey as _};
2290    use crate::lsm_tree::{LSMTree, Query};
2291    use crate::object_handle::ObjectHandle;
2292    use crate::object_store::allocator::merge::merge;
2293    use crate::object_store::allocator::{
2294        Allocator, AllocatorKey, AllocatorValue, CoalescingIterator, EXTENT_HASH_BUCKET_SIZE,
2295    };
2296    use crate::object_store::extent::MIN_BLOCK_SIZE;
2297    use crate::object_store::transaction::{
2298        Options, ReservationOptions, TRANSACTION_METADATA_MAX_AMOUNT, lock_keys,
2299    };
2300    use crate::object_store::volume::root_volume;
2301    use crate::object_store::{Directory, FxfsError, LockKey, NewChildStoreOptions, ObjectStore};
2302    use crate::range::RangeExt;
2303    use crate::serialized_types::{LATEST_VERSION, Versioned};
2304    use crate::testing;
2305    use bincode::Options as _;
2306    use fuchsia_async as fasync;
2307    use fuchsia_sync::Mutex;
2308    use std::cmp::{max, min};
2309    use std::ops::{Bound, Range};
2310    use std::sync::Arc;
2311    use storage_device::DeviceHolder;
2312    use storage_device::fake_device::FakeDevice;
2313
2314    #[test]
2315    fn test_allocator_key_is_range_based() {
2316        // Make sure we disallow using allocator keys with point queries.
2317        assert!(AllocatorKey { device_range: (0..100).into() }.is_range_key());
2318    }
2319
2320    #[test]
2321    fn test_allocator_key_fuzzy_hash_len() {
2322        let key = AllocatorKey { device_range: (0..512).into() };
2323        let mut iter = key.fuzzy_hash();
2324        assert_eq!(iter.len(), 1);
2325        assert_eq!(iter.size_hint(), (1, Some(1)));
2326        assert!(iter.next().is_some());
2327        assert_eq!(iter.len(), 0);
2328        assert_eq!(iter.size_hint(), (0, Some(0)));
2329        assert_eq!(iter.next(), None);
2330
2331        let key = AllocatorKey { device_range: (0..3 * EXTENT_HASH_BUCKET_SIZE).into() };
2332        let mut iter = key.fuzzy_hash();
2333        assert_eq!(iter.len(), 3);
2334        assert_eq!(iter.size_hint(), (3, Some(3)));
2335        assert!(iter.next().is_some());
2336        assert_eq!(iter.len(), 2);
2337        assert_eq!(iter.size_hint(), (2, Some(2)));
2338        assert!(iter.next().is_some());
2339        assert_eq!(iter.len(), 1);
2340        assert_eq!(iter.size_hint(), (1, Some(1)));
2341        assert!(iter.next().is_some());
2342        assert_eq!(iter.len(), 0);
2343        assert_eq!(iter.size_hint(), (0, Some(0)));
2344        assert_eq!(iter.next(), None);
2345    }
2346
2347    #[test]
2348    fn test_allocator_key_search_key() {
2349        let key = AllocatorKey { device_range: (MIN_BLOCK_SIZE.get()..3 * MIN_BLOCK_SIZE).into() };
2350        assert!(!key.is_search_key());
2351        let search_key = key.search_key().unwrap();
2352        assert!(search_key.is_search_key());
2353        assert_eq!(search_key.device_range, (MIN_BLOCK_SIZE.get()..2 * MIN_BLOCK_SIZE).into());
2354    }
2355
2356    #[test]
2357    fn test_allocator_key_serialization_compatibility() {
2358        let range = 1024..2048;
2359        let key = AllocatorKey { device_range: range.clone().into() };
2360
2361        // 1. Serialize the range directly using bincode (which is what the manual
2362        //    Versioned implementation did)
2363        let options = bincode::DefaultOptions::new().allow_trailing_bytes();
2364        let expected_bytes = options.serialize(&range).unwrap();
2365
2366        // 2. Serialize AllocatorKey via our derived Versioned implementation
2367        let mut key_bytes = Vec::new();
2368        key.serialize_into(&mut key_bytes).unwrap();
2369
2370        // Verify they are byte-compatible
2371        assert_eq!(key_bytes, expected_bytes);
2372
2373        // 3. Deserialize a Range<u64> as AllocatorKey via our derived Versioned
2374        //    implementation
2375        let deserialized_key =
2376            AllocatorKey::deserialize_from(&mut &expected_bytes[..], LATEST_VERSION).unwrap();
2377        assert_eq!(deserialized_key, key);
2378    }
2379
2380    #[fuchsia::test]
2381    async fn test_coalescing_iterator() {
2382        let skip_list = SkipListLayer::new(100);
2383        let items = [
2384            Item::new(
2385                AllocatorKey { device_range: (0..100 * 512).into() },
2386                AllocatorValue::Abs { count: 1, owner_object_id: 99 },
2387            ),
2388            Item::new(
2389                AllocatorKey { device_range: (100 * 512..200 * 512).into() },
2390                AllocatorValue::Abs { count: 1, owner_object_id: 99 },
2391            ),
2392        ];
2393        skip_list.insert(items[1].clone()).expect("insert error");
2394        skip_list.insert(items[0].clone()).expect("insert error");
2395        let mut iter =
2396            CoalescingIterator::new(skip_list.seek(Bound::Unbounded)).await.expect("new failed");
2397        let ItemRef { key, value, .. } = iter.get().expect("get failed");
2398        assert_eq!(
2399            (key, value),
2400            (
2401                &AllocatorKey { device_range: (0..200 * 512).into() },
2402                &AllocatorValue::Abs { count: 1, owner_object_id: 99 }
2403            )
2404        );
2405        iter.advance().await.expect("advance failed");
2406        assert!(iter.get().is_none());
2407    }
2408
2409    #[fuchsia::test]
2410    async fn test_merge_and_coalesce_across_three_layers() {
2411        let lsm_tree = LSMTree::new(merge, None);
2412        lsm_tree
2413            .insert(Item::new(
2414                AllocatorKey { device_range: (100 * 512..200 * 512).into() },
2415                AllocatorValue::Abs { count: 1, owner_object_id: 99 },
2416            ))
2417            .expect("insert error");
2418        lsm_tree.seal();
2419        lsm_tree
2420            .insert(Item::new(
2421                AllocatorKey { device_range: (0..100 * 512).into() },
2422                AllocatorValue::Abs { count: 1, owner_object_id: 99 },
2423            ))
2424            .expect("insert error");
2425
2426        let layer_set = lsm_tree.layer_set();
2427        let mut merger = layer_set.merger();
2428        let mut iter =
2429            CoalescingIterator::new(merger.query(Query::FullScan).await.expect("seek failed"))
2430                .await
2431                .expect("new failed");
2432        let ItemRef { key, value, .. } = iter.get().expect("get failed");
2433        assert_eq!(
2434            (key, value),
2435            (
2436                &AllocatorKey { device_range: (0..200 * 512).into() },
2437                &AllocatorValue::Abs { count: 1, owner_object_id: 99 }
2438            )
2439        );
2440        iter.advance().await.expect("advance failed");
2441        assert!(iter.get().is_none());
2442    }
2443
2444    #[fuchsia::test]
2445    async fn test_merge_and_coalesce_wont_merge_across_object_id() {
2446        let lsm_tree = LSMTree::new(merge, None);
2447        lsm_tree
2448            .insert(Item::new(
2449                AllocatorKey { device_range: (100 * 512..200 * 512).into() },
2450                AllocatorValue::Abs { count: 1, owner_object_id: 99 },
2451            ))
2452            .expect("insert error");
2453        lsm_tree.seal();
2454        lsm_tree
2455            .insert(Item::new(
2456                AllocatorKey { device_range: (0..100 * 512).into() },
2457                AllocatorValue::Abs { count: 1, owner_object_id: 98 },
2458            ))
2459            .expect("insert error");
2460
2461        let layer_set = lsm_tree.layer_set();
2462        let mut merger = layer_set.merger();
2463        let mut iter =
2464            CoalescingIterator::new(merger.query(Query::FullScan).await.expect("seek failed"))
2465                .await
2466                .expect("new failed");
2467        let ItemRef { key, value, .. } = iter.get().expect("get failed");
2468        assert_eq!(
2469            (key, value),
2470            (
2471                &AllocatorKey { device_range: (0..100 * 512).into() },
2472                &AllocatorValue::Abs { count: 1, owner_object_id: 98 },
2473            )
2474        );
2475        iter.advance().await.expect("advance failed");
2476        let ItemRef { key, value, .. } = iter.get().expect("get failed");
2477        assert_eq!(
2478            (key, value),
2479            (
2480                &AllocatorKey { device_range: (100 * 512..200 * 512).into() },
2481                &AllocatorValue::Abs { count: 1, owner_object_id: 99 }
2482            )
2483        );
2484        iter.advance().await.expect("advance failed");
2485        assert!(iter.get().is_none());
2486    }
2487
2488    fn overlap(a: &Range<u64>, b: &Range<u64>) -> u64 {
2489        if a.end > b.start && a.start < b.end {
2490            min(a.end, b.end) - max(a.start, b.start)
2491        } else {
2492            0
2493        }
2494    }
2495
2496    async fn collect_allocations(allocator: &Allocator) -> Vec<Range<u64>> {
2497        let layer_set = allocator.tree.layer_set();
2498        let mut merger = layer_set.merger();
2499        let mut iter = allocator
2500            .filter(merger.query(Query::FullScan).await.expect("seek failed"), false)
2501            .await
2502            .expect("build iterator");
2503        let mut allocations: Vec<Range<u64>> = Vec::new();
2504        while let Some(ItemRef { key: AllocatorKey { device_range }, .. }) = iter.get() {
2505            if let Some(r) = allocations.last() {
2506                assert!(device_range.start >= r.end);
2507            }
2508            allocations.push(device_range.clone().into());
2509            iter.advance().await.expect("advance failed");
2510        }
2511        allocations
2512    }
2513
2514    async fn check_allocations(allocator: &Allocator, expected_allocations: &[Range<u64>]) {
2515        let layer_set = allocator.tree.layer_set();
2516        let mut merger = layer_set.merger();
2517        let mut iter = allocator
2518            .filter(merger.query(Query::FullScan).await.expect("seek failed"), false)
2519            .await
2520            .expect("build iterator");
2521        let mut found = 0;
2522        while let Some(ItemRef { key: AllocatorKey { device_range }, .. }) = iter.get() {
2523            let mut l = device_range.length().expect("Invalid range");
2524            found += l;
2525            // Make sure that the entire range we have found completely overlaps with all the
2526            // allocations we expect to find.
2527            for range in expected_allocations {
2528                l -= overlap(range, device_range);
2529                if l == 0 {
2530                    break;
2531                }
2532            }
2533            assert_eq!(l, 0, "range {:?} not covered by expectations", device_range);
2534            iter.advance().await.expect("advance failed");
2535        }
2536        // Make sure the total we found adds up to what we expect.
2537        assert_eq!(found, expected_allocations.iter().map(|r| r.length().unwrap()).sum::<u64>());
2538    }
2539
2540    async fn test_fs() -> (OpenFxFilesystem, Arc<Allocator>) {
2541        let device = DeviceHolder::new(FakeDevice::new(4096, 4096));
2542        let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2543        let allocator = fs.allocator();
2544        (fs, allocator)
2545    }
2546
2547    #[fuchsia::test]
2548    async fn test_allocations() {
2549        const STORE_OBJECT_ID: u64 = 99;
2550        let (fs, allocator) = test_fs().await;
2551        let mut transaction = fs
2552            .root_store()
2553            .new_transaction(lock_keys![], Options::default())
2554            .await
2555            .expect("new failed");
2556        let mut device_ranges = collect_allocations(&allocator).await;
2557
2558        // Expected extents:
2559        let expected = vec![
2560            0..4096,        // Superblock A (4k)
2561            4096..139264,   // root_store layer files, StoreInfo.. (33x4k blocks)
2562            139264..204800, // Superblock A extension (64k)
2563            204800..335872, // Initial Journal (128k)
2564            335872..401408, // Superblock B extension (64k)
2565            524288..528384, // Superblock B (4k)
2566        ];
2567        assert_eq!(device_ranges, expected);
2568        device_ranges.push(
2569            allocator
2570                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
2571                .await
2572                .expect("allocate failed"),
2573        );
2574        assert_eq!(device_ranges.last().unwrap().length().expect("Invalid range"), fs.block_size());
2575        device_ranges.push(
2576            allocator
2577                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
2578                .await
2579                .expect("allocate failed"),
2580        );
2581        assert_eq!(device_ranges.last().unwrap().length().expect("Invalid range"), fs.block_size());
2582        assert_eq!(overlap(&device_ranges[0], &device_ranges[1]), 0);
2583        transaction.commit().await.expect("commit failed");
2584        let mut transaction = fs
2585            .root_store()
2586            .new_transaction(lock_keys![], Options::default())
2587            .await
2588            .expect("new failed");
2589        device_ranges.push(
2590            allocator
2591                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
2592                .await
2593                .expect("allocate failed"),
2594        );
2595        assert_eq!(device_ranges[7].length().expect("Invalid range"), fs.block_size());
2596        assert_eq!(overlap(&device_ranges[5], &device_ranges[7]), 0);
2597        assert_eq!(overlap(&device_ranges[6], &device_ranges[7]), 0);
2598        transaction.commit().await.expect("commit failed");
2599
2600        check_allocations(&allocator, &device_ranges).await;
2601    }
2602
2603    #[fuchsia::test]
2604    async fn test_allocate_more_than_max_size() {
2605        const STORE_OBJECT_ID: u64 = 99;
2606        let (fs, allocator) = test_fs().await;
2607        let mut transaction = fs
2608            .root_store()
2609            .new_transaction(lock_keys![], Options::default())
2610            .await
2611            .expect("new failed");
2612        let mut device_ranges = collect_allocations(&allocator).await;
2613        device_ranges.push(
2614            allocator
2615                .allocate(&mut transaction, STORE_OBJECT_ID, fs.device().size())
2616                .await
2617                .expect("allocate failed"),
2618        );
2619        assert_eq!(
2620            device_ranges.last().unwrap().length().expect("Invalid range"),
2621            allocator.max_extent_size_bytes
2622        );
2623        transaction.commit().await.expect("commit failed");
2624
2625        check_allocations(&allocator, &device_ranges).await;
2626    }
2627
2628    #[fuchsia::test]
2629    async fn test_deallocations() {
2630        const STORE_OBJECT_ID: u64 = 99;
2631        let (fs, allocator) = test_fs().await;
2632        let initial_allocations = collect_allocations(&allocator).await;
2633
2634        let mut transaction = fs
2635            .root_store()
2636            .new_transaction(lock_keys![], Options::default())
2637            .await
2638            .expect("new failed");
2639        let device_range1 = allocator
2640            .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
2641            .await
2642            .expect("allocate failed");
2643        assert_eq!(device_range1.length().expect("Invalid range"), fs.block_size());
2644        transaction.commit().await.expect("commit failed");
2645
2646        let mut transaction = fs
2647            .root_store()
2648            .new_transaction(lock_keys![], Options::default())
2649            .await
2650            .expect("new failed");
2651        allocator
2652            .deallocate(&mut transaction, STORE_OBJECT_ID, device_range1)
2653            .await
2654            .expect("deallocate failed");
2655        transaction.commit().await.expect("commit failed");
2656
2657        check_allocations(&allocator, &initial_allocations).await;
2658    }
2659
2660    #[fuchsia::test]
2661    async fn test_mark_allocated() {
2662        const STORE_OBJECT_ID: u64 = 99;
2663        let (fs, allocator) = test_fs().await;
2664        let mut device_ranges = collect_allocations(&allocator).await;
2665        let range = {
2666            let mut transaction = fs
2667                .root_store()
2668                .new_transaction(lock_keys![], Options::default())
2669                .await
2670                .expect("new failed");
2671            // First, allocate 2 blocks.
2672            allocator
2673                .allocate(&mut transaction, STORE_OBJECT_ID, 2 * fs.block_size())
2674                .await
2675                .expect("allocate failed")
2676            // Let the transaction drop.
2677        };
2678
2679        let mut transaction = fs
2680            .root_store()
2681            .new_transaction(lock_keys![], Options::default())
2682            .await
2683            .expect("new failed");
2684
2685        // If we allocate 1 block, the two blocks that were allocated earlier should be available,
2686        // and this should return the first of them.
2687        device_ranges.push(
2688            allocator
2689                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
2690                .await
2691                .expect("allocate failed"),
2692        );
2693
2694        assert_eq!(device_ranges.last().unwrap().start, range.start);
2695
2696        // Mark the second block as allocated.
2697        let mut range2 = range.clone();
2698        range2.start += fs.block_size();
2699        allocator
2700            .mark_allocated(&mut transaction, STORE_OBJECT_ID, range2.clone())
2701            .expect("mark_allocated failed");
2702        device_ranges.push(range2);
2703
2704        // This should avoid the range we marked as allocated.
2705        device_ranges.push(
2706            allocator
2707                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
2708                .await
2709                .expect("allocate failed"),
2710        );
2711        let last_range = device_ranges.last().unwrap();
2712        assert_eq!(last_range.length().expect("Invalid range"), fs.block_size());
2713        assert_eq!(overlap(last_range, &range), 0);
2714        transaction.commit().await.expect("commit failed");
2715
2716        check_allocations(&allocator, &device_ranges).await;
2717    }
2718
2719    #[fuchsia::test]
2720    async fn test_mark_for_deletion() {
2721        const STORE_OBJECT_ID: u64 = 99;
2722        let (fs, allocator) = test_fs().await;
2723
2724        // Allocate some stuff.
2725        let initial_allocated_bytes = allocator.get_allocated_bytes();
2726        let mut device_ranges = collect_allocations(&allocator).await;
2727        let mut transaction = fs
2728            .root_store()
2729            .new_transaction(lock_keys![], Options::default())
2730            .await
2731            .expect("new failed");
2732        // Note we have a cap on individual allocation length so we allocate over multiple mutation.
2733        for _ in 0..15 {
2734            device_ranges.push(
2735                allocator
2736                    .allocate(&mut transaction, STORE_OBJECT_ID, 100 * fs.block_size())
2737                    .await
2738                    .expect("allocate failed"),
2739            );
2740            device_ranges.push(
2741                allocator
2742                    .allocate(&mut transaction, STORE_OBJECT_ID, 100 * fs.block_size())
2743                    .await
2744                    .expect("allocate2 failed"),
2745            );
2746        }
2747        transaction.commit().await.expect("commit failed");
2748        check_allocations(&allocator, &device_ranges).await;
2749
2750        assert_eq!(
2751            allocator.get_allocated_bytes(),
2752            initial_allocated_bytes + fs.block_size() * 3000
2753        );
2754
2755        // Mark for deletion.
2756        let mut transaction = fs
2757            .root_store()
2758            .new_transaction(lock_keys![], Options::default())
2759            .await
2760            .expect("new failed");
2761        allocator.mark_for_deletion(&mut transaction, STORE_OBJECT_ID);
2762        transaction.commit().await.expect("commit failed");
2763
2764        // Expect that allocated bytes is updated immediately but device ranges are still allocated.
2765        assert_eq!(allocator.get_allocated_bytes(), initial_allocated_bytes);
2766        check_allocations(&allocator, &device_ranges).await;
2767
2768        // Allocate more space than we have until we deallocate the mark_for_deletion space.
2769        // This should force a flush on allocate(). (1500 * 3 > test_fs size of 4096 blocks).
2770        device_ranges.clear();
2771
2772        let mut transaction = fs
2773            .root_store()
2774            .new_transaction(lock_keys![], Options::default())
2775            .await
2776            .expect("new failed");
2777        let target_bytes = 1500 * fs.block_size();
2778        while device_ranges.iter().map(|x| x.length().unwrap()).sum::<u64>() != target_bytes {
2779            let len = std::cmp::min(
2780                target_bytes - device_ranges.iter().map(|x| x.length().unwrap()).sum::<u64>(),
2781                100 * fs.block_size(),
2782            );
2783            device_ranges.push(
2784                allocator.allocate(&mut transaction, 100, len).await.expect("allocate failed"),
2785            );
2786        }
2787        transaction.commit().await.expect("commit failed");
2788
2789        // Have the deleted ranges cleaned up.
2790        allocator.flush().await.expect("flush failed");
2791
2792        // The flush above seems to trigger an allocation for the allocator itself.
2793        // We will just check that we have the right size for the owner we care about.
2794
2795        assert!(!allocator.get_owner_allocated_bytes().contains_key(&STORE_OBJECT_ID));
2796        assert_eq!(*allocator.get_owner_allocated_bytes().get(&100).unwrap(), target_bytes,);
2797    }
2798
2799    async fn create_file(store: &Arc<ObjectStore>, size: usize) {
2800        let root_directory =
2801            Directory::open(store, store.root_directory_object_id()).await.expect("open failed");
2802
2803        let mut transaction = store
2804            .filesystem()
2805            .ensure_local()
2806            .root_store()
2807            .new_transaction(
2808                lock_keys![LockKey::object(
2809                    store.store_object_id(),
2810                    store.root_directory_object_id()
2811                )],
2812                Options::default(),
2813            )
2814            .await
2815            .expect("new_transaction failed");
2816        let file = root_directory
2817            .create_child_file(&mut transaction, &format!("foo {}", size))
2818            .await
2819            .expect("create_child_file failed");
2820        transaction.commit().await.expect("commit failed");
2821
2822        let buffer = file.allocate_buffer(size).await;
2823
2824        // Append some data to it.
2825        const CHUNK_SIZE: usize = 1_048_576;
2826        for offset in (0..size).step_by(CHUNK_SIZE) {
2827            let len = std::cmp::min(CHUNK_SIZE, size - offset);
2828            let mut transaction = file.new_transaction().await.expect("new_transaction failed");
2829            file.txn_write(&mut transaction, offset as u64, buffer.subslice(offset..offset + len))
2830                .await
2831                .expect("txn_write failed");
2832            transaction.commit().await.expect("commit failed");
2833        }
2834    }
2835
2836    #[fuchsia::test]
2837    async fn test_replay_with_deleted_store_and_compaction() {
2838        let (fs, _) = test_fs().await;
2839
2840        const FILE_SIZE: usize = 10_000_000;
2841
2842        let mut store_id = {
2843            let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
2844            let store = root_vol
2845                .new_volume("vol", NewChildStoreOptions::default())
2846                .await
2847                .expect("new_volume failed");
2848
2849            create_file(&store, FILE_SIZE).await;
2850            store.store_object_id()
2851        };
2852
2853        fs.close().await.expect("close failed");
2854        let device = fs.take_device().await;
2855        device.reopen(false);
2856
2857        let mut fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
2858
2859        // Compact so that when we replay the transaction to delete the store won't find any
2860        // mutations.
2861        fs.journal().force_compact().await.expect("compact failed");
2862
2863        for _ in 0..2 {
2864            {
2865                let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
2866
2867                let transaction = fs
2868                    .root_store()
2869                    .new_transaction(
2870                        lock_keys![
2871                            LockKey::object(
2872                                root_vol.volume_directory().store().store_object_id(),
2873                                root_vol.volume_directory().object_id(),
2874                            ),
2875                            LockKey::flush(store_id)
2876                        ],
2877                        Options { reservation: ReservationOptions::Borrowed, ..Default::default() },
2878                    )
2879                    .await
2880                    .expect("new_transaction failed");
2881                root_vol
2882                    .delete_volume("vol", transaction, || {})
2883                    .await
2884                    .expect("delete_volume failed");
2885
2886                let store = root_vol
2887                    .new_volume("vol", NewChildStoreOptions::default())
2888                    .await
2889                    .expect("new_volume failed");
2890                create_file(&store, FILE_SIZE).await;
2891                store_id = store.store_object_id();
2892            }
2893
2894            fs.close().await.expect("close failed");
2895            let device = fs.take_device().await;
2896            device.reopen(false);
2897
2898            fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
2899        }
2900
2901        fsck(fs.clone()).await.expect("fsck failed");
2902        fs.close().await.expect("close failed");
2903    }
2904
2905    #[fuchsia::test(threads = 4)]
2906    async fn test_compaction_delete_race() {
2907        let (fs, _allocator) = test_fs().await;
2908
2909        {
2910            const FILE_SIZE: usize = 10_000_000;
2911
2912            let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
2913            let store = root_vol
2914                .new_volume("vol", NewChildStoreOptions::default())
2915                .await
2916                .expect("new_volume failed");
2917
2918            create_file(&store, FILE_SIZE).await;
2919
2920            // Race compaction with deleting a store.
2921            let fs_clone = fs.clone();
2922
2923            // Even though the executor has 4 threads, it's hard to get it to run with
2924            // multiple threads.
2925            let executor_tasks = testing::force_executor_threads_to_run(4).await;
2926
2927            let task = fasync::Task::spawn(async move {
2928                fs_clone.journal().force_compact().await.expect("compact failed");
2929            });
2930
2931            // We don't need the executor tasks any more.
2932            drop(executor_tasks);
2933
2934            // This range is chosen such that it caused this test to fail after quite a low number
2935            // of iterations for the bug that this test was introduced for.
2936            let sleep = rand::random_range(3000..6000);
2937            std::thread::sleep(std::time::Duration::from_micros(sleep));
2938            log::info!("sleep {sleep}us");
2939
2940            let transaction = fs
2941                .root_store()
2942                .new_transaction(
2943                    lock_keys![
2944                        LockKey::object(
2945                            root_vol.volume_directory().store().store_object_id(),
2946                            root_vol.volume_directory().object_id(),
2947                        ),
2948                        LockKey::flush(store.store_object_id())
2949                    ],
2950                    Options { reservation: ReservationOptions::Borrowed, ..Default::default() },
2951                )
2952                .await
2953                .expect("new_transaction failed");
2954            root_vol.delete_volume("vol", transaction, || {}).await.expect("delete_volume failed");
2955
2956            task.await;
2957        }
2958
2959        fs.journal().force_compact().await.expect("compact failed");
2960        fs.close().await.expect("close failed");
2961
2962        let device = fs.take_device().await;
2963        device.reopen(false);
2964
2965        let fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
2966        fsck(fs.clone()).await.expect("fsck failed");
2967        fs.close().await.expect("close failed");
2968    }
2969
2970    #[fuchsia::test]
2971    async fn test_delete_multiple_volumes() {
2972        let (mut fs, _) = test_fs().await;
2973
2974        for _ in 0..50 {
2975            {
2976                let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
2977                let store = root_vol
2978                    .new_volume("vol", NewChildStoreOptions::default())
2979                    .await
2980                    .expect("new_volume failed");
2981
2982                create_file(&store, 1_000_000).await;
2983
2984                let transaction = fs
2985                    .root_store()
2986                    .new_transaction(
2987                        lock_keys![
2988                            LockKey::object(
2989                                root_vol.volume_directory().store().store_object_id(),
2990                                root_vol.volume_directory().object_id(),
2991                            ),
2992                            LockKey::flush(store.store_object_id())
2993                        ],
2994                        Options { reservation: ReservationOptions::Borrowed, ..Default::default() },
2995                    )
2996                    .await
2997                    .expect("new_transaction failed");
2998                root_vol
2999                    .delete_volume("vol", transaction, || {})
3000                    .await
3001                    .expect("delete_volume failed");
3002
3003                fs.allocator().flush().await.expect("flush failed");
3004            }
3005
3006            fs.close().await.expect("close failed");
3007            let device = fs.take_device().await;
3008            device.reopen(false);
3009
3010            fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
3011        }
3012
3013        fsck(fs.clone()).await.expect("fsck failed");
3014        fs.close().await.expect("close failed");
3015    }
3016
3017    #[fuchsia::test]
3018    async fn test_allocate_free_reallocate() {
3019        const STORE_OBJECT_ID: u64 = 99;
3020        let (fs, allocator) = test_fs().await;
3021
3022        // Allocate some stuff.
3023        let mut device_ranges = Vec::new();
3024        let mut transaction = fs
3025            .root_store()
3026            .new_transaction(lock_keys![], Options::default())
3027            .await
3028            .expect("new failed");
3029        for _ in 0..30 {
3030            device_ranges.push(
3031                allocator
3032                    .allocate(&mut transaction, STORE_OBJECT_ID, 100 * fs.block_size())
3033                    .await
3034                    .expect("allocate failed"),
3035            );
3036        }
3037        transaction.commit().await.expect("commit failed");
3038
3039        assert_eq!(
3040            fs.block_size() * 3000,
3041            *allocator.get_owner_allocated_bytes().entry(STORE_OBJECT_ID).or_default()
3042        );
3043
3044        // Delete it all.
3045        let mut transaction = fs
3046            .root_store()
3047            .new_transaction(lock_keys![], Options::default())
3048            .await
3049            .expect("new failed");
3050        for range in std::mem::replace(&mut device_ranges, Vec::new()) {
3051            allocator.deallocate(&mut transaction, STORE_OBJECT_ID, range).await.expect("dealloc");
3052        }
3053        transaction.commit().await.expect("commit failed");
3054
3055        assert_eq!(0, *allocator.get_owner_allocated_bytes().entry(STORE_OBJECT_ID).or_default());
3056
3057        // Allocate some more stuff. Due to storage pressure, this requires us to flush device
3058        // before reusing the above space
3059        let mut transaction = fs
3060            .root_store()
3061            .new_transaction(lock_keys![], Options::default())
3062            .await
3063            .expect("new failed");
3064        let target_len = 1500 * fs.block_size();
3065        while device_ranges.iter().map(|i| i.length().unwrap()).sum::<u64>() != target_len {
3066            let len = target_len - device_ranges.iter().map(|i| i.length().unwrap()).sum::<u64>();
3067            device_ranges.push(
3068                allocator
3069                    .allocate(&mut transaction, STORE_OBJECT_ID, len)
3070                    .await
3071                    .expect("allocate failed"),
3072            );
3073        }
3074        transaction.commit().await.expect("commit failed");
3075
3076        assert_eq!(
3077            fs.block_size() * 1500,
3078            *allocator.get_owner_allocated_bytes().entry(STORE_OBJECT_ID).or_default()
3079        );
3080    }
3081
3082    #[fuchsia::test]
3083    async fn test_flush() {
3084        const STORE_OBJECT_ID: u64 = 99;
3085
3086        let mut device_ranges = Vec::new();
3087        let device = {
3088            let (fs, allocator) = test_fs().await;
3089            let mut transaction = fs
3090                .root_store()
3091                .new_transaction(lock_keys![], Options::default())
3092                .await
3093                .expect("new failed");
3094            device_ranges.push(
3095                allocator
3096                    .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3097                    .await
3098                    .expect("allocate failed"),
3099            );
3100            device_ranges.push(
3101                allocator
3102                    .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3103                    .await
3104                    .expect("allocate failed"),
3105            );
3106            device_ranges.push(
3107                allocator
3108                    .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3109                    .await
3110                    .expect("allocate failed"),
3111            );
3112            transaction.commit().await.expect("commit failed");
3113
3114            allocator.flush().await.expect("flush failed");
3115
3116            fs.close().await.expect("close failed");
3117            fs.take_device().await
3118        };
3119
3120        device.reopen(false);
3121        let fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
3122        let allocator = fs.allocator();
3123
3124        let allocated = collect_allocations(&allocator).await;
3125
3126        // Make sure the ranges we allocated earlier are still allocated.
3127        for i in &device_ranges {
3128            let mut overlapping = 0;
3129            for j in &allocated {
3130                overlapping += overlap(i, j);
3131            }
3132            assert_eq!(overlapping, i.length().unwrap(), "Range {i:?} not allocated");
3133        }
3134
3135        let mut transaction = fs
3136            .root_store()
3137            .new_transaction(lock_keys![], Options::default())
3138            .await
3139            .expect("new failed");
3140        let range = allocator
3141            .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3142            .await
3143            .expect("allocate failed");
3144
3145        // Make sure the range just allocated doesn't overlap any other allocated ranges.
3146        for r in &allocated {
3147            assert_eq!(overlap(r, &range), 0);
3148        }
3149        transaction.commit().await.expect("commit failed");
3150    }
3151
3152    #[fuchsia::test]
3153    async fn test_dropped_transaction() {
3154        const STORE_OBJECT_ID: u64 = 99;
3155        let (fs, allocator) = test_fs().await;
3156        let allocated_range = {
3157            let mut transaction = fs
3158                .root_store()
3159                .new_transaction(lock_keys![], Options::default())
3160                .await
3161                .expect("new_transaction failed");
3162            allocator
3163                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3164                .await
3165                .expect("allocate failed")
3166        };
3167        // After dropping the transaction and attempting to allocate again, we should end up with
3168        // the same range because the reservation should have been released.
3169        let mut transaction = fs
3170            .root_store()
3171            .new_transaction(lock_keys![], Options::default())
3172            .await
3173            .expect("new_transaction failed");
3174        assert_eq!(
3175            allocator
3176                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3177                .await
3178                .expect("allocate failed"),
3179            allocated_range
3180        );
3181    }
3182
3183    #[fuchsia::test]
3184    async fn test_cleanup_removed_owner() {
3185        const STORE_OBJECT_ID: u64 = 99;
3186        let device = {
3187            let (fs, allocator) = test_fs().await;
3188
3189            assert!(!allocator.get_owner_allocated_bytes().contains_key(&STORE_OBJECT_ID));
3190            {
3191                let mut transaction = fs
3192                    .root_store()
3193                    .new_transaction(lock_keys![], Options::default())
3194                    .await
3195                    .unwrap();
3196                allocator
3197                    .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3198                    .await
3199                    .expect("Allocating");
3200                transaction.commit().await.expect("Committing.");
3201            }
3202            allocator.flush().await.expect("Flushing");
3203            assert!(allocator.get_owner_allocated_bytes().contains_key(&STORE_OBJECT_ID));
3204            {
3205                let mut transaction = fs
3206                    .root_store()
3207                    .new_transaction(lock_keys![], Options::default())
3208                    .await
3209                    .unwrap();
3210                allocator.mark_for_deletion(&mut transaction, STORE_OBJECT_ID);
3211                transaction.commit().await.expect("Committing.");
3212            }
3213            assert!(!allocator.get_owner_allocated_bytes().contains_key(&STORE_OBJECT_ID));
3214            fs.close().await.expect("Closing");
3215            fs.take_device().await
3216        };
3217
3218        device.reopen(false);
3219        let fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
3220        let allocator = fs.allocator();
3221        assert!(!allocator.get_owner_allocated_bytes().contains_key(&STORE_OBJECT_ID));
3222    }
3223
3224    #[fuchsia::test]
3225    async fn test_allocated_bytes() {
3226        const STORE_OBJECT_ID: u64 = 99;
3227        let (fs, allocator) = test_fs().await;
3228
3229        let initial_allocated_bytes = allocator.get_allocated_bytes();
3230
3231        // Verify allocated_bytes reflects allocation changes.
3232        let allocated_bytes = initial_allocated_bytes + fs.block_size();
3233        let allocated_range = {
3234            let mut transaction = fs
3235                .root_store()
3236                .new_transaction(lock_keys![], Options::default())
3237                .await
3238                .expect("new_transaction failed");
3239            let range = allocator
3240                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3241                .await
3242                .expect("allocate failed");
3243            transaction.commit().await.expect("commit failed");
3244            assert_eq!(allocator.get_allocated_bytes(), allocated_bytes);
3245            range
3246        };
3247
3248        {
3249            let mut transaction = fs
3250                .root_store()
3251                .new_transaction(lock_keys![], Options::default())
3252                .await
3253                .expect("new_transaction failed");
3254            allocator
3255                .allocate(&mut transaction, STORE_OBJECT_ID, fs.block_size().get())
3256                .await
3257                .expect("allocate failed");
3258
3259            // Prior to committing, the count of allocated bytes shouldn't change.
3260            assert_eq!(allocator.get_allocated_bytes(), allocated_bytes);
3261        }
3262
3263        // After dropping the prior transaction, the allocated bytes still shouldn't have changed.
3264        assert_eq!(allocator.get_allocated_bytes(), allocated_bytes);
3265
3266        // Verify allocated_bytes reflects deallocations.
3267        let deallocate_range = allocated_range.start + 20..allocated_range.end - 20;
3268        let mut transaction = fs
3269            .root_store()
3270            .new_transaction(lock_keys![], Options::default())
3271            .await
3272            .expect("new failed");
3273        allocator
3274            .deallocate(&mut transaction, STORE_OBJECT_ID, deallocate_range)
3275            .await
3276            .expect("deallocate failed");
3277
3278        // Before committing, there should be no change.
3279        assert_eq!(allocator.get_allocated_bytes(), allocated_bytes);
3280
3281        transaction.commit().await.expect("commit failed");
3282
3283        // After committing, all but 40 bytes should remain allocated.
3284        assert_eq!(allocator.get_allocated_bytes(), initial_allocated_bytes + 40);
3285    }
3286
3287    #[fuchsia::test]
3288    async fn test_persist_bytes_limit() {
3289        const LIMIT: u64 = 12345;
3290        const OWNER_ID: u64 = 12;
3291
3292        let (fs, allocator) = test_fs().await;
3293        {
3294            let mut transaction = fs
3295                .root_store()
3296                .new_transaction(lock_keys![], Options::default())
3297                .await
3298                .expect("new_transaction failed");
3299            allocator
3300                .set_bytes_limit(&mut transaction, OWNER_ID, LIMIT)
3301                .expect("Failed to set limit.");
3302            assert!(allocator.inner.lock().info.limit_bytes.get(&OWNER_ID).is_none());
3303            transaction.commit().await.expect("Failed to commit transaction");
3304            let bytes: u64 = *allocator
3305                .inner
3306                .lock()
3307                .info
3308                .limit_bytes
3309                .get(&OWNER_ID)
3310                .expect("Failed to find limit");
3311            assert_eq!(LIMIT, bytes);
3312        }
3313    }
3314
3315    /// Given a sorted list of non-overlapping ranges, this will coalesce adjacent ranges.
3316    /// This allows comparison of equivalent sets of ranges which may occur due to differences
3317    /// across allocator strategies.
3318    fn coalesce_ranges(ranges: Vec<Range<u64>>) -> Vec<Range<u64>> {
3319        let mut coalesced = Vec::new();
3320        let mut prev: Option<Range<u64>> = None;
3321        for range in ranges {
3322            if let Some(prev_range) = &mut prev {
3323                if range.start == prev_range.end {
3324                    prev_range.end = range.end;
3325                } else {
3326                    coalesced.push(prev_range.clone());
3327                    prev = Some(range);
3328                }
3329            } else {
3330                prev = Some(range);
3331            }
3332        }
3333        if let Some(prev_range) = prev {
3334            coalesced.push(prev_range);
3335        }
3336        coalesced
3337    }
3338
3339    #[fuchsia::test]
3340    async fn test_take_for_trimming() {
3341        const STORE_OBJECT_ID: u64 = 99;
3342
3343        // Allocate a large chunk, then free a few bits of it, so we have free chunks interleaved
3344        // with allocated chunks.
3345        let allocated_range;
3346        let expected_free_ranges;
3347        let device = {
3348            let (fs, allocator) = test_fs().await;
3349            let bs = fs.block_size();
3350            let mut transaction = fs
3351                .root_store()
3352                .new_transaction(lock_keys![], Options::default())
3353                .await
3354                .expect("new failed");
3355            allocated_range = allocator
3356                .allocate(&mut transaction, STORE_OBJECT_ID, 32 * bs)
3357                .await
3358                .expect("allocate failed");
3359            transaction.commit().await.expect("commit failed");
3360
3361            let mut transaction = fs
3362                .root_store()
3363                .new_transaction(lock_keys![], Options::default())
3364                .await
3365                .expect("new failed");
3366            let base = allocated_range.start;
3367            expected_free_ranges = vec![
3368                base..(base + (bs * 1)),
3369                (base + (bs * 2))..(base + (bs * 3)),
3370                // Note that the next three ranges are adjacent and will be treated as one free
3371                // range once applied.  We separate them here to exercise the handling of "large"
3372                // free ranges.
3373                (base + (bs * 4))..(base + (bs * 8)),
3374                (base + (bs * 8))..(base + (bs * 12)),
3375                (base + (bs * 12))..(base + (bs * 13)),
3376                (base + (bs * 29))..(base + (bs * 30)),
3377            ];
3378            for range in &expected_free_ranges {
3379                allocator
3380                    .deallocate(&mut transaction, STORE_OBJECT_ID, range.clone())
3381                    .await
3382                    .expect("deallocate failed");
3383            }
3384            transaction.commit().await.expect("commit failed");
3385
3386            allocator.flush().await.expect("flush failed");
3387
3388            fs.close().await.expect("close failed");
3389            fs.take_device().await
3390        };
3391
3392        device.reopen(false);
3393        let fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
3394        let allocator = fs.allocator();
3395
3396        // These values were picked so that each of them would be the reason why
3397        // collect_free_extents finished, and so we would return after partially processing one of
3398        // the free extents.
3399        let max_extent_size = (fs.block_size() * 4) as usize;
3400        const EXTENTS_PER_BATCH: usize = 2;
3401        let mut free_ranges = vec![];
3402        let mut offset = allocated_range.start;
3403        while offset < allocated_range.end {
3404            let free = allocator
3405                .take_for_trimming(offset, max_extent_size, EXTENTS_PER_BATCH)
3406                .await
3407                .expect("take_for_trimming failed");
3408            free_ranges.extend(
3409                free.extents().iter().filter(|range| range.end <= allocated_range.end).cloned(),
3410            );
3411            offset = free.extents().last().expect("Unexpectedly hit the end of free extents").end;
3412        }
3413        // Coalesce adjacent free ranges because the allocator may return smaller aligned chunks
3414        // but the overall range should always be equivalent.
3415        let coalesced_free_ranges = coalesce_ranges(free_ranges);
3416        let coalesced_expected_free_ranges = coalesce_ranges(expected_free_ranges);
3417
3418        assert_eq!(coalesced_free_ranges, coalesced_expected_free_ranges);
3419    }
3420
3421    #[fuchsia::test]
3422    async fn test_allocations_wait_for_free_extents() {
3423        const STORE_OBJECT_ID: u64 = 99;
3424        let (fs, allocator) = test_fs().await;
3425        let allocator_clone = allocator.clone();
3426
3427        let mut transaction = fs
3428            .root_store()
3429            .new_transaction(lock_keys![], Options::default())
3430            .await
3431            .expect("new failed");
3432
3433        // Tie up all of the free extents on the device, and make sure allocations block.
3434        let max_extent_size = fs.device().size() as usize;
3435        const EXTENTS_PER_BATCH: usize = usize::MAX;
3436
3437        // HACK: Treat `trimmable_extents` as being locked by `trim_done` (i.e. it should only be
3438        // accessed whilst `trim_done` is locked). We can't combine them into the same mutex,
3439        // because the inner type would be "poisoned" by the lifetime parameter of
3440        // `trimmable_extents` (which is in the lifetime of `allocator`), and then we can't move it
3441        // into `alloc_task` which would require a `'static` lifetime.
3442        let trim_done = Arc::new(Mutex::new(false));
3443        let trimmable_extents = allocator
3444            .take_for_trimming(0, max_extent_size, EXTENTS_PER_BATCH)
3445            .await
3446            .expect("take_for_trimming failed");
3447
3448        let trim_done_clone = trim_done.clone();
3449        let bs = fs.block_size();
3450        let alloc_task = fasync::Task::spawn(async move {
3451            allocator_clone
3452                .allocate(&mut transaction, STORE_OBJECT_ID, bs.get())
3453                .await
3454                .expect("allocate should fail");
3455            {
3456                assert!(*trim_done_clone.lock(), "Allocation finished before trim completed");
3457            }
3458            transaction.commit().await.expect("commit failed");
3459        });
3460
3461        // Add a small delay to simulate the trim taking some nonzero amount of time.  Otherwise,
3462        // this will almost certainly always beat the allocation attempt.
3463        fasync::Timer::new(std::time::Duration::from_millis(100)).await;
3464
3465        // Once the free extents are released, the task should unblock.
3466        {
3467            let mut trim_done = trim_done.lock();
3468            std::mem::drop(trimmable_extents);
3469            *trim_done = true;
3470        }
3471
3472        alloc_task.await;
3473    }
3474
3475    #[fuchsia::test]
3476    async fn test_allocation_with_reservation_not_multiple_of_block_size() {
3477        const STORE_OBJECT_ID: u64 = 99;
3478        let (fs, allocator) = test_fs().await;
3479
3480        // Reserve an amount that isn't a multiple of the block size.
3481        const RESERVATION_AMOUNT: u64 = TRANSACTION_METADATA_MAX_AMOUNT + 5000;
3482        let reservation =
3483            allocator.clone().reserve(Some(STORE_OBJECT_ID), RESERVATION_AMOUNT).unwrap();
3484
3485        let mut transaction = fs
3486            .root_store()
3487            .new_transaction(
3488                lock_keys![],
3489                Options {
3490                    reservation: ReservationOptions::Hold(&reservation),
3491                    ..Options::default()
3492                },
3493            )
3494            .await
3495            .expect("new failed");
3496
3497        let range = allocator
3498            .allocate(
3499                &mut transaction,
3500                STORE_OBJECT_ID,
3501                fs.block_size().align_up(RESERVATION_AMOUNT).unwrap(),
3502            )
3503            .await
3504            .expect("allocate faiiled");
3505        assert!(fs.block_size().is_aligned(range.end - range.start));
3506
3507        println!("{}", range.end - range.start);
3508    }
3509
3510    #[fuchsia::test]
3511    async fn test_concurrent_take_for_trimming_returns_error() {
3512        let (fs, allocator) = test_fs().await;
3513        let max_extent_size = fs.device().size() as usize;
3514        const EXTENTS_PER_BATCH: usize = usize::MAX;
3515
3516        {
3517            let _trimmable_extents = allocator
3518                .take_for_trimming(0, max_extent_size, EXTENTS_PER_BATCH)
3519                .await
3520                .expect("take_for_trimming failed");
3521
3522            let res = allocator.take_for_trimming(0, max_extent_size, EXTENTS_PER_BATCH).await;
3523            assert!(matches!(res, Err(e) if FxfsError::AlreadyBound.matches(&e)));
3524        }
3525
3526        fs.close().await.expect("close failed");
3527    }
3528}