1pub 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
138pub trait ReservationOwner: Send + Sync {
140 fn release_reservation(&self, owner_object_id: Option<u64>, amount: u64);
144}
145
146pub 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: u64,
164
165 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 pub fn amount(&self) -> u64 {
195 self.inner.lock().amount
196 }
197
198 pub fn add(&self, amount: u64) {
200 self.inner.lock().amount += amount;
201 }
202
203 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 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 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 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 pub fn commit(&self, amount: u64) {
244 let mut inner = self.inner.lock();
245 inner.reserved -= amount;
246 inner.amount -= amount;
247 }
248
249 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 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 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
304pub 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 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 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 self.device_range.cmp(&other.device_range)
439 }
440}
441
442pub 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 None,
454 Abs { count: u64, owner_object_id: u64 },
458}
459
460pub type AllocatorItem = Item<AllocatorKey, AllocatorValue>;
461
462pub type AllocatorInfo = AllocatorInfoV32;
464
465#[derive(Debug, Default, Clone, Deserialize, Serialize, TypeFingerprint, Versioned)]
466pub struct AllocatorInfoV32 {
467 pub layers: Vec<u64>,
469 pub allocated_bytes: BTreeMap<u64, u64>,
471 pub marked_for_deletion: HashSet<u64>,
474 pub limit_bytes: BTreeMap<u64, u64>,
477}
478
479const MAX_ALLOCATOR_INFO_SERIALIZED_SIZE: usize = 131_072;
480
481pub fn max_extent_size_for_block_size(block_size: BlockSize) -> u64 {
483 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 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#[derive(Debug, Default, PartialEq)]
519struct ByteTracking {
520 allocated_bytes: Saturating<u64>,
527
528 uncommitted_allocated_bytes: u64,
531
532 reserved_bytes: u64,
534
535 committed_deallocated_bytes: u64,
539}
540
541impl ByteTracking {
542 fn used_bytes(&self) -> Saturating<u64> {
545 self.allocated_bytes + Saturating(self.uncommitted_allocated_bytes + self.reserved_bytes)
546 }
547
548 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 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 log_file_offset: u64,
569 range: Range<u64>,
571 owner_object_id: u64,
573}
574
575struct Inner {
576 info: AllocatorInfo,
577
578 opened: bool,
581
582 dropped_temporary_allocations: Vec<Range<u64>>,
610
611 owner_bytes: BTreeMap<u64, ByteTracking>,
614
615 unattributed_reserved_bytes: u64,
618
619 committed_deallocated: VecDeque<CommittedDeallocation>,
621
622 trim_reserved_bytes: u64,
625
626 trim_listener: Option<EventListener>,
630
631 strategy: strategy::BestFit,
633
634 allocation_size_histogram: [u64; 64],
636 rebuild_strategy_trigger_histogram: [u64; 64],
638
639 marked_for_deletion: HashSet<u64>,
643
644 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 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 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 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 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
753pub struct TrimmableExtents<'a> {
756 allocator: &'a Allocator,
757 extents: Vec<Range<u64>>,
758 _drop_event: DropEvent,
762}
763
764impl<'a> TrimmableExtents<'a> {
765 pub fn extents(&self) -> &Vec<Range<u64>> {
766 &self.extents
767 }
768
769 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 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 pub fn enable_allocations(&self) {
842 self.allocations_allowed.store(true, Ordering::SeqCst);
843 }
844
845 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 pub fn allocation_size_histogram(&self) -> [u64; 64] {
872 self.inner.lock().allocation_size_histogram
873 }
874
875 pub async fn create(&self, transaction: &mut Transaction<'_>) -> Result<(), Error> {
877 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 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 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 {
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 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 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 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 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 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 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 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 pub fn parent_objects(&self) -> Vec<u64> {
1144 self.inner.lock().info.layers.clone()
1147 }
1148
1149 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 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 pub fn owner_bytes_debug(&self) -> String {
1165 format!("{:?}", self.inner.lock().owner_bytes)
1166 }
1167
1168 fn needs_sync(&self) -> bool {
1169 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 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 let mut inner = self.inner.lock();
1189 inner.remove_reservation(old_owner_object_id, amount);
1190 inner.add_reservation(None, amount);
1191 }
1192
1193 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 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 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 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 assert_eq!(inner.uncommitted_allocated_bytes(), 0);
1306 assert_eq!(inner.reserved_bytes(), 0);
1307 }
1308}
1309
1310#[fxfs_trace::trace]
1311impl Allocator {
1312 pub fn object_id(&self) -> u64 {
1314 self.object_id
1315 }
1316
1317 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 #[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 let reservation = if let Some(reservation) =
1371 transaction.allocator_reservation(owner_object_id)
1372 {
1373 match reservation.owner_object_id {
1374 None => assert!(self.is_system_store(owner_object_id)),
1376 Some(res_owner_object_id) => assert_eq!(owner_object_id, res_owner_object_id),
1378 };
1379 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 let device_used = inner.used_bytes();
1394 let owner_bytes_left = inner.owner_id_bytes_left(owner_object_id);
1395 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 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 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)] let _guard = 'sync: loop {
1462 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 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 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 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 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 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 |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 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 #[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 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 pub fn set_bytes_limit(
1663 &self,
1664 transaction: &mut Transaction<'_>,
1665 owner_object_id: u64,
1666 bytes: u64,
1667 ) -> Result<(), Error> {
1668 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 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 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 #[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 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 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 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 pub fn mark_for_deletion(&self, transaction: &mut Transaction<'_>, owner_object_id: u64) {
1757 transaction.add(
1760 self.object_id(),
1761 Mutation::Allocator(AllocatorMutation::MarkForDeletion(owner_object_id)),
1762 );
1763 }
1764
1765 pub fn did_flush_device(&self, flush_log_offset: u64) {
1768 #[allow(clippy::never_loop)] 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 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 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 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 assert!(inner.volumes_deleted_pending_sync.contains(&owner_object_id));
1805 }
1806 }
1807 }
1808 }
1809
1810 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 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 pub fn get_allocated_bytes(&self) -> u64 {
1861 self.inner.lock().allocated_bytes().0
1862 }
1863
1864 pub fn get_disk_bytes(&self) -> u64 {
1866 self.device_size
1867 }
1868
1869 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 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 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 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 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 self.inner.lock().info.limit_bytes.insert(owner_object_id, bytes);
2000 }
2001 Mutation::BeginFlush => {
2002 self.tree.seal();
2003 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
2049pub 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 ensure!(
2090 left.key.device_range.end <= right.key.device_range.start,
2091 FxfsError::Inconsistent
2092 );
2093 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 transaction.add(self.allocator.object_id(), Mutation::BeginFlush);
2152 let info = transaction
2153 .commit_with_callback(|_| {
2154 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 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 for object_id in &info.layers {
2220 root_store.add_to_graveyard(&mut transaction, *object_id);
2221 }
2222
2223 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 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 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 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 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 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 let options = bincode::DefaultOptions::new().allow_trailing_bytes();
2364 let expected_bytes = options.serialize(&range).unwrap();
2365
2366 let mut key_bytes = Vec::new();
2368 key.serialize_into(&mut key_bytes).unwrap();
2369
2370 assert_eq!(key_bytes, expected_bytes);
2372
2373 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 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 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 let expected = vec![
2560 0..4096, 4096..139264, 139264..204800, 204800..335872, 335872..401408, 524288..528384, ];
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 allocator
2673 .allocate(&mut transaction, STORE_OBJECT_ID, 2 * fs.block_size())
2674 .await
2675 .expect("allocate failed")
2676 };
2678
2679 let mut transaction = fs
2680 .root_store()
2681 .new_transaction(lock_keys![], Options::default())
2682 .await
2683 .expect("new failed");
2684
2685 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 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 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 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 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 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 assert_eq!(allocator.get_allocated_bytes(), initial_allocated_bytes);
2766 check_allocations(&allocator, &device_ranges).await;
2767
2768 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 allocator.flush().await.expect("flush failed");
2791
2792 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 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 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 let fs_clone = fs.clone();
2922
2923 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 drop(executor_tasks);
2933
2934 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 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 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 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 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 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 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 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 assert_eq!(allocator.get_allocated_bytes(), allocated_bytes);
3261 }
3262
3263 assert_eq!(allocator.get_allocated_bytes(), allocated_bytes);
3265
3266 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 assert_eq!(allocator.get_allocated_bytes(), allocated_bytes);
3280
3281 transaction.commit().await.expect("commit failed");
3282
3283 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 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 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 (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 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 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 let max_extent_size = fs.device().size() as usize;
3435 const EXTENTS_PER_BATCH: usize = usize::MAX;
3436
3437 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 fasync::Timer::new(std::time::Duration::from_millis(100)).await;
3464
3465 {
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 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}