1mod legacy;
6
7pub use legacy::*;
8
9use crate::checksum::Checksums;
11use crate::log::error;
12use crate::lsm_tree::types::{
13 FuzzyHash, Item, ItemRef, LayerKey, MergeType, OrdLowerBound, OrdUpperBound, RangeKey,
14 SortByU64, Value,
15};
16use crate::object_store::extent_record::{
17 ExtentKey, ExtentKeyPartitionIterator, ExtentKeyV32, ExtentValue, ExtentValueV38,
18};
19use crate::serialized_types::{Migrate, Versioned, migrate_nodefault, migrate_to_version};
20use fprint::TypeFingerprint;
21use fxfs_crypto::{WrappedKey, WrappingKeyId};
22use fxfs_unicode::CasefoldString;
23use serde::{Deserialize, Serialize};
24use std::collections::BTreeMap;
25use std::default::Default;
26use std::hash::Hash;
27use std::time::{Duration, SystemTime, UNIX_EPOCH};
28
29pub type ObjectDescriptor = ObjectDescriptorV32;
31
32#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
33#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
34pub enum ObjectDescriptorV32 {
35 File,
37 Directory,
39 Volume,
41 Symlink,
43}
44
45pub type ProjectProperty = ProjectPropertyV32;
47
48#[derive(
49 Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint,
50)]
51#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
52pub enum ProjectPropertyV32 {
53 Limit,
55 Usage,
57}
58
59pub type ObjectKeyData = ObjectKeyDataV43;
60
61#[derive(
62 Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize, TypeFingerprint,
63)]
64#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
65pub enum ObjectKeyDataV43 {
66 Object,
69 Keys,
71 Attribute(u64, AttributeKeyV32),
73 Child { name: String },
75 GraveyardEntry { object_id: u64 },
77 Project { project_id: u64, property: ProjectPropertyV32 },
81 ExtendedAttribute {
84 #[serde(with = "crate::zerocopy_serialization")]
85 name: Vec<u8>,
86 },
87 GraveyardAttributeEntry { object_id: u64, attribute_id: u64 },
89 EncryptedCasefoldChild(EncryptedCasefoldChild),
94 CasefoldChild { name: CasefoldString },
97 EncryptedChild(EncryptedChild),
99}
100
101#[derive(
102 Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize, TypeFingerprint,
103)]
104#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
105pub struct EncryptedCasefoldChild {
106 pub hash_code: u32,
107 #[serde(with = "crate::zerocopy_serialization")]
108 pub name: Vec<u8>,
109}
110
111#[derive(
112 Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize, TypeFingerprint,
113)]
114#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
115pub struct EncryptedChild(#[serde(with = "crate::zerocopy_serialization")] pub Vec<u8>);
116
117pub type AttributeKey = AttributeKeyV32;
118
119#[derive(
120 Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint,
121)]
122#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
123pub enum AttributeKeyV32 {
124 Attribute,
126 Extent(ExtentKeyV32),
127}
128
129pub type ObjectKey = ObjectKeyV43;
131
132#[derive(
133 Clone,
134 Debug,
135 Eq,
136 Ord,
137 Hash,
138 PartialEq,
139 PartialOrd,
140 Serialize,
141 Deserialize,
142 TypeFingerprint,
143 Versioned,
144)]
145#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
146pub struct ObjectKeyV43 {
147 pub object_id: u64,
149 pub data: ObjectKeyDataV43,
151}
152
153impl SortByU64 for ObjectKey {
154 fn get_leading_u64(&self) -> u64 {
155 self.object_id
156 }
157}
158
159impl ObjectKey {
160 pub fn object(object_id: u64) -> Self {
162 Self { object_id: object_id, data: ObjectKeyData::Object }
163 }
164
165 pub fn keys(object_id: u64) -> Self {
167 Self { object_id, data: ObjectKeyData::Keys }
168 }
169
170 pub fn attribute(object_id: u64, attribute_id: u64, key: AttributeKey) -> Self {
172 Self { object_id, data: ObjectKeyData::Attribute(attribute_id, key) }
173 }
174
175 pub fn extent(object_id: u64, attribute_id: u64, range: std::ops::Range<u64>) -> Self {
177 Self {
178 object_id,
179 data: ObjectKeyData::Attribute(
180 attribute_id,
181 AttributeKey::Extent(ExtentKey::new(range)),
182 ),
183 }
184 }
185
186 pub fn from_extent(object_id: u64, attribute_id: u64, extent: ExtentKey) -> Self {
188 Self {
189 object_id,
190 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(extent)),
191 }
192 }
193
194 pub fn child(object_id: u64, name: &str, casefold: bool) -> Self {
196 if casefold {
197 Self { object_id, data: ObjectKeyData::CasefoldChild { name: name.into() } }
198 } else {
199 Self { object_id, data: ObjectKeyData::Child { name: name.into() } }
200 }
201 }
202
203 pub fn encrypted_child(object_id: u64, name: Vec<u8>, hash_code: Option<u32>) -> Self {
213 if let Some(hash_code) = hash_code {
214 Self {
215 object_id,
216 data: ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
217 hash_code,
218 name,
219 }),
220 }
221 } else {
222 Self { object_id, data: ObjectKeyData::EncryptedChild(EncryptedChild(name)) }
223 }
224 }
225
226 pub fn graveyard_entry(graveyard_object_id: u64, object_id: u64) -> Self {
228 Self { object_id: graveyard_object_id, data: ObjectKeyData::GraveyardEntry { object_id } }
229 }
230
231 pub fn graveyard_attribute_entry(
233 graveyard_object_id: u64,
234 object_id: u64,
235 attribute_id: u64,
236 ) -> Self {
237 Self {
238 object_id: graveyard_object_id,
239 data: ObjectKeyData::GraveyardAttributeEntry { object_id, attribute_id },
240 }
241 }
242
243 pub fn project_limit(object_id: u64, project_id: u64) -> Self {
245 Self {
246 object_id,
247 data: ObjectKeyData::Project { project_id, property: ProjectProperty::Limit },
248 }
249 }
250
251 pub fn project_usage(object_id: u64, project_id: u64) -> Self {
253 Self {
254 object_id,
255 data: ObjectKeyData::Project { project_id, property: ProjectProperty::Usage },
256 }
257 }
258
259 pub fn extended_attribute(object_id: u64, name: Vec<u8>) -> Self {
260 Self { object_id, data: ObjectKeyData::ExtendedAttribute { name } }
261 }
262
263 pub fn key_for_merge_into(&self) -> Self {
266 if let Self {
267 object_id,
268 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
269 } = self
270 {
271 Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.key_for_merge_into()))
272 } else {
273 self.clone()
274 }
275 }
276}
277
278impl OrdUpperBound for ObjectKey {
279 fn cmp_upper_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
280 self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
281 (
282 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
283 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
284 ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_upper_bound(right_extent)),
285 _ => self.data.cmp(&other.data),
286 })
287 }
288}
289
290impl OrdLowerBound for ObjectKey {
291 fn cmp_lower_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
292 self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
293 (
294 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
295 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
296 ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_lower_bound(right_extent)),
297 _ => self.data.cmp(&other.data),
298 })
299 }
300}
301
302impl LayerKey for ObjectKey {
303 fn merge_type(&self) -> MergeType {
304 match self.data {
307 ObjectKeyData::Object
308 | ObjectKeyData::Keys
309 | ObjectKeyData::Attribute(..)
310 | ObjectKeyData::Child { .. }
311 | ObjectKeyData::EncryptedChild(_)
312 | ObjectKeyData::EncryptedCasefoldChild(_)
313 | ObjectKeyData::CasefoldChild { .. }
314 | ObjectKeyData::GraveyardEntry { .. }
315 | ObjectKeyData::GraveyardAttributeEntry { .. }
316 | ObjectKeyData::Project { property: ProjectProperty::Limit, .. }
317 | ObjectKeyData::ExtendedAttribute { .. } => MergeType::OptimizedMerge,
318 ObjectKeyData::Project { property: ProjectProperty::Usage, .. } => MergeType::FullMerge,
319 }
320 }
321
322 fn next_key(&self) -> Option<Self> {
323 match self.data {
324 ObjectKeyData::Attribute(_, AttributeKey::Extent(_)) => {
325 let mut key = self.clone();
326 if let ObjectKey {
327 data: ObjectKeyData::Attribute(_, AttributeKey::Extent(ExtentKey { range })),
328 ..
329 } = &mut key
330 {
331 *range = range.end..range.end + 1;
335 }
336 Some(key)
337 }
338 _ => None,
339 }
340 }
341
342 fn search_key(&self) -> Self {
343 if let Self {
344 object_id,
345 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
346 } = self
347 {
348 Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.search_key()))
349 } else {
350 self.clone()
351 }
352 }
353}
354
355impl RangeKey for ObjectKey {
356 fn overlaps(&self, other: &Self) -> bool {
357 if self.object_id != other.object_id {
358 return false;
359 }
360 match (&self.data, &other.data) {
361 (
362 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_key)),
363 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_key)),
364 ) if *left_attr_id == *right_attr_id => {
365 left_key.range.end > right_key.range.start
366 && left_key.range.start < right_key.range.end
367 }
368 (a, b) => a == b,
369 }
370 }
371}
372
373pub enum ObjectKeyFuzzyHashIterator {
374 ExtentKey(u64, u64, ExtentKeyPartitionIterator),
375 NotExtentKey(Option<u64>),
376}
377
378impl Iterator for ObjectKeyFuzzyHashIterator {
379 type Item = u64;
380
381 fn next(&mut self) -> Option<Self::Item> {
382 match self {
383 Self::ExtentKey(oid, attr_id, extent_keys) => extent_keys.next().map(|range| {
384 let key = ObjectKey::extent(*oid, *attr_id, range);
385 crate::stable_hash::stable_hash(key)
386 }),
387 Self::NotExtentKey(hash) => hash.take(),
388 }
389 }
390}
391
392impl FuzzyHash for ObjectKey {
393 fn fuzzy_hash(&self) -> impl Iterator<Item = u64> {
394 match &self.data {
395 ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent)) => {
396 ObjectKeyFuzzyHashIterator::ExtentKey(
397 self.object_id,
398 *attr_id,
399 extent.fuzzy_hash_partition(),
400 )
401 }
402 _ => {
403 let hash = crate::stable_hash::stable_hash(self);
404 ObjectKeyFuzzyHashIterator::NotExtentKey(Some(hash))
405 }
406 }
407 }
408
409 fn is_range_key(&self) -> bool {
410 match &self.data {
411 ObjectKeyData::Attribute(_, AttributeKey::Extent(_)) => true,
412 _ => false,
413 }
414 }
415}
416
417pub type Timestamp = TimestampV49;
419
420#[derive(
421 Copy,
422 Clone,
423 Debug,
424 Default,
425 Eq,
426 PartialEq,
427 Ord,
428 PartialOrd,
429 Serialize,
430 Deserialize,
431 TypeFingerprint,
432)]
433#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
434pub struct TimestampV49 {
435 nanos: u64,
436}
437
438impl Timestamp {
439 const NSEC_PER_SEC: u64 = 1_000_000_000;
440
441 pub fn now() -> Self {
442 SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or(Duration::ZERO).into()
443 }
444
445 pub const fn zero() -> Self {
446 Self { nanos: 0 }
447 }
448
449 pub const fn from_nanos(nanos: u64) -> Self {
450 Self { nanos }
451 }
452
453 pub fn from_secs_and_nanos(secs: u64, nanos: u32) -> Self {
454 let Some(secs_in_nanos) = secs.checked_mul(Self::NSEC_PER_SEC) else {
455 error!("Fxfs doesn't support dates past 2554-07-21");
456 return Self { nanos: u64::MAX };
457 };
458 let Some(nanos) = secs_in_nanos.checked_add(nanos as u64) else {
459 error!("Fxfs doesn't support dates past 2554-07-21");
460 return Self { nanos: u64::MAX };
461 };
462 Self { nanos }
463 }
464
465 pub fn as_nanos(&self) -> u64 {
468 self.nanos
469 }
470
471 pub fn subsec_nanos(&self) -> u32 {
473 (self.nanos % Self::NSEC_PER_SEC) as u32
474 }
475
476 pub fn as_secs(&self) -> u64 {
479 self.nanos / Self::NSEC_PER_SEC
480 }
481}
482
483impl From<std::time::Duration> for Timestamp {
484 fn from(duration: std::time::Duration) -> Self {
485 Self::from_secs_and_nanos(duration.as_secs(), duration.subsec_nanos())
486 }
487}
488
489impl From<Timestamp> for std::time::Duration {
490 fn from(timestamp: Timestamp) -> std::time::Duration {
491 Duration::from_nanos(timestamp.nanos)
492 }
493}
494
495pub type ObjectKind = ObjectKindV49;
496
497#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
498#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
499pub enum ObjectKindV49 {
500 File {
501 refs: u64,
503 },
504 Directory {
505 sub_dirs: u64,
507 wrapping_key_id: Option<WrappingKeyId>,
510 casefold: bool,
513 },
514 Graveyard,
515 Symlink {
516 refs: u64,
518 #[serde(with = "crate::zerocopy_serialization")]
521 link: Box<[u8]>,
522 },
523 EncryptedSymlink {
524 refs: u64,
526 #[serde(with = "crate::zerocopy_serialization")]
531 link: Box<[u8]>,
532 },
533}
534
535pub type PosixAttributes = PosixAttributesV32;
538
539#[derive(Clone, Debug, Copy, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
540#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
541pub struct PosixAttributesV32 {
542 pub mode: u32,
544 pub uid: u32,
546 pub gid: u32,
548 pub rdev: u64,
550}
551
552pub type ObjectAttributes = ObjectAttributesV49;
556
557#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
558#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
559pub struct ObjectAttributesV49 {
560 pub creation_time: TimestampV49,
562 pub modification_time: TimestampV49,
564 pub project_id: u64,
566 pub posix_attributes: Option<PosixAttributesV32>,
568 pub allocated_size: u64,
570 pub access_time: TimestampV49,
572 pub change_time: TimestampV49,
574}
575
576pub type ExtendedAttributeValue = ExtendedAttributeValueV32;
577
578#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
579#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
580pub enum ExtendedAttributeValueV32 {
581 Inline(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
584 AttributeId(u64),
587}
588
589pub type ChildValue = ChildValueV32;
591
592#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
593#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
594pub struct ChildValueV32 {
595 pub object_id: u64,
597 pub object_descriptor: ObjectDescriptorV32,
599}
600
601pub type RootDigest = RootDigestV33;
602
603#[derive(
604 Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint,
605)]
606#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
607pub enum RootDigestV33 {
608 Sha256([u8; 32]),
609 Sha512(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
610}
611
612pub type FsverityMetadata = FsverityMetadataV50;
613
614#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
615#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
616pub enum FsverityMetadataV50 {
617 Internal(RootDigestV33, #[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
619 F2fs(std::ops::Range<u64>),
621}
622
623pub type EncryptionKey = EncryptionKeyV49;
624pub type EncryptionKeyV49 = fxfs_crypto::EncryptionKey;
625
626pub type EncryptionKeys = EncryptionKeysV49;
627
628#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
629#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
630pub struct EncryptionKeysV49(Vec<(u64, EncryptionKeyV49)>);
631
632impl EncryptionKeys {
633 pub fn get(&self, id: u64) -> Option<&EncryptionKey> {
634 self.0.iter().find_map(|(i, key)| (*i == id).then_some(key))
635 }
636
637 pub fn insert(&mut self, id: u64, key: EncryptionKey) {
638 self.0.push((id, key))
639 }
640
641 pub fn remove(&mut self, id: u64) -> Option<EncryptionKey> {
642 if let Some(ix) = self.0.iter().position(|(k, _)| *k == id) {
643 Some(self.0.remove(ix).1)
644 } else {
645 None
646 }
647 }
648}
649
650impl From<EncryptionKeys> for BTreeMap<u64, WrappedKey> {
651 fn from(keys: EncryptionKeys) -> Self {
652 keys.0.into_iter().map(|(id, key)| (id, key.into())).collect()
653 }
654}
655
656impl From<Vec<(u64, EncryptionKey)>> for EncryptionKeys {
657 fn from(value: Vec<(u64, EncryptionKey)>) -> Self {
658 Self(value)
659 }
660}
661
662impl std::ops::Deref for EncryptionKeys {
663 type Target = Vec<(u64, EncryptionKey)>;
664 fn deref(&self) -> &Self::Target {
665 &self.0
666 }
667}
668
669pub type ObjectValue = ObjectValueV50;
673impl Value for ObjectValue {
674 const DELETED_MARKER: Self = Self::None;
675}
676
677#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
678#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
679pub enum ObjectValueV50 {
680 None,
684 Some,
687 Object { kind: ObjectKindV49, attributes: ObjectAttributesV49 },
689 Keys(EncryptionKeysV49),
691 Attribute { size: u64, has_overwrite_extents: bool },
693 Extent(ExtentValueV38),
695 Child(ChildValueV32),
697 Trim,
701 BytesAndNodes { bytes: i64, nodes: i64 },
703 ExtendedAttribute(ExtendedAttributeValueV32),
706 VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV50 },
709}
710
711impl ObjectValue {
712 pub fn file(
714 refs: u64,
715 allocated_size: u64,
716 creation_time: Timestamp,
717 modification_time: Timestamp,
718 access_time: Timestamp,
719 change_time: Timestamp,
720 project_id: u64,
721 posix_attributes: Option<PosixAttributes>,
722 ) -> ObjectValue {
723 ObjectValue::Object {
724 kind: ObjectKind::File { refs },
725 attributes: ObjectAttributes {
726 creation_time,
727 modification_time,
728 project_id,
729 posix_attributes,
730 allocated_size,
731 access_time,
732 change_time,
733 },
734 }
735 }
736 pub fn keys(encryption_keys: EncryptionKeys) -> ObjectValue {
737 ObjectValue::Keys(encryption_keys)
738 }
739 pub fn attribute(size: u64, has_overwrite_extents: bool) -> ObjectValue {
741 ObjectValue::Attribute { size, has_overwrite_extents }
742 }
743 pub fn verified_attribute(size: u64, fsverity_metadata: FsverityMetadata) -> ObjectValue {
745 ObjectValue::VerifiedAttribute { size, fsverity_metadata }
746 }
747 pub fn extent(device_offset: u64, key_id: u64) -> ObjectValue {
749 ObjectValue::Extent(ExtentValue::new_raw(device_offset, key_id))
750 }
751 pub fn extent_with_checksum(
753 device_offset: u64,
754 checksum: Checksums,
755 key_id: u64,
756 ) -> ObjectValue {
757 ObjectValue::Extent(ExtentValue::with_checksum(device_offset, checksum, key_id))
758 }
759 pub fn deleted_extent() -> ObjectValue {
761 ObjectValue::Extent(ExtentValue::deleted_extent())
762 }
763 pub fn child(object_id: u64, object_descriptor: ObjectDescriptor) -> ObjectValue {
765 ObjectValue::Child(ChildValue { object_id, object_descriptor })
766 }
767 pub fn symlink(
769 link: impl Into<Box<[u8]>>,
770 creation_time: Timestamp,
771 modification_time: Timestamp,
772 project_id: u64,
773 ) -> ObjectValue {
774 ObjectValue::Object {
775 kind: ObjectKind::Symlink { refs: 1, link: link.into() },
776 attributes: ObjectAttributes {
777 creation_time,
778 modification_time,
779 project_id,
780 ..Default::default()
781 },
782 }
783 }
784 pub fn encrypted_symlink(
786 link: impl Into<Box<[u8]>>,
787 creation_time: Timestamp,
788 modification_time: Timestamp,
789 project_id: u64,
790 ) -> ObjectValue {
791 ObjectValue::Object {
792 kind: ObjectKind::EncryptedSymlink { refs: 1, link: link.into() },
793 attributes: ObjectAttributes {
794 creation_time,
795 modification_time,
796 project_id,
797 ..Default::default()
798 },
799 }
800 }
801 pub fn inline_extended_attribute(value: impl Into<Vec<u8>>) -> ObjectValue {
802 ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(value.into()))
803 }
804 pub fn extended_attribute(attribute_id: u64) -> ObjectValue {
805 ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(attribute_id))
806 }
807}
808
809pub type ObjectItem = ObjectItemV50;
810pub type ObjectItemV50 = Item<ObjectKeyV43, ObjectValueV50>;
811
812impl ObjectItem {
813 pub fn is_tombstone(&self) -> bool {
814 matches!(
815 self,
816 Item {
817 key: ObjectKey { data: ObjectKeyData::Object, .. },
818 value: ObjectValue::None,
819 ..
820 }
821 )
822 }
823}
824
825impl<'a> From<ItemRef<'a, ObjectKey, ObjectValue>>
827 for Option<(u64, u64, &'a ExtentKey, &'a ExtentValue)>
828{
829 fn from(item: ItemRef<'a, ObjectKey, ObjectValue>) -> Self {
830 match item {
831 ItemRef {
832 key:
833 ObjectKey {
834 object_id,
835 data:
836 ObjectKeyData::Attribute(
837 attribute_id, AttributeKey::Extent(extent_key),
839 ),
840 },
841 value: ObjectValue::Extent(extent_value),
842 ..
843 } => Some((*object_id, *attribute_id, extent_key, extent_value)),
844 _ => None,
845 }
846 }
847}
848
849pub type FxfsKey = FxfsKeyV49;
850pub type FxfsKeyV49 = fxfs_crypto::FxfsKey;
851
852#[cfg(test)]
853mod tests {
854 use super::{ObjectKey, ObjectKeyV43, TimestampV49};
855 use crate::lsm_tree::types::{
856 FuzzyHash as _, LayerKey, OrdLowerBound, OrdUpperBound, RangeKey,
857 };
858 use std::cmp::Ordering;
859 use std::ops::Add;
860 use std::time::{Duration, SystemTime, UNIX_EPOCH};
861
862 #[test]
867 fn test_hash_stability() {
868 assert_eq!(
872 &ObjectKeyV43::object(100).fuzzy_hash().collect::<Vec<_>>()[..],
873 &[11885326717398844384]
874 );
875 assert_eq!(
876 &ObjectKeyV43::extent(1, 0, 0..2 * 1024 * 1024).fuzzy_hash().collect::<Vec<_>>()[..],
877 &[11090579907097549012, 2814892992701560424]
878 );
879 }
880
881 #[test]
882 fn test_next_key() {
883 let next_key = ObjectKey::extent(1, 0, 0..100).next_key().unwrap();
884 assert_eq!(ObjectKey::extent(1, 0, 101..200).cmp_lower_bound(&next_key), Ordering::Greater);
885 assert_eq!(ObjectKey::extent(1, 0, 100..200).cmp_lower_bound(&next_key), Ordering::Equal);
886 assert_eq!(ObjectKey::extent(1, 0, 100..101).cmp_lower_bound(&next_key), Ordering::Equal);
887 assert_eq!(ObjectKey::extent(1, 0, 99..100).cmp_lower_bound(&next_key), Ordering::Less);
888 assert_eq!(ObjectKey::extent(1, 0, 0..100).cmp_upper_bound(&next_key), Ordering::Less);
889 assert_eq!(ObjectKey::extent(1, 0, 99..100).cmp_upper_bound(&next_key), Ordering::Less);
890 assert_eq!(ObjectKey::extent(1, 0, 100..101).cmp_upper_bound(&next_key), Ordering::Equal);
891 assert_eq!(ObjectKey::extent(1, 0, 100..200).cmp_upper_bound(&next_key), Ordering::Greater);
892 assert_eq!(ObjectKey::extent(1, 0, 50..101).cmp_upper_bound(&next_key), Ordering::Equal);
893 assert_eq!(ObjectKey::extent(1, 0, 50..200).cmp_upper_bound(&next_key), Ordering::Greater);
894 }
895 #[test]
896 fn test_range_key() {
897 assert!(ObjectKeyV43::extent(1, 0, 0..2 * 1024 * 1024).is_range_key());
900 assert!(!ObjectKeyV43::object(100).is_range_key());
901
902 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(1)), true);
903 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(2)), false);
904 assert_eq!(ObjectKey::extent(1, 0, 0..100).overlaps(&ObjectKey::object(1)), false);
905 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::extent(1, 0, 0..100)), false);
906 assert_eq!(
907 ObjectKey::extent(1, 0, 0..100).overlaps(&ObjectKey::extent(2, 0, 0..100)),
908 false
909 );
910 assert_eq!(
911 ObjectKey::extent(1, 0, 0..100).overlaps(&ObjectKey::extent(1, 1, 0..100)),
912 false
913 );
914 assert_eq!(
915 ObjectKey::extent(1, 0, 0..100).overlaps(&ObjectKey::extent(1, 0, 0..100)),
916 true
917 );
918
919 assert_eq!(
920 ObjectKey::extent(1, 0, 0..50).overlaps(&ObjectKey::extent(1, 0, 49..100)),
921 true
922 );
923 assert_eq!(
924 ObjectKey::extent(1, 0, 49..100).overlaps(&ObjectKey::extent(1, 0, 0..50)),
925 true
926 );
927
928 assert_eq!(
929 ObjectKey::extent(1, 0, 0..50).overlaps(&ObjectKey::extent(1, 0, 50..100)),
930 false
931 );
932 assert_eq!(
933 ObjectKey::extent(1, 0, 50..100).overlaps(&ObjectKey::extent(1, 0, 0..50)),
934 false
935 );
936 }
937
938 #[test]
939 fn test_timestamp() {
940 fn compare_time(std_time: Duration) {
941 let ts_time: TimestampV49 = std_time.into();
942 assert_eq!(<TimestampV49 as Into<Duration>>::into(ts_time), std_time);
943 assert_eq!(ts_time.subsec_nanos(), std_time.subsec_nanos());
944 assert_eq!(ts_time.as_secs(), std_time.as_secs());
945 assert_eq!(ts_time.as_nanos() as u128, std_time.as_nanos());
946 }
947 compare_time(Duration::from_nanos(0));
948 compare_time(Duration::from_nanos(u64::MAX));
949 compare_time(SystemTime::now().duration_since(UNIX_EPOCH).unwrap());
950
951 let ts: TimestampV49 = Duration::from_secs(u64::MAX - 1).into();
952 assert_eq!(ts.nanos, u64::MAX);
953
954 let ts: TimestampV49 = (Duration::from_nanos(u64::MAX).add(Duration::from_nanos(1))).into();
955 assert_eq!(ts.nanos, u64::MAX);
956 }
957}