Skip to main content

fxfs/object_store/
transaction.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
5use crate::checksum::Checksum;
6use crate::filesystem::FxFilesystem;
7use crate::log::*;
8use crate::lsm_tree::types::Item;
9use crate::object_handle::INVALID_OBJECT_ID;
10use crate::object_store::allocator::{AllocatorItem, Reservation};
11use crate::object_store::object_manager::{ObjectManager, reserved_space_from_journal_usage};
12use crate::object_store::object_record::{
13    FxfsKey, FxfsKeyV49, ObjectItem, ObjectItemV56, ObjectKey, ObjectKeyData, ObjectValue,
14    ProjectProperty,
15};
16use crate::object_store::{AttributeId, AttributeKey, ProjectId};
17use crate::serialized_types::{Migrate, Versioned, migrate_to_version};
18use anyhow::Error;
19use either::{Either, Left, Right};
20use fprint::TypeFingerprint;
21use fuchsia_sync::Mutex;
22use futures::future::poll_fn;
23use futures::pin_mut;
24use rustc_hash::FxHashMap as HashMap;
25use scopeguard::ScopeGuard;
26use serde::{Deserialize, Serialize};
27use std::cell::UnsafeCell;
28use std::cmp::Ordering;
29use std::collections::hash_map::Entry;
30use std::collections::{BTreeSet, btree_set};
31use std::iter::Peekable;
32use std::marker::PhantomPinned;
33use std::ops::{Deref, DerefMut, Range};
34use std::sync::Arc;
35use std::task::{Poll, Waker};
36use std::{fmt, mem};
37
38/// This allows for special handling of certain transactions such as deletes and the
39/// extension of Journal extents. For most other use cases it is appropriate to use
40/// `default()` here.
41#[derive(Clone, Copy, Default)]
42pub struct Options<'a> {
43    /// If true, don't check for low journal space.  This should be true for any transactions that
44    /// might alleviate journal space (i.e. compaction).
45    pub skip_journal_checks: bool,
46
47    /// If true, borrow metadata space from the metadata reservation.  This setting should be set to
48    /// true for any transaction that will either not affect space usage after compaction
49    /// (e.g. setting attributes), or reduce space usage (e.g. unlinking).  Otherwise, a transaction
50    /// might fail with an out-of-space error.
51    pub borrow_metadata_space: bool,
52
53    /// If specified, a reservation to be used with the transaction.  If not set, any allocations
54    /// that are part of this transaction will have to take their chances, and will fail if there is
55    /// no free space.  The intention is that this should be used for things like the journal which
56    /// require guaranteed space.
57    pub allocator_reservation: Option<&'a Reservation>,
58}
59
60// This is the amount of space that we reserve for metadata when we are creating a new transaction.
61// A transaction should not take more than this.  This is expressed in terms of space occupied in
62// the journal; transactions must not take up more space in the journal than the number below.  The
63// amount chosen here must be large enough for the maximum possible transaction that can be created,
64// so transactions always need to be bounded which might involve splitting an operation up into
65// smaller transactions.
66pub const TRANSACTION_MAX_JOURNAL_USAGE: u64 = 24_576;
67pub const TRANSACTION_METADATA_MAX_AMOUNT: u64 =
68    reserved_space_from_journal_usage(TRANSACTION_MAX_JOURNAL_USAGE);
69
70#[must_use]
71pub struct TransactionLocks<'a>(pub WriteGuard<'a>);
72
73/// The journal consists of these records which will be replayed at mount time.  Within a
74/// transaction, these are stored as a set which allows some mutations to be deduplicated and found
75/// (and we require custom comparison functions below).  For example, we need to be able to find
76/// object size changes.
77pub type Mutation = MutationV57;
78
79#[derive(
80    Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint, Versioned,
81)]
82#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
83pub enum MutationV57 {
84    ObjectStore(ObjectStoreMutationV56),
85    EncryptedObjectStore(#[serde(with = "crate::zerocopy_serialization")] Box<[u8]>),
86    Allocator(AllocatorMutationV32),
87    /// Indicates the beginning of a flush. This would typically involve sealing a tree.
88    BeginFlush,
89    /// Indicates the end of a flush. This would typically involve replacing the immutable layers
90    /// with compacted ones.
91    EndFlush,
92    /// Volume has been deleted. Requires we remove it from the set of managed ObjectStore.
93    DeleteVolume,
94    UpdateBorrowed(u64),
95    UpdateMutationsKey(UpdateMutationsKey),
96    CreateInternalDir(u64),
97}
98
99#[derive(Migrate, Clone, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
100#[migrate_to_version(MutationV57)]
101pub enum MutationV56 {
102    ObjectStore(ObjectStoreMutationV56),
103    EncryptedObjectStore(#[serde(with = "crate::zerocopy_serialization")] Box<[u8]>),
104    Allocator(AllocatorMutationV32),
105    BeginFlush,
106    EndFlush,
107    DeleteVolume,
108    UpdateBorrowed(u64),
109    UpdateMutationsKey(UpdateMutationsKey),
110    CreateInternalDir(u64),
111}
112
113impl Mutation {
114    pub fn insert_object(key: ObjectKey, value: ObjectValue) -> Self {
115        Mutation::ObjectStore(ObjectStoreMutation {
116            item: Item::new(key, value),
117            op: Operation::Insert,
118        })
119    }
120
121    pub fn replace_or_insert_object(key: ObjectKey, value: ObjectValue) -> Self {
122        Mutation::ObjectStore(ObjectStoreMutation {
123            item: Item::new(key, value),
124            op: Operation::ReplaceOrInsert,
125        })
126    }
127
128    pub fn merge_object(key: ObjectKey, value: ObjectValue) -> Self {
129        Mutation::ObjectStore(ObjectStoreMutation {
130            item: Item::new(key, value),
131            op: Operation::Merge,
132        })
133    }
134
135    pub fn update_mutations_key(key: FxfsKey) -> Self {
136        Mutation::UpdateMutationsKey(key.into())
137    }
138}
139
140// We have custom comparison functions for mutations that just use the key, rather than the key and
141// value that would be used by default so that we can deduplicate and find mutations (see
142// get_object_mutation below).
143pub type ObjectStoreMutation = ObjectStoreMutationV56;
144
145#[derive(Clone, Debug, Serialize, Deserialize, TypeFingerprint)]
146#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
147pub struct ObjectStoreMutationV56 {
148    pub item: ObjectItemV56,
149    pub op: Operation,
150}
151
152/// The different LSM tree operations that can be performed as part of a mutation.
153pub type Operation = OperationV32;
154
155#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, TypeFingerprint)]
156#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
157pub enum OperationV32 {
158    Insert,
159    ReplaceOrInsert,
160    Merge,
161}
162
163impl Ord for ObjectStoreMutation {
164    fn cmp(&self, other: &Self) -> Ordering {
165        self.item.key.cmp(&other.item.key)
166    }
167}
168
169impl PartialOrd for ObjectStoreMutation {
170    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
171        Some(self.cmp(other))
172    }
173}
174
175impl PartialEq for ObjectStoreMutation {
176    fn eq(&self, other: &Self) -> bool {
177        self.item.key.eq(&other.item.key)
178    }
179}
180
181impl Eq for ObjectStoreMutation {}
182
183impl Ord for AllocatorItem {
184    fn cmp(&self, other: &Self) -> Ordering {
185        self.key.cmp(&other.key)
186    }
187}
188
189impl PartialOrd for AllocatorItem {
190    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
191        Some(self.cmp(other))
192    }
193}
194
195/// Same as std::ops::Range but with Ord and PartialOrd support, sorted first by start of the range,
196/// then by the end.
197pub type DeviceRange = DeviceRangeV32;
198
199#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TypeFingerprint)]
200#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
201pub struct DeviceRangeV32(pub Range<u64>);
202
203impl Deref for DeviceRange {
204    type Target = Range<u64>;
205
206    fn deref(&self) -> &Self::Target {
207        &self.0
208    }
209}
210
211impl DerefMut for DeviceRange {
212    fn deref_mut(&mut self) -> &mut Self::Target {
213        &mut self.0
214    }
215}
216
217impl From<Range<u64>> for DeviceRange {
218    fn from(range: Range<u64>) -> Self {
219        Self(range)
220    }
221}
222
223impl Into<Range<u64>> for DeviceRange {
224    fn into(self) -> Range<u64> {
225        self.0
226    }
227}
228
229impl Ord for DeviceRange {
230    fn cmp(&self, other: &Self) -> Ordering {
231        self.start.cmp(&other.start).then(self.end.cmp(&other.end))
232    }
233}
234
235impl PartialOrd for DeviceRange {
236    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
237        Some(self.cmp(other))
238    }
239}
240
241pub type AllocatorMutation = AllocatorMutationV32;
242
243#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint)]
244#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
245pub enum AllocatorMutationV32 {
246    Allocate {
247        device_range: DeviceRangeV32,
248        owner_object_id: u64,
249    },
250    Deallocate {
251        device_range: DeviceRangeV32,
252        owner_object_id: u64,
253    },
254    SetLimit {
255        owner_object_id: u64,
256        bytes: u64,
257    },
258    /// Marks all extents with a given owner_object_id for deletion.
259    /// Used to free space allocated to encrypted ObjectStore where we may not have the key.
260    /// Note that the actual deletion time is undefined so this should never be used where an
261    /// ObjectStore is still in use due to a high risk of corruption. Similarly, owner_object_id
262    /// should never be reused for the same reasons.
263    MarkForDeletion(u64),
264}
265
266pub type UpdateMutationsKey = UpdateMutationsKeyV49;
267
268#[derive(Clone, Debug, Serialize, Deserialize, TypeFingerprint)]
269pub struct UpdateMutationsKeyV49(pub FxfsKeyV49);
270
271impl From<UpdateMutationsKey> for FxfsKey {
272    fn from(outer: UpdateMutationsKey) -> Self {
273        outer.0
274    }
275}
276
277impl From<FxfsKey> for UpdateMutationsKey {
278    fn from(inner: FxfsKey) -> Self {
279        Self(inner)
280    }
281}
282
283#[cfg(fuzz)]
284impl<'a> arbitrary::Arbitrary<'a> for UpdateMutationsKey {
285    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
286        Ok(UpdateMutationsKey::from(FxfsKey::arbitrary(u).unwrap()))
287    }
288}
289
290impl Ord for UpdateMutationsKey {
291    fn cmp(&self, other: &Self) -> Ordering {
292        (self as *const UpdateMutationsKey).cmp(&(other as *const _))
293    }
294}
295
296impl PartialOrd for UpdateMutationsKey {
297    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
298        Some(self.cmp(other))
299    }
300}
301
302impl Eq for UpdateMutationsKey {}
303
304impl PartialEq for UpdateMutationsKey {
305    fn eq(&self, other: &Self) -> bool {
306        std::ptr::eq(self, other)
307    }
308}
309
310/// When creating a transaction, locks typically need to be held to prevent two or more writers
311/// trying to make conflicting mutations at the same time.  LockKeys are used for this.
312/// NOTE: Ordering is important here!  The lock manager sorts the list of locks in a transaction
313/// to acquire them in a consistent order, but there is a special case for the Flush lock.
314/// The Flush lock is taken when we flush an LSM tree (e.g. an object store), and is held for
315/// several transactions.  As such, it must come first in the lock acquisition ordering, so that
316/// other transactions using the Flush lock have the same ordering as in flushing.
317#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Copy)]
318pub enum LockKey {
319    /// Used to lock flushing an object.
320    Flush {
321        object_id: u64,
322    },
323
324    /// Used to lock changes to a particular object attribute (e.g. writes).
325    ObjectAttribute {
326        store_object_id: u64,
327        object_id: u64,
328        attribute_id: AttributeId,
329    },
330
331    /// Used to lock changes to a particular object (e.g. adding a child to a directory).
332    Object {
333        store_object_id: u64,
334        object_id: u64,
335    },
336
337    ProjectId {
338        store_object_id: u64,
339        project_id: ProjectId,
340    },
341
342    /// Used to lock any truncate operations for a file.
343    Truncate {
344        store_object_id: u64,
345        object_id: u64,
346    },
347
348    /// A lock used when getting or creating the internal directory.
349    InternalDirectory {
350        store_object_id: u64,
351    },
352
353    /// Used to serialize pre caching of keys.  The lock ordering is different for this: it is
354    /// acquired in `Filesystem::commit_transaction` and happens *after* other keys have been
355    /// promoted to write locks, but before the commit lock.
356    PreCacheKeys {
357        store_object_id: u64,
358    },
359}
360
361impl LockKey {
362    pub const fn object_attribute(
363        store_object_id: u64,
364        object_id: u64,
365        attribute_id: AttributeId,
366    ) -> Self {
367        LockKey::ObjectAttribute { store_object_id, object_id, attribute_id }
368    }
369
370    pub const fn object(store_object_id: u64, object_id: u64) -> Self {
371        LockKey::Object { store_object_id, object_id }
372    }
373
374    pub const fn flush(object_id: u64) -> Self {
375        LockKey::Flush { object_id }
376    }
377
378    pub const fn truncate(store_object_id: u64, object_id: u64) -> Self {
379        LockKey::Truncate { store_object_id, object_id }
380    }
381
382    pub const fn pre_cache_keys(store_object_id: u64) -> Self {
383        LockKey::PreCacheKeys { store_object_id }
384    }
385}
386
387/// A container for holding `LockKey` objects. Can store a single `LockKey` inline.
388#[derive(Clone, Debug)]
389pub enum LockKeys {
390    None,
391    Inline(LockKey),
392    Vec(Vec<LockKey>),
393}
394
395impl LockKeys {
396    pub fn with_capacity(capacity: usize) -> Self {
397        if capacity > 1 { LockKeys::Vec(Vec::with_capacity(capacity)) } else { LockKeys::None }
398    }
399
400    pub fn push(&mut self, key: LockKey) {
401        match self {
402            Self::None => *self = LockKeys::Inline(key),
403            Self::Inline(inline) => {
404                *self = LockKeys::Vec(vec![*inline, key]);
405            }
406            Self::Vec(vec) => vec.push(key),
407        }
408    }
409
410    pub fn truncate(&mut self, len: usize) {
411        match self {
412            Self::None => {}
413            Self::Inline(_) => {
414                if len == 0 {
415                    *self = Self::None;
416                }
417            }
418            Self::Vec(vec) => vec.truncate(len),
419        }
420    }
421
422    fn len(&self) -> usize {
423        match self {
424            Self::None => 0,
425            Self::Inline(_) => 1,
426            Self::Vec(vec) => vec.len(),
427        }
428    }
429
430    fn contains(&self, key: &LockKey) -> bool {
431        match self {
432            Self::None => false,
433            Self::Inline(single) => single == key,
434            Self::Vec(vec) => vec.contains(key),
435        }
436    }
437
438    fn sort_unstable(&mut self) {
439        match self {
440            Self::Vec(vec) => vec.sort_unstable(),
441            _ => {}
442        }
443    }
444
445    fn dedup(&mut self) {
446        match self {
447            Self::Vec(vec) => vec.dedup(),
448            _ => {}
449        }
450    }
451
452    fn iter(&self) -> LockKeysIter<'_> {
453        match self {
454            LockKeys::None => LockKeysIter::None,
455            LockKeys::Inline(key) => LockKeysIter::Inline(key),
456            LockKeys::Vec(keys) => LockKeysIter::Vec(keys.iter()),
457        }
458    }
459}
460
461enum LockKeysIter<'a> {
462    None,
463    Inline(&'a LockKey),
464    Vec(std::slice::Iter<'a, LockKey>),
465}
466
467impl<'a> Iterator for LockKeysIter<'a> {
468    type Item = &'a LockKey;
469    fn next(&mut self) -> Option<Self::Item> {
470        match self {
471            Self::None => None,
472            Self::Inline(inline) => {
473                let next = *inline;
474                *self = Self::None;
475                Some(next)
476            }
477            Self::Vec(vec) => vec.next(),
478        }
479    }
480}
481
482impl Default for LockKeys {
483    fn default() -> Self {
484        LockKeys::None
485    }
486}
487
488#[macro_export]
489macro_rules! lock_keys {
490    () => {
491        $crate::object_store::transaction::LockKeys::None
492    };
493    ($lock_key:expr $(,)?) => {
494        $crate::object_store::transaction::LockKeys::Inline($lock_key)
495    };
496    ($($lock_keys:expr),+ $(,)?) => {
497        $crate::object_store::transaction::LockKeys::Vec(vec![$($lock_keys),+])
498    };
499}
500pub use lock_keys;
501
502/// Mutations in a transaction can be associated with an object so that when mutations are applied,
503/// updates can be applied to in-memory structures. For example, we cache object sizes, so when a
504/// size change is applied, we can update the cached object size.
505pub trait AssociatedObject: Send + Sync {
506    fn will_apply_mutation(&self, _mutation: &Mutation, _object_id: u64, _manager: &ObjectManager) {
507    }
508}
509
510pub enum AssocObj<'a> {
511    None,
512    Borrowed(&'a dyn AssociatedObject),
513    Owned(Box<dyn AssociatedObject>),
514}
515
516impl AssocObj<'_> {
517    pub fn map<R, F: FnOnce(&dyn AssociatedObject) -> R>(&self, f: F) -> Option<R> {
518        match self {
519            AssocObj::None => None,
520            AssocObj::Borrowed(b) => Some(f(*b)),
521            AssocObj::Owned(o) => Some(f(o.as_ref())),
522        }
523    }
524}
525
526pub struct TxnMutation<'a> {
527    // This, at time of writing, is either the object ID of an object store, or the object ID of the
528    // allocator.  In the case of an object mutation, there's another object ID in the mutation
529    // record that would be for the object actually being changed.
530    pub object_id: u64,
531
532    // The actual mutation.  This gets serialized to the journal.
533    pub mutation: Mutation,
534
535    // An optional associated object for the mutation.  During replay, there will always be no
536    // associated object.
537    pub associated_object: AssocObj<'a>,
538}
539
540// We store TxnMutation in a set, and for that, we only use object_id and mutation and not the
541// associated object or checksum.
542//
543// WARNING: It is critical that `object_id` (which corresponds to the store ID for store mutations)
544// remains the primary key for sorting. The commit pipeline (`commit_transaction`) relies on
545// the mutations being sorted by `object_id` to acquire store locks in a consistent order,
546// preventing deadlocks.
547impl Ord for TxnMutation<'_> {
548    fn cmp(&self, other: &Self) -> Ordering {
549        self.object_id.cmp(&other.object_id).then_with(|| self.mutation.cmp(&other.mutation))
550    }
551}
552
553impl PartialOrd for TxnMutation<'_> {
554    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
555        Some(self.cmp(other))
556    }
557}
558
559impl PartialEq for TxnMutation<'_> {
560    fn eq(&self, other: &Self) -> bool {
561        self.object_id.eq(&other.object_id) && self.mutation.eq(&other.mutation)
562    }
563}
564
565impl Eq for TxnMutation<'_> {}
566
567impl std::fmt::Debug for TxnMutation<'_> {
568    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
569        f.debug_struct("TxnMutation")
570            .field("object_id", &self.object_id)
571            .field("mutation", &self.mutation)
572            .finish()
573    }
574}
575
576/// An iterator over mutations belonging to a single object store within a transaction.
577/// It wraps a mutable reference to a peekable iterator over transaction mutations and yields
578/// mutations until the object ID changes from the object ID peeked at creation time.
579pub struct ObjectMutationIterator<'a, 'b> {
580    iter: &'a mut Peekable<btree_set::Iter<'b, TxnMutation<'b>>>,
581    object_id: u64,
582}
583
584impl<'a, 'b> ObjectMutationIterator<'a, 'b> {
585    pub fn new(iter: &'a mut Peekable<btree_set::Iter<'b, TxnMutation<'b>>>) -> Option<Self> {
586        let object_id = iter.peek()?.object_id;
587        Some(Self { iter, object_id })
588    }
589
590    pub fn object_id(&self) -> u64 {
591        self.object_id
592    }
593}
594
595impl<'b> Iterator for ObjectMutationIterator<'_, 'b> {
596    type Item = &'b Mutation;
597
598    fn next(&mut self) -> Option<Self::Item> {
599        if self.iter.peek().is_some_and(|m| m.object_id == self.object_id) {
600            Some(&self.iter.next().unwrap().mutation)
601        } else {
602            None
603        }
604    }
605}
606
607impl Drop for ObjectMutationIterator<'_, '_> {
608    // Need to have a drop to iterate to the end so that we always finish the current object before
609    // releasing the borrow.
610    fn drop(&mut self) {
611        for _ in self.by_ref() {}
612    }
613}
614
615pub enum MetadataReservation {
616    // The state after a transaction has been dropped.
617    None,
618
619    // Metadata space for this transaction is being borrowed from ObjectManager's metadata
620    // reservation.
621    Borrowed,
622
623    // A metadata reservation was made when the transaction was created.
624    Reservation(Reservation),
625
626    // The metadata space is being _held_ within `allocator_reservation`.
627    Hold(u64),
628}
629
630/// A transaction groups mutation records to be committed as a group.
631pub struct Transaction<'a> {
632    fs: Arc<FxFilesystem>,
633
634    // The mutations that make up this transaction.
635    mutations: BTreeSet<TxnMutation<'a>>,
636
637    // The locks that this transaction currently holds.
638    txn_locks: LockKeys,
639
640    /// If set, an allocator reservation that should be used for allocations.
641    pub allocator_reservation: Option<&'a Reservation>,
642
643    /// The reservation for the metadata for this transaction.
644    pub metadata_reservation: MetadataReservation,
645
646    // Keep track of objects explicitly created by this transaction. No locks are required for them.
647    // Addressed by (owner_object_id, object_id).
648    new_objects: BTreeSet<(u64, u64)>,
649
650    /// Any data checksums which should be evaluated when replaying this transaction.
651    checksums: Vec<(Range<u64>, Vec<Checksum>, bool)>,
652
653    /// Set if this transaction contains data (i.e. includes any extent mutations).
654    includes_write: bool,
655}
656
657impl<'a> Transaction<'a> {
658    /// Creates a new transaction.  `txn_locks` are read locks that can be upgraded to write locks
659    /// at commit time.
660    pub async fn new(
661        fs: Arc<FxFilesystem>,
662        options: Options<'a>,
663        txn_locks: LockKeys,
664    ) -> Result<Transaction<'a>, Error> {
665        fs.add_transaction(options.skip_journal_checks).await;
666        let fs_clone = fs.clone();
667        let guard = scopeguard::guard((), |_| fs_clone.sub_transaction());
668        let (metadata_reservation, allocator_reservation, hold) =
669            fs.reservation_for_transaction(options).await?;
670
671        let txn_locks = {
672            let lock_manager = fs.lock_manager();
673            let mut write_guard = lock_manager.txn_lock(txn_locks).await;
674            std::mem::take(&mut write_guard.0.lock_keys)
675        };
676        let mut transaction = Transaction {
677            fs,
678            mutations: BTreeSet::new(),
679            txn_locks,
680            allocator_reservation: None,
681            metadata_reservation,
682            new_objects: BTreeSet::new(),
683            checksums: Vec::new(),
684            includes_write: false,
685        };
686
687        ScopeGuard::into_inner(guard);
688        hold.map(|h| h.forget()); // Transaction takes ownership from here on.
689        transaction.allocator_reservation = allocator_reservation;
690        Ok(transaction)
691    }
692
693    pub fn mutations(&self) -> &BTreeSet<TxnMutation<'a>> {
694        &self.mutations
695    }
696
697    pub fn take_mutations(&mut self) -> BTreeSet<TxnMutation<'a>> {
698        self.new_objects.clear();
699        mem::take(&mut self.mutations)
700    }
701
702    /// Adds a mutation to this transaction.  If the mutation already exists, it is replaced and the
703    /// old mutation is returned.
704    pub fn add(&mut self, object_id: u64, mutation: Mutation) -> Option<Mutation> {
705        self.add_with_object(object_id, mutation, AssocObj::None)
706    }
707
708    /// Removes a mutation that matches `mutation`.
709    pub fn remove(&mut self, object_id: u64, mutation: Mutation) {
710        let txn_mutation = TxnMutation { object_id, mutation, associated_object: AssocObj::None };
711        if self.mutations.remove(&txn_mutation) {
712            if let Mutation::ObjectStore(ObjectStoreMutation {
713                item:
714                    ObjectItem {
715                        key: ObjectKey { object_id: new_object_id, data: ObjectKeyData::Object },
716                        ..
717                    },
718                op: Operation::Insert,
719            }) = txn_mutation.mutation
720            {
721                self.new_objects.remove(&(object_id, new_object_id));
722            }
723        }
724    }
725
726    /// Adds a mutation with an associated object. If the mutation already exists, it is replaced
727    /// and the old mutation is returned.
728    pub fn add_with_object(
729        &mut self,
730        object_id: u64,
731        mutation: Mutation,
732        associated_object: AssocObj<'a>,
733    ) -> Option<Mutation> {
734        assert!(object_id != INVALID_OBJECT_ID);
735        if let Mutation::ObjectStore(ObjectStoreMutation {
736            item:
737                Item {
738                    key:
739                        ObjectKey { data: ObjectKeyData::Attribute(_, AttributeKey::Extent(_)), .. },
740                    ..
741                },
742            ..
743        }) = &mutation
744        {
745            self.includes_write = true;
746        }
747        let txn_mutation = TxnMutation { object_id, mutation, associated_object };
748        self.verify_locks(&txn_mutation);
749        self.mutations.replace(txn_mutation).map(|m| m.mutation)
750    }
751
752    pub fn add_checksum(&mut self, range: Range<u64>, checksums: Vec<Checksum>, first_write: bool) {
753        self.checksums.push((range, checksums, first_write));
754    }
755
756    pub fn includes_write(&self) -> bool {
757        self.includes_write
758    }
759
760    pub fn checksums(&self) -> &[(Range<u64>, Vec<Checksum>, bool)] {
761        &self.checksums
762    }
763
764    pub fn take_checksums(&mut self) -> Vec<(Range<u64>, Vec<Checksum>, bool)> {
765        std::mem::replace(&mut self.checksums, Vec::new())
766    }
767
768    fn verify_locks(&mut self, mutation: &TxnMutation<'_>) {
769        // It was considered to change the locks from Vec to BTreeSet since we'll now be searching
770        // through it, but given the small set that these locks usually comprise, it probably isn't
771        // worth it.
772        match mutation {
773            TxnMutation {
774                mutation:
775                    Mutation::ObjectStore {
776                        0: ObjectStoreMutation { item: ObjectItem { key, .. }, op },
777                    },
778                object_id: store_object_id,
779                ..
780            } => {
781                match &key.data {
782                    ObjectKeyData::Attribute(..) => {
783                        // TODO(https://fxbug.dev/42073914): Check lock requirements.
784                    }
785                    ObjectKeyData::Child { .. }
786                    | ObjectKeyData::EncryptedChild(_)
787                    | ObjectKeyData::EncryptedCasefoldChild(_)
788                    | ObjectKeyData::CasefoldChild { .. }
789                    | ObjectKeyData::LegacyCasefoldChild(_) => {
790                        let id = key.object_id;
791                        if !self.txn_locks.contains(&LockKey::object(*store_object_id, id))
792                            && !self.new_objects.contains(&(*store_object_id, id))
793                        {
794                            debug_assert!(
795                                false,
796                                "Not holding required lock for object {id} \
797                                in store {store_object_id}"
798                            );
799                            error!(
800                                "Not holding required lock for object {id} in store \
801                                {store_object_id}"
802                            )
803                        }
804                    }
805                    ObjectKeyData::GraveyardEntry { .. } => {
806                        // TODO(https://fxbug.dev/42073911): Check lock requirements.
807                    }
808                    ObjectKeyData::GraveyardAttributeEntry { .. } => {
809                        // TODO(https://fxbug.dev/122974): Check lock requirements.
810                    }
811                    ObjectKeyData::Keys => {
812                        let id = key.object_id;
813                        if !self.txn_locks.contains(&LockKey::object(*store_object_id, id))
814                            && !self.new_objects.contains(&(*store_object_id, id))
815                        {
816                            debug_assert!(
817                                false,
818                                "Not holding required lock for object {id} \
819                                in store {store_object_id}"
820                            );
821                            error!(
822                                "Not holding required lock for object {id} in store \
823                                {store_object_id}"
824                            )
825                        }
826                    }
827                    ObjectKeyData::Object => match op {
828                        // Insert implies the caller expects no object with which to race
829                        Operation::Insert => {
830                            self.new_objects.insert((*store_object_id, key.object_id));
831                        }
832                        Operation::Merge | Operation::ReplaceOrInsert => {
833                            let id = key.object_id;
834                            if !self.txn_locks.contains(&LockKey::object(*store_object_id, id))
835                                && !self.new_objects.contains(&(*store_object_id, id))
836                            {
837                                debug_assert!(
838                                    false,
839                                    "Not holding required lock for object {id} \
840                                    in store {store_object_id}"
841                                );
842                                error!(
843                                    "Not holding required lock for object {id} in store \
844                                    {store_object_id}"
845                                )
846                            }
847                        }
848                    },
849                    ObjectKeyData::Project { project_id, property: ProjectProperty::Limit } => {
850                        if !self.txn_locks.contains(&LockKey::ProjectId {
851                            store_object_id: *store_object_id,
852                            project_id: *project_id,
853                        }) {
854                            debug_assert!(
855                                false,
856                                "Not holding required lock for project limit id {project_id} \
857                                in store {store_object_id}"
858                            );
859                            error!(
860                                "Not holding required lock for project limit id {project_id} in \
861                                store {store_object_id}"
862                            )
863                        }
864                    }
865                    ObjectKeyData::Project { property: ProjectProperty::Usage, .. } => match op {
866                        Operation::Insert | Operation::ReplaceOrInsert => {
867                            panic!(
868                                "Project usage is all handled by merging deltas, no inserts or \
869                                replacements should be used"
870                            );
871                        }
872                        // Merges are all handled like atomic +/- and serialized by the tree locks.
873                        Operation::Merge => {}
874                    },
875                    ObjectKeyData::ExtendedAttribute { .. } => {
876                        let id = key.object_id;
877                        if !self.txn_locks.contains(&LockKey::object(*store_object_id, id))
878                            && !self.new_objects.contains(&(*store_object_id, id))
879                        {
880                            debug_assert!(
881                                false,
882                                "Not holding required lock for object {id} \
883                                in store {store_object_id} while mutating extended attribute"
884                            );
885                            error!(
886                                "Not holding required lock for object {id} in store \
887                                {store_object_id} while mutating extended attribute"
888                            )
889                        }
890                    }
891                }
892            }
893            TxnMutation { mutation: Mutation::DeleteVolume, object_id, .. } => {
894                if !self.txn_locks.contains(&LockKey::flush(*object_id)) {
895                    debug_assert!(false, "Not holding required lock for DeleteVolume");
896                    error!("Not holding required lock for DeleteVolume");
897                }
898            }
899            _ => {}
900        }
901    }
902
903    /// Returns true if this transaction has no mutations.
904    pub fn is_empty(&self) -> bool {
905        self.mutations.is_empty()
906    }
907
908    /// Searches for an existing object mutation within the transaction that has the given key and
909    /// returns it if found.
910    pub fn get_object_mutation(
911        &self,
912        store_object_id: u64,
913        key: ObjectKey,
914    ) -> Option<&ObjectStoreMutation> {
915        if let Some(TxnMutation { mutation: Mutation::ObjectStore(mutation), .. }) =
916            self.mutations.get(&TxnMutation {
917                object_id: store_object_id,
918                mutation: Mutation::insert_object(key, ObjectValue::None),
919                associated_object: AssocObj::None,
920            })
921        {
922            Some(mutation)
923        } else {
924            None
925        }
926    }
927
928    /// Commits a transaction.  If successful, returns the journal offset of the transaction.
929    pub async fn commit(mut self) -> Result<u64, Error> {
930        debug!(txn:? = &self; "Commit");
931        self.fs.clone().commit_transaction(&mut self, |x| x).await
932    }
933
934    /// Commits and then runs the callback whilst locks are held.  The callback accepts a single
935    /// parameter which is the journal offset of the transaction.
936    pub async fn commit_with_callback<R: Send>(
937        mut self,
938        f: impl FnOnce(u64) -> R + Send,
939    ) -> Result<R, Error> {
940        debug!(txn:? = &self; "Commit");
941        self.fs.clone().commit_transaction(&mut self, f).await
942    }
943
944    /// Commits the transaction, but allows the transaction to be used again.  The locks are not
945    /// dropped (but transaction locks will get downgraded to read locks).
946    pub async fn commit_and_continue(&mut self) -> Result<(), Error> {
947        debug!(txn:? = self; "Commit");
948        self.fs.clone().commit_transaction(self, |_| {}).await?;
949        assert!(self.mutations.is_empty());
950        self.fs.lock_manager().downgrade_locks(&self.txn_locks);
951        Ok(())
952    }
953
954    /// Prepares to commit by upgrading transaction locks to write locks and waiting for active
955    /// readers to finish.
956    pub async fn commit_prepare(&self) {
957        self.fs.lock_manager().commit_prepare(self).await;
958    }
959}
960
961impl Drop for Transaction<'_> {
962    fn drop(&mut self) {
963        // Call the filesystem implementation of drop_transaction which should, as a minimum, call
964        // LockManager's drop_transaction to ensure the locks are released.
965        debug!(txn:? = &self; "Drop");
966        self.fs.clone().drop_transaction(self);
967    }
968}
969
970impl std::fmt::Debug for Transaction<'_> {
971    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
972        f.debug_struct("Transaction")
973            .field("mutations", &self.mutations)
974            .field("txn_locks", &self.txn_locks)
975            .field("reservation", &self.allocator_reservation)
976            .finish()
977    }
978}
979
980pub enum BorrowedOrOwned<'a, T> {
981    Borrowed(&'a T),
982    Owned(T),
983}
984
985impl<T> Deref for BorrowedOrOwned<'_, T> {
986    type Target = T;
987
988    fn deref(&self) -> &Self::Target {
989        match self {
990            BorrowedOrOwned::Borrowed(b) => b,
991            BorrowedOrOwned::Owned(o) => &o,
992        }
993    }
994}
995
996impl<'a, T> From<&'a T> for BorrowedOrOwned<'a, T> {
997    fn from(value: &'a T) -> Self {
998        BorrowedOrOwned::Borrowed(value)
999    }
1000}
1001
1002impl<T> From<T> for BorrowedOrOwned<'_, T> {
1003    fn from(value: T) -> Self {
1004        BorrowedOrOwned::Owned(value)
1005    }
1006}
1007
1008/// LockManager holds the locks that transactions might have taken.  A TransactionManager
1009/// implementation would typically have one of these.
1010///
1011/// Three different kinds of locks are supported.  There are read locks and write locks, which are
1012/// as one would expect.  The third kind of lock is a _transaction_ lock (which is also known as an
1013/// upgradeable read lock).  When first acquired, these block other writes (including other
1014/// transaction locks) but do not block reads.  When it is time to commit a transaction, these locks
1015/// are upgraded to full write locks (without ever dropping the lock) and then dropped after
1016/// committing (unless commit_and_continue is used).  This way, reads are only blocked for the
1017/// shortest possible time.  It follows that write locks should be used sparingly.  Locks are
1018/// granted in order with one exception: when a lock is in the initial _transaction_ lock state
1019/// (LockState::Locked), all read locks are allowed even if there are other tasks waiting for the
1020/// lock.  The reason for this is because we allow read locks to be taken by tasks that have taken a
1021/// _transaction_ lock (i.e. recursion is allowed).  In other cases, such as when a writer is
1022/// waiting and there are only readers, readers will queue up behind the writer.
1023///
1024/// To summarize:
1025///
1026/// +-------------------------+-----------------+----------------+------------------+
1027/// |                         | While read_lock | While txn_lock | While write_lock |
1028/// |                         | is held         | is held        | is held          |
1029/// +-------------------------+-----------------+----------------+------------------+
1030/// | Can acquire read_lock?  | true            | true           | false            |
1031/// +-------------------------+-----------------+----------------+------------------+
1032/// | Can acquire txn_lock?   | true            | false          | false            |
1033/// +-------------------------+-----------------+----------------+------------------+
1034/// | Can acquire write_lock? | false           | false          | false            |
1035/// +-------------------------+-----------------+----------------+------------------+
1036pub struct LockManager {
1037    locks: Mutex<Locks>,
1038}
1039
1040struct Locks {
1041    keys: HashMap<LockKey, LockEntry>,
1042}
1043
1044impl Locks {
1045    fn drop_lock(&mut self, key: LockKey, state: LockState) {
1046        if let Entry::Occupied(mut occupied) = self.keys.entry(key) {
1047            let entry = occupied.get_mut();
1048            let wake = match state {
1049                LockState::ReadLock => {
1050                    entry.read_count -= 1;
1051                    entry.read_count == 0
1052                }
1053                // drop_write_locks currently depends on us treating Locked and WriteLock the same.
1054                LockState::Locked | LockState::WriteLock => {
1055                    entry.state = LockState::ReadLock;
1056                    true
1057                }
1058            };
1059            if wake {
1060                // SAFETY: The lock in `LockManager::locks` is held.
1061                unsafe {
1062                    entry.wake();
1063                }
1064                if entry.can_remove() {
1065                    occupied.remove_entry();
1066                }
1067            }
1068        } else {
1069            unreachable!();
1070        }
1071    }
1072
1073    fn drop_read_locks(&mut self, lock_keys: LockKeys) {
1074        for lock in lock_keys.iter() {
1075            self.drop_lock(*lock, LockState::ReadLock);
1076        }
1077    }
1078
1079    fn drop_write_locks(&mut self, lock_keys: LockKeys) {
1080        for lock in lock_keys.iter() {
1081            // This is a bit hacky, but this works for locks in either the Locked or WriteLock
1082            // states.
1083            self.drop_lock(*lock, LockState::WriteLock);
1084        }
1085    }
1086
1087    // Downgrades locks from WriteLock to Locked.
1088    fn downgrade_locks(&mut self, lock_keys: &LockKeys) {
1089        for lock in lock_keys.iter() {
1090            // SAFETY: The lock in `LockManager::locks` is held.
1091            unsafe {
1092                self.keys.get_mut(lock).unwrap().downgrade_lock();
1093            }
1094        }
1095    }
1096}
1097
1098#[derive(Debug)]
1099struct LockEntry {
1100    // In the states that allow readers (ReadLock, Locked), this count can be non-zero
1101    // to indicate the number of active readers.
1102    read_count: u64,
1103
1104    // The state of the lock (see below).
1105    state: LockState,
1106
1107    // A doubly-linked list of wakers that should be woken when they have been granted the lock.
1108    // New wakers are usually chained on to tail, with the exception being the case where a lock in
1109    // state Locked is to be upgraded to WriteLock, but can't because there are readers.  It might
1110    // be possible to use intrusive-collections in the future.
1111    head: *const LockWaker,
1112    tail: *const LockWaker,
1113}
1114
1115unsafe impl Send for LockEntry {}
1116
1117// Represents a node in the waker list.  It is only safe to access the members wrapped by UnsafeCell
1118// when LockManager's `locks` member is locked.
1119struct LockWaker {
1120    // The next and previous pointers in the doubly-linked list.
1121    next: UnsafeCell<*const LockWaker>,
1122    prev: UnsafeCell<*const LockWaker>,
1123
1124    // Holds the lock key for this waker.  This is required so that we can find the associated
1125    // `LockEntry`.
1126    key: LockKey,
1127
1128    // The underlying waker that should be used to wake the task.
1129    waker: UnsafeCell<WakerState>,
1130
1131    // The target state for this waker.
1132    target_state: LockState,
1133
1134    // True if this is an upgrade.
1135    is_upgrade: bool,
1136
1137    // We need to be pinned because these form part of the linked list.
1138    _pin: PhantomPinned,
1139}
1140
1141enum WakerState {
1142    // This is the initial state before the waker has been first polled.
1143    Pending,
1144
1145    // Once polled, this contains the actual waker.
1146    Registered(Waker),
1147
1148    // The waker has been woken and has been granted the lock.
1149    Woken,
1150}
1151
1152impl WakerState {
1153    fn is_woken(&self) -> bool {
1154        matches!(self, WakerState::Woken)
1155    }
1156}
1157
1158unsafe impl Send for LockWaker {}
1159unsafe impl Sync for LockWaker {}
1160
1161impl LockWaker {
1162    // Waits for the waker to be woken.
1163    async fn wait(&self, manager: &LockManager) {
1164        // We must guard against the future being dropped.
1165        let waker_guard = scopeguard::guard((), |_| {
1166            let mut locks = manager.locks.lock();
1167            // SAFETY: We've acquired the lock.
1168            unsafe {
1169                if (*self.waker.get()).is_woken() {
1170                    // We were woken, but didn't actually run, so we must drop the lock.
1171                    if self.is_upgrade {
1172                        locks.keys.get_mut(&self.key).unwrap().downgrade_lock();
1173                    } else {
1174                        locks.drop_lock(self.key, self.target_state);
1175                    }
1176                } else {
1177                    // We haven't been woken but we've been dropped so we must remove ourself from
1178                    // the waker list.
1179                    locks.keys.get_mut(&self.key).unwrap().remove_waker(self);
1180                }
1181            }
1182        });
1183
1184        poll_fn(|cx| {
1185            let _locks = manager.locks.lock();
1186            // SAFETY: We've acquired the lock.
1187            unsafe {
1188                if (*self.waker.get()).is_woken() {
1189                    Poll::Ready(())
1190                } else {
1191                    *self.waker.get() = WakerState::Registered(cx.waker().clone());
1192                    Poll::Pending
1193                }
1194            }
1195        })
1196        .await;
1197
1198        ScopeGuard::into_inner(waker_guard);
1199    }
1200}
1201
1202#[derive(Copy, Clone, Debug, PartialEq)]
1203enum LockState {
1204    // In this state, there are only readers.
1205    ReadLock,
1206
1207    // This state is used for transactions to lock other writers (including other transactions), but
1208    // it still allows readers.
1209    Locked,
1210
1211    // A writer has exclusive access; all other readers and writers are blocked.
1212    WriteLock,
1213}
1214
1215impl LockManager {
1216    pub fn new() -> Self {
1217        LockManager { locks: Mutex::new(Locks { keys: HashMap::default() }) }
1218    }
1219
1220    /// Acquires the locks.  It is the caller's responsibility to ensure that drop_transaction is
1221    /// called when a transaction is dropped i.e. the filesystem's drop_transaction method should
1222    /// call LockManager's drop_transaction method.
1223    pub async fn txn_lock<'a>(&'a self, lock_keys: LockKeys) -> TransactionLocks<'a> {
1224        TransactionLocks(
1225            debug_assert_not_too_long!(self.lock(lock_keys, LockState::Locked)).right().unwrap(),
1226        )
1227    }
1228
1229    // `state` indicates the kind of lock required.  ReadLock means acquire a read lock.  Locked
1230    // means lock other writers, but still allow readers.  WriteLock means acquire a write lock.
1231    async fn lock<'a>(
1232        &'a self,
1233        mut lock_keys: LockKeys,
1234        target_state: LockState,
1235    ) -> Either<ReadGuard<'a>, WriteGuard<'a>> {
1236        let mut guard = match &target_state {
1237            LockState::ReadLock => Left(ReadGuard {
1238                manager: self.into(),
1239                lock_keys: LockKeys::with_capacity(lock_keys.len()),
1240            }),
1241            LockState::Locked | LockState::WriteLock => Right(WriteGuard {
1242                manager: self.into(),
1243                lock_keys: LockKeys::with_capacity(lock_keys.len()),
1244            }),
1245        };
1246        let guard_keys = match &mut guard {
1247            Left(g) => &mut g.lock_keys,
1248            Right(g) => &mut g.lock_keys,
1249        };
1250        lock_keys.sort_unstable();
1251        lock_keys.dedup();
1252        for lock in lock_keys.iter() {
1253            let lock_waker = None;
1254            pin_mut!(lock_waker);
1255            {
1256                let mut locks = self.locks.lock();
1257                match locks.keys.entry(*lock) {
1258                    Entry::Vacant(vacant) => {
1259                        vacant.insert(LockEntry {
1260                            read_count: if let LockState::ReadLock = target_state {
1261                                guard_keys.push(*lock);
1262                                1
1263                            } else {
1264                                guard_keys.push(*lock);
1265                                0
1266                            },
1267                            state: target_state,
1268                            head: std::ptr::null(),
1269                            tail: std::ptr::null(),
1270                        });
1271                    }
1272                    Entry::Occupied(mut occupied) => {
1273                        let entry = occupied.get_mut();
1274                        // SAFETY: We've acquired the lock.
1275                        if unsafe { entry.is_allowed(target_state, entry.head.is_null()) } {
1276                            if let LockState::ReadLock = target_state {
1277                                entry.read_count += 1;
1278                                guard_keys.push(*lock);
1279                            } else {
1280                                entry.state = target_state;
1281                                guard_keys.push(*lock);
1282                            }
1283                        } else {
1284                            // Initialise a waker and push it on the tail of the list.
1285                            // SAFETY: `lock_waker` isn't used prior to this point.
1286                            unsafe {
1287                                *lock_waker.as_mut().get_unchecked_mut() = Some(LockWaker {
1288                                    next: UnsafeCell::new(std::ptr::null()),
1289                                    prev: UnsafeCell::new(entry.tail),
1290                                    key: *lock,
1291                                    waker: UnsafeCell::new(WakerState::Pending),
1292                                    target_state: target_state,
1293                                    is_upgrade: false,
1294                                    _pin: PhantomPinned,
1295                                });
1296                            }
1297                            let waker = (*lock_waker).as_ref().unwrap();
1298                            if entry.tail.is_null() {
1299                                entry.head = waker;
1300                            } else {
1301                                // SAFETY: We've acquired the lock.
1302                                unsafe {
1303                                    *(*entry.tail).next.get() = waker;
1304                                }
1305                            }
1306                            entry.tail = waker;
1307                        }
1308                    }
1309                }
1310            }
1311            if let Some(waker) = &*lock_waker {
1312                waker.wait(self).await;
1313                guard_keys.push(*lock);
1314            }
1315        }
1316        guard
1317    }
1318
1319    /// This should be called by the filesystem's drop_transaction implementation.
1320    pub fn drop_transaction(&self, transaction: &mut Transaction<'_>) {
1321        let mut locks = self.locks.lock();
1322        locks.drop_write_locks(std::mem::take(&mut transaction.txn_locks));
1323    }
1324
1325    /// Prepares to commit by waiting for readers to finish.
1326    pub async fn commit_prepare(&self, transaction: &Transaction<'_>) {
1327        self.commit_prepare_keys(&transaction.txn_locks).await;
1328    }
1329
1330    async fn commit_prepare_keys(&self, lock_keys: &LockKeys) {
1331        for lock in lock_keys.iter() {
1332            let lock_waker = None;
1333            pin_mut!(lock_waker);
1334            {
1335                let mut locks = self.locks.lock();
1336                let entry = locks.keys.get_mut(lock).unwrap();
1337                // Callers may invoke `Transaction::commit_prepare` explicitly before committing
1338                // (e.g. to upgrade locks and verify invariants after disk I/O has finished).
1339                // Skipping keys already in `LockState::WriteLock` makes `commit_prepare`
1340                // idempotent when called again during `commit_transaction`.
1341                if entry.state == LockState::WriteLock {
1342                    continue;
1343                }
1344                assert_eq!(entry.state, LockState::Locked);
1345
1346                if entry.read_count == 0 {
1347                    entry.state = LockState::WriteLock;
1348                } else {
1349                    // Initialise a waker and push it on the head of the list.
1350                    // SAFETY: `lock_waker` isn't used prior to this point.
1351                    unsafe {
1352                        *lock_waker.as_mut().get_unchecked_mut() = Some(LockWaker {
1353                            next: UnsafeCell::new(entry.head),
1354                            prev: UnsafeCell::new(std::ptr::null()),
1355                            key: *lock,
1356                            waker: UnsafeCell::new(WakerState::Pending),
1357                            target_state: LockState::WriteLock,
1358                            is_upgrade: true,
1359                            _pin: PhantomPinned,
1360                        });
1361                    }
1362                    let waker = (*lock_waker).as_ref().unwrap();
1363                    if entry.head.is_null() {
1364                        entry.tail = (*lock_waker).as_ref().unwrap();
1365                    } else {
1366                        // SAFETY: We've acquired the lock.
1367                        unsafe {
1368                            *(*entry.head).prev.get() = waker;
1369                        }
1370                    }
1371                    entry.head = waker;
1372                }
1373            }
1374
1375            if let Some(waker) = &*lock_waker {
1376                waker.wait(self).await;
1377            }
1378        }
1379    }
1380
1381    /// Acquires a read lock for the given keys.  Read locks are only blocked whilst a transaction
1382    /// is being committed for the same locks.  They are only necessary where consistency is
1383    /// required between different mutations within a transaction.  For example, a write might
1384    /// change the size and extents for an object, in which case a read lock is required so that
1385    /// observed size and extents are seen together or not at all.
1386    pub async fn read_lock<'a>(&'a self, lock_keys: LockKeys) -> ReadGuard<'a> {
1387        debug_assert_not_too_long!(self.lock(lock_keys, LockState::ReadLock)).left().unwrap()
1388    }
1389
1390    /// Acquires a write lock for the given keys.  Write locks provide exclusive access to the
1391    /// requested lock keys.
1392    pub async fn write_lock<'a>(&'a self, lock_keys: LockKeys) -> WriteGuard<'a> {
1393        debug_assert_not_too_long!(self.lock(lock_keys, LockState::WriteLock)).right().unwrap()
1394    }
1395
1396    /// Downgrades locks from the WriteLock state to Locked state.  This will panic if the locks are
1397    /// not in the WriteLock state.
1398    pub fn downgrade_locks(&self, lock_keys: &LockKeys) {
1399        self.locks.lock().downgrade_locks(lock_keys);
1400    }
1401}
1402
1403// These unsafe functions require that `locks` in LockManager is locked.
1404impl LockEntry {
1405    unsafe fn wake(&mut self) {
1406        // If the lock's state is WriteLock, or there's nothing waiting, return early.
1407        if self.head.is_null() || self.state == LockState::WriteLock {
1408            return;
1409        }
1410
1411        let waker = unsafe { &*self.head };
1412
1413        if waker.is_upgrade {
1414            if self.read_count > 0 {
1415                return;
1416            }
1417        } else if !unsafe { self.is_allowed(waker.target_state, true) } {
1418            return;
1419        }
1420
1421        unsafe { self.pop_and_wake() };
1422
1423        // If the waker was a write lock, we can't wake any more up, but otherwise, we can keep
1424        // waking up readers.
1425        if waker.target_state == LockState::WriteLock {
1426            return;
1427        }
1428
1429        while !self.head.is_null() && unsafe { (*self.head).target_state } == LockState::ReadLock {
1430            unsafe { self.pop_and_wake() };
1431        }
1432    }
1433
1434    unsafe fn pop_and_wake(&mut self) {
1435        let waker = unsafe { &*self.head };
1436
1437        // Pop the waker.
1438        self.head = unsafe { *waker.next.get() };
1439        if self.head.is_null() {
1440            self.tail = std::ptr::null()
1441        } else {
1442            unsafe { *(*self.head).prev.get() = std::ptr::null() };
1443        }
1444
1445        // Adjust our state accordingly.
1446        if waker.target_state == LockState::ReadLock {
1447            self.read_count += 1;
1448        } else {
1449            self.state = waker.target_state;
1450        }
1451
1452        // Now wake the task.
1453        if let WakerState::Registered(waker) =
1454            std::mem::replace(unsafe { &mut *waker.waker.get() }, WakerState::Woken)
1455        {
1456            waker.wake();
1457        }
1458    }
1459
1460    fn can_remove(&self) -> bool {
1461        self.state == LockState::ReadLock && self.read_count == 0
1462    }
1463
1464    unsafe fn remove_waker(&mut self, waker: &LockWaker) {
1465        unsafe {
1466            let is_first = (*waker.prev.get()).is_null();
1467            if is_first {
1468                self.head = *waker.next.get();
1469            } else {
1470                *(**waker.prev.get()).next.get() = *waker.next.get();
1471            }
1472            if (*waker.next.get()).is_null() {
1473                self.tail = *waker.prev.get();
1474            } else {
1475                *(**waker.next.get()).prev.get() = *waker.prev.get();
1476            }
1477            if is_first {
1478                // We must call wake in case we erased a pending write lock and readers can now
1479                // proceed.
1480                self.wake();
1481            }
1482        }
1483    }
1484
1485    // Returns whether or not a lock with given `target_state` can proceed.  `is_head` should be
1486    // true if this is something at the head of the waker list (or the waker list is empty) and
1487    // false if there are other items on the waker list that are prior.
1488    unsafe fn is_allowed(&self, target_state: LockState, is_head: bool) -> bool {
1489        match self.state {
1490            LockState::ReadLock => {
1491                // Allow ReadLock and Locked so long as nothing else is waiting.
1492                (self.read_count == 0
1493                    || target_state == LockState::Locked
1494                    || target_state == LockState::ReadLock)
1495                    && is_head
1496            }
1497            LockState::Locked => {
1498                // Always allow reads unless there's an upgrade waiting.  We have to
1499                // always allow reads in this state because tasks that have locks in
1500                // the Locked state can later try and acquire ReadLock.
1501                target_state == LockState::ReadLock
1502                    && (is_head || unsafe { !(*self.head).is_upgrade })
1503            }
1504            LockState::WriteLock => false,
1505        }
1506    }
1507
1508    unsafe fn downgrade_lock(&mut self) {
1509        assert_eq!(std::mem::replace(&mut self.state, LockState::Locked), LockState::WriteLock);
1510        unsafe { self.wake() };
1511    }
1512}
1513
1514#[must_use]
1515pub struct ReadGuard<'a> {
1516    manager: LockManagerRef<'a>,
1517    lock_keys: LockKeys,
1518}
1519
1520impl ReadGuard<'_> {
1521    pub fn fs(&self) -> Option<&Arc<FxFilesystem>> {
1522        if let LockManagerRef::Owned(fs) = &self.manager { Some(fs) } else { None }
1523    }
1524
1525    pub fn into_owned(mut self, fs: Arc<FxFilesystem>) -> ReadGuard<'static> {
1526        ReadGuard {
1527            manager: LockManagerRef::Owned(fs),
1528            lock_keys: std::mem::replace(&mut self.lock_keys, LockKeys::None),
1529        }
1530    }
1531}
1532
1533impl Drop for ReadGuard<'_> {
1534    fn drop(&mut self) {
1535        let mut locks = self.manager.locks.lock();
1536        locks.drop_read_locks(std::mem::take(&mut self.lock_keys));
1537    }
1538}
1539
1540impl fmt::Debug for ReadGuard<'_> {
1541    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1542        f.debug_struct("ReadGuard")
1543            .field("manager", &(&self.manager as *const _))
1544            .field("lock_keys", &self.lock_keys)
1545            .finish()
1546    }
1547}
1548
1549#[must_use]
1550pub struct WriteGuard<'a> {
1551    manager: LockManagerRef<'a>,
1552    lock_keys: LockKeys,
1553}
1554
1555impl WriteGuard<'_> {
1556    pub fn into_owned(mut self, fs: Arc<FxFilesystem>) -> WriteGuard<'static> {
1557        WriteGuard {
1558            manager: LockManagerRef::Owned(fs),
1559            lock_keys: std::mem::replace(&mut self.lock_keys, LockKeys::None),
1560        }
1561    }
1562}
1563
1564impl Drop for WriteGuard<'_> {
1565    fn drop(&mut self) {
1566        let mut locks = self.manager.locks.lock();
1567        locks.drop_write_locks(std::mem::take(&mut self.lock_keys));
1568    }
1569}
1570
1571impl fmt::Debug for WriteGuard<'_> {
1572    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1573        f.debug_struct("WriteGuard")
1574            .field("manager", &(&self.manager as *const _))
1575            .field("lock_keys", &self.lock_keys)
1576            .finish()
1577    }
1578}
1579
1580enum LockManagerRef<'a> {
1581    Borrowed(&'a LockManager),
1582    Owned(Arc<FxFilesystem>),
1583}
1584
1585impl Deref for LockManagerRef<'_> {
1586    type Target = LockManager;
1587
1588    fn deref(&self) -> &Self::Target {
1589        match self {
1590            LockManagerRef::Borrowed(m) => m,
1591            LockManagerRef::Owned(f) => f.lock_manager(),
1592        }
1593    }
1594}
1595
1596impl<'a> From<&'a LockManager> for LockManagerRef<'a> {
1597    fn from(value: &'a LockManager) -> Self {
1598        LockManagerRef::Borrowed(value)
1599    }
1600}
1601
1602#[cfg(test)]
1603mod tests {
1604    use super::{
1605        AssocObj, AttributeId, LockKey, LockKeys, LockManager, LockState, Mutation,
1606        ObjectMutationIterator, Options, TxnMutation,
1607    };
1608    use crate::filesystem::FxFilesystem;
1609    use fuchsia_async as fasync;
1610    use fuchsia_sync::Mutex;
1611    use futures::channel::oneshot::channel;
1612    use futures::future::FutureExt;
1613    use futures::stream::FuturesUnordered;
1614    use futures::{StreamExt, join, pin_mut};
1615    use std::collections::BTreeSet;
1616    use std::task::Poll;
1617    use std::time::Duration;
1618    use storage_device::DeviceHolder;
1619    use storage_device::fake_device::FakeDevice;
1620
1621    #[fuchsia::test]
1622    async fn test_simple() {
1623        let device = DeviceHolder::new(FakeDevice::new(4096, 1024));
1624        let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1625        let mut t = fs
1626            .root_store()
1627            .new_transaction(lock_keys![], Options::default())
1628            .await
1629            .expect("new_transaction failed");
1630        t.add(1, Mutation::BeginFlush);
1631        assert!(!t.is_empty());
1632    }
1633
1634    #[fuchsia::test]
1635    async fn test_locks() {
1636        let device = DeviceHolder::new(FakeDevice::new(4096, 1024));
1637        let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1638        let (send1, recv1) = channel();
1639        let (send2, recv2) = channel();
1640        let (send3, recv3) = channel();
1641        let done = Mutex::new(false);
1642        let mut futures = FuturesUnordered::new();
1643        futures.push(
1644            async {
1645                let _t = fs
1646                    .root_store()
1647                    .new_transaction(
1648                        lock_keys![LockKey::object_attribute(1, 2, AttributeId::TEST_ID)],
1649                        Options::default(),
1650                    )
1651                    .await
1652                    .expect("new_transaction failed");
1653                send1.send(()).unwrap(); // Tell the next future to continue.
1654                send3.send(()).unwrap(); // Tell the last future to continue.
1655                recv2.await.unwrap();
1656                // This is a halting problem so all we can do is sleep.
1657                fasync::Timer::new(Duration::from_millis(100)).await;
1658                assert!(!*done.lock());
1659            }
1660            .boxed(),
1661        );
1662        futures.push(
1663            async {
1664                recv1.await.unwrap();
1665                // This should not block since it is a different key.
1666                let _t = fs
1667                    .root_store()
1668                    .new_transaction(
1669                        lock_keys![LockKey::object_attribute(2, 2, AttributeId::TEST_ID)],
1670                        Options::default(),
1671                    )
1672                    .await
1673                    .expect("new_transaction failed");
1674                // Tell the first future to continue.
1675                send2.send(()).unwrap();
1676            }
1677            .boxed(),
1678        );
1679        futures.push(
1680            async {
1681                // This should block until the first future has completed.
1682                recv3.await.unwrap();
1683                let _t = fs
1684                    .root_store()
1685                    .new_transaction(
1686                        lock_keys![LockKey::object_attribute(1, 2, AttributeId::TEST_ID)],
1687                        Options::default(),
1688                    )
1689                    .await;
1690                *done.lock() = true;
1691            }
1692            .boxed(),
1693        );
1694        while let Some(()) = futures.next().await {}
1695    }
1696
1697    #[fuchsia::test]
1698    async fn test_read_lock_after_write_lock() {
1699        let device = DeviceHolder::new(FakeDevice::new(4096, 1024));
1700        let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1701        let (send1, recv1) = channel();
1702        let (send2, recv2) = channel();
1703        let done = Mutex::new(false);
1704        join!(
1705            async {
1706                let t = fs
1707                    .root_store()
1708                    .new_transaction(
1709                        lock_keys![LockKey::object_attribute(1, 2, AttributeId::TEST_ID)],
1710                        Options::default(),
1711                    )
1712                    .await
1713                    .expect("new_transaction failed");
1714                send1.send(()).unwrap(); // Tell the next future to continue.
1715                recv2.await.unwrap();
1716                t.commit().await.expect("commit failed");
1717                *done.lock() = true;
1718            },
1719            async {
1720                recv1.await.unwrap();
1721                // Reads should not be blocked until the transaction is committed.
1722                let _guard = fs
1723                    .lock_manager()
1724                    .read_lock(lock_keys![LockKey::object_attribute(1, 2, AttributeId::TEST_ID)])
1725                    .await;
1726                // Tell the first future to continue.
1727                send2.send(()).unwrap();
1728                // It shouldn't proceed until we release our read lock, but it's a halting
1729                // problem, so sleep.
1730                fasync::Timer::new(Duration::from_millis(100)).await;
1731                assert!(!*done.lock());
1732            },
1733        );
1734    }
1735
1736    #[fuchsia::test]
1737    async fn test_write_lock_after_read_lock() {
1738        let device = DeviceHolder::new(FakeDevice::new(4096, 1024));
1739        let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1740        let (send1, recv1) = channel();
1741        let (send2, recv2) = channel();
1742        let done = Mutex::new(false);
1743        join!(
1744            async {
1745                // Reads should not be blocked until the transaction is committed.
1746                let _guard = fs
1747                    .lock_manager()
1748                    .read_lock(lock_keys![LockKey::object_attribute(1, 2, AttributeId::TEST_ID)])
1749                    .await;
1750                // Tell the next future to continue and then wait.
1751                send1.send(()).unwrap();
1752                recv2.await.unwrap();
1753                // It shouldn't proceed until we release our read lock, but it's a halting
1754                // problem, so sleep.
1755                fasync::Timer::new(Duration::from_millis(100)).await;
1756                assert!(!*done.lock());
1757            },
1758            async {
1759                recv1.await.unwrap();
1760                let t = fs
1761                    .root_store()
1762                    .new_transaction(
1763                        lock_keys![LockKey::object_attribute(1, 2, AttributeId::TEST_ID)],
1764                        Options::default(),
1765                    )
1766                    .await
1767                    .expect("new_transaction failed");
1768                send2.send(()).unwrap(); // Tell the first future to continue;
1769                t.commit().await.expect("commit failed");
1770                *done.lock() = true;
1771            },
1772        );
1773    }
1774
1775    #[fuchsia::test]
1776    async fn test_drop_uncommitted_transaction() {
1777        let device = DeviceHolder::new(FakeDevice::new(4096, 1024));
1778        let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1779        let key = lock_keys![LockKey::object(1, 1)];
1780
1781        // Dropping while there's a reader.
1782        {
1783            let _write_lock = fs
1784                .root_store()
1785                .new_transaction(key.clone(), Options::default())
1786                .await
1787                .expect("new_transaction failed");
1788            let _read_lock = fs.lock_manager().read_lock(key.clone()).await;
1789        }
1790        // Dropping while there's no reader.
1791        {
1792            let _write_lock = fs
1793                .root_store()
1794                .new_transaction(key.clone(), Options::default())
1795                .await
1796                .expect("new_transaction failed");
1797        }
1798        // Make sure we can take the lock again (i.e. it was actually released).
1799        fs.root_store()
1800            .new_transaction(key.clone(), Options::default())
1801            .await
1802            .expect("new_transaction failed");
1803    }
1804
1805    #[fuchsia::test]
1806    async fn test_drop_waiting_write_lock() {
1807        let manager = LockManager::new();
1808        let keys = lock_keys![LockKey::object(1, 1)];
1809        {
1810            let _guard = manager.lock(keys.clone(), LockState::ReadLock).await;
1811            if let Poll::Ready(_) =
1812                futures::poll!(manager.lock(keys.clone(), LockState::WriteLock).boxed())
1813            {
1814                assert!(false);
1815            }
1816        }
1817        let _ = manager.lock(keys, LockState::WriteLock).await;
1818    }
1819
1820    #[fuchsia::test]
1821    async fn test_write_lock_blocks_everything() {
1822        let manager = LockManager::new();
1823        let keys = lock_keys![LockKey::object(1, 1)];
1824        {
1825            let _guard = manager.lock(keys.clone(), LockState::WriteLock).await;
1826            if let Poll::Ready(_) =
1827                futures::poll!(manager.lock(keys.clone(), LockState::WriteLock).boxed())
1828            {
1829                assert!(false);
1830            }
1831            if let Poll::Ready(_) =
1832                futures::poll!(manager.lock(keys.clone(), LockState::ReadLock).boxed())
1833            {
1834                assert!(false);
1835            }
1836        }
1837        {
1838            let _guard = manager.lock(keys.clone(), LockState::WriteLock).await;
1839        }
1840        {
1841            let _guard = manager.lock(keys, LockState::ReadLock).await;
1842        }
1843    }
1844
1845    #[fuchsia::test]
1846    async fn test_downgrade_locks() {
1847        let manager = LockManager::new();
1848        let keys = lock_keys![LockKey::object(1, 1)];
1849        let _guard = manager.txn_lock(keys.clone()).await;
1850        manager.commit_prepare_keys(&keys).await;
1851
1852        // Use FuturesUnordered so that we can check that the waker is woken.
1853        let mut read_lock: FuturesUnordered<_> =
1854            std::iter::once(manager.read_lock(keys.clone())).collect();
1855
1856        // Trying to acquire a read lock now should be blocked.
1857        assert!(futures::poll!(read_lock.next()).is_pending());
1858
1859        manager.downgrade_locks(&keys);
1860
1861        // After downgrading, it should be possible to take a read lock.
1862        assert!(futures::poll!(read_lock.next()).is_ready());
1863    }
1864
1865    #[fuchsia::test]
1866    async fn test_dropped_write_lock_wakes() {
1867        let manager = LockManager::new();
1868        let keys = lock_keys![LockKey::object(1, 1)];
1869        let _guard = manager.lock(keys.clone(), LockState::ReadLock).await;
1870        let mut read_lock = FuturesUnordered::new();
1871        read_lock.push(manager.lock(keys.clone(), LockState::ReadLock));
1872
1873        {
1874            let write_lock = manager.lock(keys, LockState::WriteLock);
1875            pin_mut!(write_lock);
1876
1877            // The write lock should be blocked because of the read lock.
1878            assert!(futures::poll!(write_lock).is_pending());
1879
1880            // Another read lock should be blocked because of the write lock.
1881            assert!(futures::poll!(read_lock.next()).is_pending());
1882        }
1883
1884        // Dropping the write lock should allow the read lock to proceed.
1885        assert!(futures::poll!(read_lock.next()).is_ready());
1886    }
1887
1888    #[fuchsia::test]
1889    async fn test_drop_upgrade() {
1890        let manager = LockManager::new();
1891        let keys = lock_keys![LockKey::object(1, 1)];
1892        let _guard = manager.lock(keys.clone(), LockState::Locked).await;
1893
1894        {
1895            let commit_prepare = manager.commit_prepare_keys(&keys);
1896            pin_mut!(commit_prepare);
1897            let _read_guard = manager.lock(keys.clone(), LockState::ReadLock).await;
1898            assert!(futures::poll!(commit_prepare).is_pending());
1899
1900            // Now we test dropping read_guard which should wake commit_prepare and
1901            // then dropping commit_prepare.
1902        }
1903
1904        // We should be able to still commit_prepare.
1905        manager.commit_prepare_keys(&keys).await;
1906    }
1907
1908    #[fuchsia::test]
1909    async fn test_woken_upgrade_blocks_reads() {
1910        let manager = LockManager::new();
1911        let keys = lock_keys![LockKey::object(1, 1)];
1912        // Start with a transaction lock.
1913        let guard = manager.lock(keys.clone(), LockState::Locked).await;
1914
1915        // Take a read lock.
1916        let read1 = manager.lock(keys.clone(), LockState::ReadLock).await;
1917
1918        // Try and upgrade the transaction lock, which should not be possible because of the read.
1919        let commit_prepare = manager.commit_prepare_keys(&keys);
1920        pin_mut!(commit_prepare);
1921        assert!(futures::poll!(commit_prepare.as_mut()).is_pending());
1922
1923        // Taking another read should also be blocked.
1924        let read2 = manager.lock(keys.clone(), LockState::ReadLock);
1925        pin_mut!(read2);
1926        assert!(futures::poll!(read2.as_mut()).is_pending());
1927
1928        // Drop the first read and the upgrade should complete.
1929        std::mem::drop(read1);
1930        assert!(futures::poll!(commit_prepare).is_ready());
1931
1932        // But the second read should still be blocked.
1933        assert!(futures::poll!(read2.as_mut()).is_pending());
1934
1935        // If we drop the write lock now, the read should be unblocked.
1936        std::mem::drop(guard);
1937        assert!(futures::poll!(read2).is_ready());
1938    }
1939
1940    static LOCK_KEY_1: LockKey = LockKey::flush(1);
1941    static LOCK_KEY_2: LockKey = LockKey::flush(2);
1942    static LOCK_KEY_3: LockKey = LockKey::flush(3);
1943
1944    // The keys, storage method, and capacity must all match.
1945    fn assert_lock_keys_equal(value: &LockKeys, expected: &LockKeys) {
1946        match (value, expected) {
1947            (LockKeys::None, LockKeys::None) => {}
1948            (LockKeys::Inline(key1), LockKeys::Inline(key2)) => {
1949                if key1 != key2 {
1950                    panic!("{key1:?} != {key2:?}");
1951                }
1952            }
1953            (LockKeys::Vec(vec1), LockKeys::Vec(vec2)) => {
1954                if vec1 != vec2 {
1955                    panic!("{vec1:?} != {vec2:?}");
1956                }
1957                if vec1.capacity() != vec2.capacity() {
1958                    panic!(
1959                        "LockKeys have different capacity: {} != {}",
1960                        vec1.capacity(),
1961                        vec2.capacity()
1962                    );
1963                }
1964            }
1965            (_, _) => panic!("{value:?} != {expected:?}"),
1966        }
1967    }
1968
1969    // Only the keys must match. Storage method and capacity don't matter.
1970    fn assert_lock_keys_equivalent(value: &LockKeys, expected: &LockKeys) {
1971        let value: Vec<_> = value.iter().collect();
1972        let expected: Vec<_> = expected.iter().collect();
1973        assert_eq!(value, expected);
1974    }
1975
1976    #[test]
1977    fn test_lock_keys_macro() {
1978        assert_lock_keys_equal(&lock_keys![], &LockKeys::None);
1979        assert_lock_keys_equal(&lock_keys![LOCK_KEY_1], &LockKeys::Inline(LOCK_KEY_1));
1980        assert_lock_keys_equal(
1981            &lock_keys![LOCK_KEY_1, LOCK_KEY_2],
1982            &LockKeys::Vec(vec![LOCK_KEY_1, LOCK_KEY_2]),
1983        );
1984    }
1985
1986    #[test]
1987    fn test_lock_keys_with_capacity() {
1988        assert_lock_keys_equal(&LockKeys::with_capacity(0), &LockKeys::None);
1989        assert_lock_keys_equal(&LockKeys::with_capacity(1), &LockKeys::None);
1990        assert_lock_keys_equal(&LockKeys::with_capacity(2), &LockKeys::Vec(Vec::with_capacity(2)));
1991    }
1992
1993    #[test]
1994    fn test_lock_keys_len() {
1995        assert_eq!(lock_keys![].len(), 0);
1996        assert_eq!(lock_keys![LOCK_KEY_1].len(), 1);
1997        assert_eq!(lock_keys![LOCK_KEY_1, LOCK_KEY_2].len(), 2);
1998    }
1999
2000    #[test]
2001    fn test_lock_keys_contains() {
2002        assert_eq!(lock_keys![].contains(&LOCK_KEY_1), false);
2003        assert_eq!(lock_keys![LOCK_KEY_1].contains(&LOCK_KEY_1), true);
2004        assert_eq!(lock_keys![LOCK_KEY_1].contains(&LOCK_KEY_2), false);
2005        assert_eq!(lock_keys![LOCK_KEY_1, LOCK_KEY_2].contains(&LOCK_KEY_1), true);
2006        assert_eq!(lock_keys![LOCK_KEY_1, LOCK_KEY_2].contains(&LOCK_KEY_2), true);
2007        assert_eq!(lock_keys![LOCK_KEY_1, LOCK_KEY_2].contains(&LOCK_KEY_3), false);
2008    }
2009
2010    #[test]
2011    fn test_lock_keys_push() {
2012        let mut keys = lock_keys![];
2013        keys.push(LOCK_KEY_1);
2014        assert_lock_keys_equal(&keys, &LockKeys::Inline(LOCK_KEY_1));
2015        keys.push(LOCK_KEY_2);
2016        assert_lock_keys_equal(&keys, &LockKeys::Vec(vec![LOCK_KEY_1, LOCK_KEY_2]));
2017        keys.push(LOCK_KEY_3);
2018        assert_lock_keys_equivalent(
2019            &keys,
2020            &LockKeys::Vec(vec![LOCK_KEY_1, LOCK_KEY_2, LOCK_KEY_3]),
2021        );
2022    }
2023
2024    #[test]
2025    fn test_lock_keys_sort_unstable() {
2026        let mut keys = lock_keys![];
2027        keys.sort_unstable();
2028        assert_lock_keys_equal(&keys, &lock_keys![]);
2029
2030        let mut keys = lock_keys![LOCK_KEY_1];
2031        keys.sort_unstable();
2032        assert_lock_keys_equal(&keys, &lock_keys![LOCK_KEY_1]);
2033
2034        let mut keys = lock_keys![LOCK_KEY_2, LOCK_KEY_1];
2035        keys.sort_unstable();
2036        assert_lock_keys_equal(&keys, &lock_keys![LOCK_KEY_1, LOCK_KEY_2]);
2037    }
2038
2039    #[test]
2040    fn test_lock_keys_dedup() {
2041        let mut keys = lock_keys![];
2042        keys.dedup();
2043        assert_lock_keys_equal(&keys, &lock_keys![]);
2044
2045        let mut keys = lock_keys![LOCK_KEY_1];
2046        keys.dedup();
2047        assert_lock_keys_equal(&keys, &lock_keys![LOCK_KEY_1]);
2048
2049        let mut keys = lock_keys![LOCK_KEY_1, LOCK_KEY_1];
2050        keys.dedup();
2051        assert_lock_keys_equivalent(&keys, &lock_keys![LOCK_KEY_1]);
2052    }
2053
2054    #[test]
2055    fn test_lock_keys_truncate() {
2056        let mut keys = lock_keys![];
2057        keys.truncate(5);
2058        assert_lock_keys_equal(&keys, &lock_keys![]);
2059        keys.truncate(0);
2060        assert_lock_keys_equal(&keys, &lock_keys![]);
2061
2062        let mut keys = lock_keys![LOCK_KEY_1];
2063        keys.truncate(5);
2064        assert_lock_keys_equal(&keys, &lock_keys![LOCK_KEY_1]);
2065        keys.truncate(0);
2066        assert_lock_keys_equal(&keys, &lock_keys![]);
2067
2068        let mut keys = lock_keys![LOCK_KEY_1, LOCK_KEY_2];
2069        keys.truncate(5);
2070        assert_lock_keys_equal(&keys, &lock_keys![LOCK_KEY_1, LOCK_KEY_2]);
2071        keys.truncate(1);
2072        // Although there's only 1 key after truncate the key is not stored inline.
2073        assert_lock_keys_equivalent(&keys, &lock_keys![LOCK_KEY_1]);
2074    }
2075
2076    #[test]
2077    fn test_lock_keys_iter() {
2078        assert_eq!(lock_keys![].iter().collect::<Vec<_>>(), Vec::<&LockKey>::new());
2079
2080        assert_eq!(lock_keys![LOCK_KEY_1].iter().collect::<Vec<_>>(), vec![&LOCK_KEY_1]);
2081
2082        assert_eq!(
2083            lock_keys![LOCK_KEY_1, LOCK_KEY_2].iter().collect::<Vec<_>>(),
2084            vec![&LOCK_KEY_1, &LOCK_KEY_2]
2085        );
2086    }
2087
2088    #[test]
2089    fn test_object_mutation_iterator() {
2090        let mut mutations = BTreeSet::new();
2091        mutations.insert(TxnMutation {
2092            object_id: 1,
2093            mutation: Mutation::BeginFlush,
2094            associated_object: AssocObj::None,
2095        });
2096        mutations.insert(TxnMutation {
2097            object_id: 1,
2098            mutation: Mutation::EndFlush,
2099            associated_object: AssocObj::None,
2100        });
2101        mutations.insert(TxnMutation {
2102            object_id: 2,
2103            mutation: Mutation::DeleteVolume,
2104            associated_object: AssocObj::None,
2105        });
2106
2107        let mut iter = mutations.iter().peekable();
2108
2109        {
2110            let mut obj_iter = ObjectMutationIterator::new(&mut iter).expect("expected object 1");
2111            assert_eq!(obj_iter.object_id(), 1);
2112            assert_eq!(obj_iter.next(), Some(&Mutation::BeginFlush));
2113            assert_eq!(obj_iter.next(), Some(&Mutation::EndFlush));
2114            assert_eq!(obj_iter.next(), None);
2115        }
2116
2117        {
2118            let mut obj_iter = ObjectMutationIterator::new(&mut iter).expect("expected object 2");
2119            assert_eq!(obj_iter.object_id(), 2);
2120            assert_eq!(obj_iter.next(), Some(&Mutation::DeleteVolume));
2121            assert_eq!(obj_iter.next(), None);
2122        }
2123
2124        // No more objects
2125        assert!(ObjectMutationIterator::new(&mut iter).is_none());
2126    }
2127
2128    #[test]
2129    fn test_object_mutation_iterator_drop_drains_remaining() {
2130        let mut mutations = BTreeSet::new();
2131        // Object 1 with 3 mutations
2132        mutations.insert(TxnMutation {
2133            object_id: 1,
2134            mutation: Mutation::BeginFlush,
2135            associated_object: AssocObj::None,
2136        });
2137        mutations.insert(TxnMutation {
2138            object_id: 1,
2139            mutation: Mutation::EndFlush,
2140            associated_object: AssocObj::None,
2141        });
2142        mutations.insert(TxnMutation {
2143            object_id: 1,
2144            mutation: Mutation::DeleteVolume,
2145            associated_object: AssocObj::None,
2146        });
2147        // Object 2 with 2 mutations
2148        mutations.insert(TxnMutation {
2149            object_id: 2,
2150            mutation: Mutation::BeginFlush,
2151            associated_object: AssocObj::None,
2152        });
2153        mutations.insert(TxnMutation {
2154            object_id: 2,
2155            mutation: Mutation::EndFlush,
2156            associated_object: AssocObj::None,
2157        });
2158
2159        let mut iter = mutations.iter().peekable();
2160
2161        {
2162            let mut obj_iter = ObjectMutationIterator::new(&mut iter).expect("expected object 1");
2163            assert_eq!(obj_iter.object_id(), 1);
2164            assert_eq!(obj_iter.next(), Some(&Mutation::BeginFlush));
2165            // Drop without reading EndFlush or DeleteVolume
2166        }
2167
2168        {
2169            let obj_iter = ObjectMutationIterator::new(&mut iter).expect("expected object 2");
2170            assert_eq!(obj_iter.object_id(), 2);
2171            // Drop immediately without reading any mutations for object 2
2172        }
2173
2174        // Dropping obj_iter for object 2 should have drained all object 2 mutations as well.
2175        assert!(ObjectMutationIterator::new(&mut iter).is_none());
2176    }
2177}