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, LegacyItem, MergeType, OrdLowerBound, OrdUpperBound,
14 SortByU64, Value,
15};
16use crate::object_store::ProjectId;
17use crate::object_store::extent::{Extent, ExtentPartitionIterator};
18use crate::object_store::extent_record::{ExtentValue, ExtentValueV38};
19use crate::serialized_types::{Migrate, Versioned, migrate_nodefault, migrate_to_version};
20use fprint::TypeFingerprint;
21use fxfs_crypto::{WrappedKey, WrappingKeyId};
22use fxfs_macros::SerializeKey;
23use fxfs_unicode::CasefoldString;
24use serde::{Deserialize, Serialize};
25use std::collections::BTreeMap;
26use std::default::Default;
27use std::hash::Hash;
28use std::time::{Duration, SystemTime, UNIX_EPOCH};
29
30pub type ObjectDescriptor = ObjectDescriptorV32;
32
33#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
34#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
35pub enum ObjectDescriptorV32 {
36 File,
38 Directory,
40 Volume,
42 Symlink,
44}
45
46pub type ProjectProperty = ProjectPropertyV32;
48
49#[derive(
50 Clone,
51 Debug,
52 Eq,
53 Hash,
54 Ord,
55 PartialEq,
56 PartialOrd,
57 Serialize,
58 Deserialize,
59 TypeFingerprint,
60 SerializeKey,
61)]
62#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
63pub enum ProjectPropertyV32 {
64 Limit,
66 Usage,
68}
69
70pub type ObjectKeyData = ObjectKeyDataV54;
71
72#[derive(
73 Clone,
74 Debug,
75 Eq,
76 Hash,
77 PartialEq,
78 PartialOrd,
79 Ord,
80 Serialize,
81 Deserialize,
82 TypeFingerprint,
83 SerializeKey,
84)]
85#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
86pub enum ObjectKeyDataV54 {
87 Object,
90 Keys,
92 Attribute(AttributeId, AttributeKeyV32),
94 Child { name: String },
96 GraveyardEntry { object_id: u64 },
98 Project { project_id: ProjectId, property: ProjectPropertyV32 },
102 ExtendedAttribute {
105 #[serde(with = "crate::zerocopy_serialization")]
106 name: Vec<u8>,
107 },
108 GraveyardAttributeEntry { object_id: u64, attribute_id: AttributeId },
110 EncryptedCasefoldChild(EncryptedCasefoldChild),
115 LegacyCasefoldChild(CasefoldString),
117 EncryptedChild(EncryptedChild),
119 CasefoldChild { hash_code: u32, name: String },
122}
123
124#[derive(
125 Clone,
126 Debug,
127 Eq,
128 Hash,
129 PartialEq,
130 PartialOrd,
131 Ord,
132 Serialize,
133 Deserialize,
134 TypeFingerprint,
135 SerializeKey,
136)]
137#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
138pub struct EncryptedCasefoldChild {
139 pub hash_code: u32,
140 #[serde(with = "crate::zerocopy_serialization")]
141 pub name: Vec<u8>,
142}
143
144#[derive(
145 Clone,
146 Debug,
147 Eq,
148 Hash,
149 PartialEq,
150 PartialOrd,
151 Ord,
152 Serialize,
153 Deserialize,
154 TypeFingerprint,
155 SerializeKey,
156)]
157#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
158pub struct EncryptedChild(#[serde(with = "crate::zerocopy_serialization")] pub Vec<u8>);
159
160pub type AttributeKey = AttributeKeyV32;
161
162#[derive(
163 Clone,
164 Debug,
165 Eq,
166 Hash,
167 Ord,
168 PartialEq,
169 PartialOrd,
170 Serialize,
171 Deserialize,
172 TypeFingerprint,
173 SerializeKey,
174)]
175#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
176pub enum AttributeKeyV32 {
177 Attribute,
179 Extent(Extent),
180}
181
182pub type ObjectKey = ObjectKeyV54;
184
185#[derive(
186 Clone,
187 Debug,
188 Eq,
189 Ord,
190 Hash,
191 PartialEq,
192 PartialOrd,
193 Serialize,
194 Deserialize,
195 SerializeKey,
196 TypeFingerprint,
197 Versioned,
198)]
199#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
200pub struct ObjectKeyV54 {
201 pub object_id: u64,
203 pub data: ObjectKeyDataV54,
205}
206
207impl SortByU64 for ObjectKey {
208 fn get_leading_u64(&self) -> u64 {
209 self.object_id
210 }
211}
212
213impl ObjectKey {
214 pub fn object(object_id: u64) -> Self {
216 Self { object_id: object_id, data: ObjectKeyData::Object }
217 }
218
219 pub fn keys(object_id: u64) -> Self {
221 Self { object_id, data: ObjectKeyData::Keys }
222 }
223
224 pub fn attribute(object_id: u64, attribute_id: AttributeId, key: AttributeKey) -> Self {
226 Self { object_id, data: ObjectKeyData::Attribute(attribute_id, key) }
227 }
228
229 pub fn extent(object_id: u64, attribute_id: AttributeId, range: std::ops::Range<u64>) -> Self {
231 Self {
232 object_id,
233 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(Extent(range))),
234 }
235 }
236
237 pub fn from_extent(object_id: u64, attribute_id: AttributeId, extent: Extent) -> Self {
239 Self {
240 object_id,
241 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(extent)),
242 }
243 }
244
245 pub fn child(object_id: u64, name: &str, dir_type: DirType) -> Self {
247 match dir_type {
248 DirType::Casefold => {
249 let casefolded_name: String = fxfs_unicode::casefold(name.chars()).collect();
250 let hash_code = fscrypt::direntry::tea_hash_filename(casefolded_name.as_bytes());
251 Self {
252 object_id,
253 data: ObjectKeyData::CasefoldChild { hash_code, name: name.into() },
254 }
255 }
256 DirType::LegacyCasefold => Self {
257 object_id,
258 data: ObjectKeyData::LegacyCasefoldChild(CasefoldString::new(name.into())),
259 },
260 DirType::Normal => Self { object_id, data: ObjectKeyData::Child { name: name.into() } },
261 DirType::Encrypted(_) | DirType::EncryptedCasefold(_) => {
262 panic!("Encrypted modes require an encrypted name");
264 }
265 }
266 }
267
268 pub fn encrypted_child(object_id: u64, name: Vec<u8>, hash_code: Option<u32>) -> Self {
278 if let Some(hash_code) = hash_code {
279 Self {
280 object_id,
281 data: ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
282 hash_code,
283 name,
284 }),
285 }
286 } else {
287 Self { object_id, data: ObjectKeyData::EncryptedChild(EncryptedChild(name)) }
288 }
289 }
290
291 pub fn graveyard_entry(graveyard_object_id: u64, object_id: u64) -> Self {
293 Self { object_id: graveyard_object_id, data: ObjectKeyData::GraveyardEntry { object_id } }
294 }
295
296 pub fn graveyard_attribute_entry(
298 graveyard_object_id: u64,
299 object_id: u64,
300 attribute_id: AttributeId,
301 ) -> Self {
302 Self {
303 object_id: graveyard_object_id,
304 data: ObjectKeyData::GraveyardAttributeEntry { object_id, attribute_id },
305 }
306 }
307
308 pub fn project_limit(object_id: u64, project_id: ProjectId) -> Self {
310 Self {
311 object_id,
312 data: ObjectKeyData::Project { project_id, property: ProjectProperty::Limit },
313 }
314 }
315
316 pub fn project_usage(object_id: u64, project_id: ProjectId) -> Self {
318 Self {
319 object_id,
320 data: ObjectKeyData::Project { project_id, property: ProjectProperty::Usage },
321 }
322 }
323
324 pub fn extended_attribute(object_id: u64, name: Vec<u8>) -> Self {
325 Self { object_id, data: ObjectKeyData::ExtendedAttribute { name } }
326 }
327
328 pub fn key_for_merge_into(&self) -> Self {
331 if let Self {
332 object_id,
333 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
334 } = self
335 {
336 Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.key_for_merge_into()))
337 } else {
338 self.clone()
339 }
340 }
341}
342
343impl OrdUpperBound for ObjectKey {
344 fn cmp_upper_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
345 self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
346 (
347 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
348 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
349 ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_upper_bound(right_extent)),
350 _ => self.data.cmp(&other.data),
351 })
352 }
353}
354
355impl OrdLowerBound for ObjectKey {
356 fn cmp_lower_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
357 self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
358 (
359 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
360 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
361 ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_lower_bound(right_extent)),
362 _ => self.data.cmp(&other.data),
363 })
364 }
365}
366
367impl LayerKey for ObjectKey {
368 fn merge_type(&self) -> MergeType {
369 match self.data {
372 ObjectKeyData::Object
373 | ObjectKeyData::Keys
374 | ObjectKeyData::Attribute(..)
375 | ObjectKeyData::Child { .. }
376 | ObjectKeyData::EncryptedChild(_)
377 | ObjectKeyData::EncryptedCasefoldChild(_)
378 | ObjectKeyData::CasefoldChild { .. }
379 | ObjectKeyData::LegacyCasefoldChild(_)
380 | ObjectKeyData::GraveyardEntry { .. }
381 | ObjectKeyData::GraveyardAttributeEntry { .. }
382 | ObjectKeyData::Project { property: ProjectProperty::Limit, .. }
383 | ObjectKeyData::ExtendedAttribute { .. } => MergeType::OptimizedMerge,
384 ObjectKeyData::Project { property: ProjectProperty::Usage, .. } => MergeType::FullMerge,
385 }
386 }
387
388 fn next_key(&self) -> Option<Self> {
389 match &self.data {
390 ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent)) => {
391 Some(ObjectKey {
395 object_id: self.object_id,
396 data: ObjectKeyData::Attribute(
397 *attr_id,
398 AttributeKey::Extent(Extent(0..extent.end + 1)),
399 ),
400 })
401 }
402 _ => None,
403 }
404 }
405
406 fn search_key(&self) -> Option<Self> {
407 if let Self {
408 object_id,
409 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
410 } = self
411 {
412 Some(Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.search_key())))
413 } else {
414 None
415 }
416 }
417
418 fn is_search_key(&self) -> bool {
419 match self {
420 Self { data: ObjectKeyData::Attribute(_, AttributeKey::Extent(e)), .. } => e.start == 0,
421 _ => true,
422 }
423 }
424
425 fn overlaps(&self, other: &Self) -> bool {
426 if self.object_id != other.object_id {
427 return false;
428 }
429 match (&self.data, &other.data) {
430 (
431 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_key)),
432 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_key)),
433 ) if *left_attr_id == *right_attr_id => {
434 left_key.end > right_key.start && left_key.start < right_key.end
435 }
436 (a, b) => a == b,
437 }
438 }
439}
440
441pub enum ObjectKeyFuzzyHashIterator {
442 Extent(u64, AttributeId, ExtentPartitionIterator),
443 NotExtent(Option<u64>),
444}
445
446impl Iterator for ObjectKeyFuzzyHashIterator {
447 type Item = u64;
448
449 fn next(&mut self) -> Option<Self::Item> {
450 match self {
451 Self::Extent(oid, attr_id, extent_keys) => extent_keys.next().map(|range| {
452 let key = ObjectKey::extent(*oid, *attr_id, range);
453 crate::stable_hash::stable_hash(key)
454 }),
455 Self::NotExtent(hash) => hash.take(),
456 }
457 }
458}
459
460impl FuzzyHash for ObjectKey {
461 fn fuzzy_hash(&self) -> impl Iterator<Item = u64> {
462 match &self.data {
463 ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent)) => {
464 ObjectKeyFuzzyHashIterator::Extent(
465 self.object_id,
466 *attr_id,
467 extent.fuzzy_hash_partition(),
468 )
469 }
470 _ => {
471 let hash = crate::stable_hash::stable_hash(self);
472 ObjectKeyFuzzyHashIterator::NotExtent(Some(hash))
473 }
474 }
475 }
476
477 fn is_range_key(&self) -> bool {
478 match &self.data {
479 ObjectKeyData::Attribute(_, AttributeKey::Extent(_)) => true,
480 _ => false,
481 }
482 }
483}
484
485pub type Timestamp = TimestampV49;
487
488#[derive(
489 Copy,
490 Clone,
491 Debug,
492 Default,
493 Eq,
494 PartialEq,
495 Ord,
496 PartialOrd,
497 Serialize,
498 Deserialize,
499 TypeFingerprint,
500)]
501#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
502pub struct TimestampV49 {
503 nanos: u64,
504}
505
506impl Timestamp {
507 const NSEC_PER_SEC: u64 = 1_000_000_000;
508
509 pub fn now() -> Self {
510 SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or(Duration::ZERO).into()
511 }
512
513 pub const fn zero() -> Self {
514 Self { nanos: 0 }
515 }
516
517 pub const fn from_nanos(nanos: u64) -> Self {
518 Self { nanos }
519 }
520
521 pub fn from_secs_and_nanos(secs: u64, nanos: u32) -> Self {
522 let Some(secs_in_nanos) = secs.checked_mul(Self::NSEC_PER_SEC) else {
523 error!("Fxfs doesn't support dates past 2554-07-21");
524 return Self { nanos: u64::MAX };
525 };
526 let Some(nanos) = secs_in_nanos.checked_add(nanos as u64) else {
527 error!("Fxfs doesn't support dates past 2554-07-21");
528 return Self { nanos: u64::MAX };
529 };
530 Self { nanos }
531 }
532
533 pub fn as_nanos(&self) -> u64 {
536 self.nanos
537 }
538
539 pub fn subsec_nanos(&self) -> u32 {
541 (self.nanos % Self::NSEC_PER_SEC) as u32
542 }
543
544 pub fn as_secs(&self) -> u64 {
547 self.nanos / Self::NSEC_PER_SEC
548 }
549}
550
551impl From<std::time::Duration> for Timestamp {
552 fn from(duration: std::time::Duration) -> Self {
553 Self::from_secs_and_nanos(duration.as_secs(), duration.subsec_nanos())
554 }
555}
556
557impl From<Timestamp> for std::time::Duration {
558 fn from(timestamp: Timestamp) -> std::time::Duration {
559 Duration::from_nanos(timestamp.nanos)
560 }
561}
562
563pub type ObjectKind = ObjectKindV54;
564
565#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, TypeFingerprint)]
566#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
567pub enum DirType {
568 Normal,
569 Encrypted(WrappingKeyId),
570 LegacyCasefold,
572 Casefold,
573 EncryptedCasefold(WrappingKeyId),
574}
575
576impl DirType {
577 pub fn is_casefold(&self) -> bool {
578 matches!(self, DirType::LegacyCasefold | DirType::Casefold | DirType::EncryptedCasefold(_))
579 }
580
581 pub fn is_encrypted(&self) -> bool {
582 matches!(self, DirType::Encrypted(_) | DirType::EncryptedCasefold(_))
583 }
584
585 pub fn with_encryption(self, id: WrappingKeyId) -> Self {
586 match self {
587 DirType::Normal => DirType::Encrypted(id),
588 DirType::Casefold => DirType::EncryptedCasefold(id),
589 _ => self,
590 }
591 }
592
593 pub fn with_casefold(self, val: bool) -> Self {
594 match (val, self) {
595 (true, DirType::Encrypted(id) | DirType::EncryptedCasefold(id)) => {
596 DirType::EncryptedCasefold(id)
597 }
598 (true, _) => DirType::Casefold,
599 (false, DirType::Encrypted(id) | DirType::EncryptedCasefold(id)) => {
600 DirType::Encrypted(id)
601 }
602 (false, _) => DirType::Normal,
603 }
604 }
605
606 pub fn wrapping_key_id(&self) -> Option<WrappingKeyId> {
607 match self {
608 DirType::Encrypted(id) | DirType::EncryptedCasefold(id) => Some(*id),
609 _ => None,
610 }
611 }
612}
613
614impl Default for DirType {
615 fn default() -> Self {
616 DirType::Normal
617 }
618}
619
620#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
621#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
622pub enum ObjectKindV54 {
623 File {
624 refs: u64,
626 },
627 Directory {
628 sub_dirs: u64,
630 dir_type: DirType,
632 },
633 Graveyard,
634 Symlink {
635 refs: u64,
637 #[serde(with = "crate::zerocopy_serialization")]
640 link: Box<[u8]>,
641 },
642 EncryptedSymlink {
643 refs: u64,
645 #[serde(with = "crate::zerocopy_serialization")]
650 link: Box<[u8]>,
651 },
652}
653
654#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
655#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
656pub enum ObjectKindV49 {
657 File {
658 refs: u64,
660 },
661 Directory {
662 sub_dirs: u64,
664 wrapping_key_id: Option<WrappingKeyId>,
667 casefold: bool,
670 },
671 Graveyard,
672 Symlink {
673 refs: u64,
675 #[serde(with = "crate::zerocopy_serialization")]
678 link: Box<[u8]>,
679 },
680 EncryptedSymlink {
681 refs: u64,
683 #[serde(with = "crate::zerocopy_serialization")]
688 link: Box<[u8]>,
689 },
690}
691
692pub type PosixAttributes = PosixAttributesV32;
695
696#[derive(Clone, Debug, Copy, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
697#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
698pub struct PosixAttributesV32 {
699 pub mode: u32,
701 pub uid: u32,
703 pub gid: u32,
705 pub rdev: u64,
707}
708
709pub type ObjectAttributes = ObjectAttributesV49;
713
714#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
715#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
716pub struct ObjectAttributesV49 {
717 pub creation_time: TimestampV49,
719 pub modification_time: TimestampV49,
721 #[serde(with = "crate::object_store::project_id::optional_project_id")]
723 pub project_id: Option<ProjectId>,
724 pub posix_attributes: Option<PosixAttributesV32>,
726 pub allocated_size: u64,
728 pub access_time: TimestampV49,
730 pub change_time: TimestampV49,
732}
733
734pub type ExtendedAttributeValue = ExtendedAttributeValueV32;
735
736#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
737#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
738pub enum ExtendedAttributeValueV32 {
739 Inline(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
742 AttributeId(AttributeId),
745}
746
747pub type ChildValue = ChildValueV32;
749
750#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
751#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
752pub struct ChildValueV32 {
753 pub object_id: u64,
755 pub object_descriptor: ObjectDescriptorV32,
757}
758
759pub type RootDigest = RootDigestV33;
760
761#[derive(
762 Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint,
763)]
764#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
765pub enum RootDigestV33 {
766 Sha256([u8; 32]),
767 Sha512(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
768}
769
770pub type FsverityMetadata = FsverityMetadataV50;
771
772#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
773#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
774pub enum FsverityMetadataV50 {
775 Internal(RootDigestV33, #[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
777 F2fs(std::ops::Range<u64>),
779}
780
781pub type EncryptionKey = EncryptionKeyV49;
782pub type EncryptionKeyV49 = fxfs_crypto::EncryptionKey;
783
784pub type EncryptionKeys = EncryptionKeysV49;
785
786#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
787#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
788pub struct EncryptionKeysV49(Vec<(u64, EncryptionKeyV49)>);
789
790impl EncryptionKeys {
791 pub fn get(&self, id: u64) -> Option<&EncryptionKey> {
792 self.0.iter().find_map(|(i, key)| (*i == id).then_some(key))
793 }
794
795 pub fn insert(&mut self, id: u64, key: EncryptionKey) {
796 self.0.push((id, key))
797 }
798
799 pub fn remove(&mut self, id: u64) -> Option<EncryptionKey> {
800 if let Some(ix) = self.0.iter().position(|(k, _)| *k == id) {
801 Some(self.0.remove(ix).1)
802 } else {
803 None
804 }
805 }
806}
807
808impl From<EncryptionKeys> for BTreeMap<u64, WrappedKey> {
809 fn from(keys: EncryptionKeys) -> Self {
810 keys.0.into_iter().map(|(id, key)| (id, key.into())).collect()
811 }
812}
813
814impl From<Vec<(u64, EncryptionKey)>> for EncryptionKeys {
815 fn from(value: Vec<(u64, EncryptionKey)>) -> Self {
816 Self(value)
817 }
818}
819
820impl std::ops::Deref for EncryptionKeys {
821 type Target = Vec<(u64, EncryptionKey)>;
822 fn deref(&self) -> &Self::Target {
823 &self.0
824 }
825}
826
827pub type ObjectValue = ObjectValueV54;
831impl Value for ObjectValue {
832 const DELETED_MARKER: Self = Self::None;
833}
834
835#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
836#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
837pub enum ObjectValueV54 {
838 None,
842 Some,
845 Object { kind: ObjectKindV54, attributes: ObjectAttributesV49 },
847 Keys(EncryptionKeysV49),
849 Attribute { size: u64, has_overwrite_extents: bool },
851 Extent(ExtentValueV38),
853 Child(ChildValue),
855 Trim,
859 BytesAndNodes { bytes: i64, nodes: i64 },
861 ExtendedAttribute(ExtendedAttributeValueV32),
864 VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV50 },
867}
868
869#[derive(Migrate, Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
870#[migrate_to_version(ObjectValueV54)]
871#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
872pub enum ObjectValueV50 {
873 None,
877 Some,
880 Object { kind: ObjectKindV49, attributes: ObjectAttributesV49 },
882 Keys(EncryptionKeysV49),
884 Attribute { size: u64, has_overwrite_extents: bool },
886 Extent(ExtentValueV38),
888 Child(ChildValueV32),
890 Trim,
894 BytesAndNodes { bytes: i64, nodes: i64 },
896 ExtendedAttribute(ExtendedAttributeValueV32),
899 VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV50 },
902}
903
904impl ObjectValue {
905 pub fn file(
907 refs: u64,
908 allocated_size: u64,
909 creation_time: Timestamp,
910 modification_time: Timestamp,
911 access_time: Timestamp,
912 change_time: Timestamp,
913 project_id: Option<ProjectId>,
914 posix_attributes: Option<PosixAttributes>,
915 ) -> ObjectValue {
916 ObjectValue::Object {
917 kind: ObjectKind::File { refs },
918 attributes: ObjectAttributes {
919 creation_time,
920 modification_time,
921 project_id,
922 posix_attributes,
923 allocated_size,
924 access_time,
925 change_time,
926 },
927 }
928 }
929 pub fn keys(encryption_keys: EncryptionKeys) -> ObjectValue {
930 ObjectValue::Keys(encryption_keys)
931 }
932 pub fn attribute(size: u64, has_overwrite_extents: bool) -> ObjectValue {
934 ObjectValue::Attribute { size, has_overwrite_extents }
935 }
936 pub fn verified_attribute(size: u64, fsverity_metadata: FsverityMetadata) -> ObjectValue {
938 ObjectValue::VerifiedAttribute { size, fsverity_metadata }
939 }
940 pub fn extent(device_offset: u64, key_id: u64) -> ObjectValue {
942 ObjectValue::Extent(ExtentValue::new_raw(device_offset, key_id))
943 }
944 pub fn extent_with_checksum(
946 device_offset: u64,
947 checksum: Checksums,
948 key_id: u64,
949 ) -> ObjectValue {
950 ObjectValue::Extent(ExtentValue::with_checksum(device_offset, checksum, key_id))
951 }
952 pub fn deleted_extent() -> ObjectValue {
954 ObjectValue::Extent(ExtentValue::deleted_extent())
955 }
956 pub fn child(object_id: u64, object_descriptor: ObjectDescriptor) -> ObjectValue {
958 ObjectValue::Child(ChildValue { object_id, object_descriptor })
959 }
960 pub fn symlink(
962 link: impl Into<Box<[u8]>>,
963 creation_time: Timestamp,
964 modification_time: Timestamp,
965 project_id: Option<ProjectId>,
966 ) -> ObjectValue {
967 ObjectValue::Object {
968 kind: ObjectKind::Symlink { refs: 1, link: link.into() },
969 attributes: ObjectAttributes {
970 creation_time,
971 modification_time,
972 project_id,
973 ..Default::default()
974 },
975 }
976 }
977 pub fn encrypted_symlink(
979 link: impl Into<Box<[u8]>>,
980 creation_time: Timestamp,
981 modification_time: Timestamp,
982 project_id: Option<ProjectId>,
983 ) -> ObjectValue {
984 ObjectValue::Object {
985 kind: ObjectKind::EncryptedSymlink { refs: 1, link: link.into() },
986 attributes: ObjectAttributes {
987 creation_time,
988 modification_time,
989 project_id,
990 ..Default::default()
991 },
992 }
993 }
994 pub fn inline_extended_attribute(value: impl Into<Vec<u8>>) -> ObjectValue {
995 ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(value.into()))
996 }
997 pub fn extended_attribute(attribute_id: AttributeId) -> ObjectValue {
998 ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(attribute_id))
999 }
1000}
1001
1002pub type ObjectItem = ObjectItemV55;
1003
1004pub type ObjectItemV54 = LegacyItem<ObjectKeyV54, ObjectValueV54>;
1005pub type ObjectItemV55 = Item<ObjectKeyV54, ObjectValueV54>;
1006
1007impl From<ObjectItemV54> for ObjectItemV55 {
1008 fn from(item: ObjectItemV54) -> Self {
1009 Self { key: item.key, value: item.value }
1010 }
1011}
1012
1013pub type ObjectItemV50 = LegacyItem<ObjectKeyV43, ObjectValueV50>;
1014
1015impl ObjectItem {
1016 pub fn is_tombstone(&self) -> bool {
1017 matches!(
1018 self,
1019 Item {
1020 key: ObjectKey { data: ObjectKeyData::Object, .. },
1021 value: ObjectValue::None,
1022 ..
1023 }
1024 )
1025 }
1026}
1027
1028impl<'a> From<ItemRef<'a, ObjectKey, ObjectValue>>
1030 for Option<(u64, AttributeId, &'a Extent, &'a ExtentValue)>
1031{
1032 fn from(item: ItemRef<'a, ObjectKey, ObjectValue>) -> Self {
1033 match item {
1034 ItemRef {
1035 key:
1036 ObjectKey {
1037 object_id,
1038 data:
1039 ObjectKeyData::Attribute(
1040 attribute_id, AttributeKey::Extent(extent_key),
1042 ),
1043 },
1044 value: ObjectValue::Extent(extent_value),
1045 ..
1046 } => Some((*object_id, *attribute_id, extent_key, extent_value)),
1047 _ => None,
1048 }
1049 }
1050}
1051
1052pub type FxfsKey = FxfsKeyV49;
1053pub type FxfsKeyV49 = fxfs_crypto::FxfsKey;
1054
1055#[derive(
1056 Clone,
1057 Copy,
1058 PartialEq,
1059 Eq,
1060 PartialOrd,
1061 Ord,
1062 Debug,
1063 Serialize,
1064 Deserialize,
1065 Hash,
1066 SerializeKey,
1067 TypeFingerprint,
1068)]
1069#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
1070#[repr(transparent)]
1071pub struct AttributeId(pub u64);
1072
1073impl AttributeId {
1074 pub const DATA: Self = Self(0);
1076
1077 pub const BLOB_METADATA: Self = Self(3);
1080
1081 pub const BLOB_MERKLE: Self = Self(1);
1084
1085 pub const FSVERITY_MERKLE: Self = Self(2);
1088
1089 pub const XATTR_RANGE_START: Self = Self(64);
1096 pub const XATTR_RANGE_END: Self = Self(512);
1097
1098 pub const SORTED_START: Self = Self(0);
1102
1103 #[cfg(test)]
1105 pub const TEST_ID: Self = Self(u64::MAX - 1000);
1106
1107 pub const fn raw(self) -> u64 {
1108 self.0
1109 }
1110
1111 pub const fn next(self) -> Self {
1113 Self(self.0 + 1)
1114 }
1115
1116 pub const fn is_xattr(self) -> bool {
1118 self.0 >= Self::XATTR_RANGE_START.0 && self.0 < Self::XATTR_RANGE_END.0
1119 }
1120}
1121
1122impl log::kv::ToValue for AttributeId {
1123 fn to_value(&self) -> log::kv::Value<'_> {
1124 log::kv::Value::from(self.0)
1125 }
1126}
1127
1128impl std::fmt::Display for AttributeId {
1129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1130 std::fmt::Display::fmt(&self.0, f)
1131 }
1132}
1133
1134#[cfg(test)]
1135mod tests {
1136 use super::{AttributeId, ObjectKey, ObjectKeyV54, TimestampV49};
1137 use crate::lsm_tree::types::{FuzzyHash as _, LayerKey};
1138 use std::ops::Add;
1139 use std::time::{Duration, SystemTime, UNIX_EPOCH};
1140
1141 #[test]
1146 fn test_hash_stability() {
1147 assert_eq!(
1151 &ObjectKeyV54::object(100).fuzzy_hash().collect::<Vec<_>>()[..],
1152 &[11885326717398844384]
1153 );
1154 assert_eq!(
1155 &ObjectKeyV54::extent(1, AttributeId::DATA, 0..2 * 1024 * 1024)
1156 .fuzzy_hash()
1157 .collect::<Vec<_>>()[..],
1158 &[11090579907097549012, 2814892992701560424]
1159 );
1160 }
1161
1162 #[test]
1163 fn test_next_key() {
1164 assert_eq!(
1165 ObjectKey::extent(1, AttributeId::TEST_ID, 25..100).next_key().unwrap(),
1166 ObjectKey::extent(1, AttributeId::TEST_ID, 0..101)
1167 );
1168 assert_eq!(ObjectKey::object(100).next_key(), None);
1169 }
1170
1171 #[test]
1172 fn test_range_key() {
1173 const ATTR_ID: AttributeId = AttributeId::TEST_ID;
1174 assert!(ObjectKey::extent(1, ATTR_ID, 0..2 * 1024 * 1024).is_range_key());
1177 assert!(!ObjectKey::object(100).is_range_key());
1178
1179 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(1)), true);
1180 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(2)), false);
1181 assert_eq!(ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::object(1)), false);
1182 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..100)), false);
1183 assert_eq!(
1184 ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(2, ATTR_ID, 0..100)),
1185 false
1186 );
1187 assert_eq!(
1188 ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(
1189 1,
1190 ATTR_ID.next(),
1191 0..100
1192 )),
1193 false
1194 );
1195 assert_eq!(
1196 ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..100)),
1197 true
1198 );
1199
1200 assert_eq!(
1201 ObjectKey::extent(1, ATTR_ID, 0..50).overlaps(&ObjectKey::extent(1, ATTR_ID, 49..100)),
1202 true
1203 );
1204 assert_eq!(
1205 ObjectKey::extent(1, ATTR_ID, 49..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..50)),
1206 true
1207 );
1208
1209 assert_eq!(
1210 ObjectKey::extent(1, ATTR_ID, 0..50).overlaps(&ObjectKey::extent(1, ATTR_ID, 50..100)),
1211 false
1212 );
1213 assert_eq!(
1214 ObjectKey::extent(1, ATTR_ID, 50..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..50)),
1215 false
1216 );
1217 }
1218
1219 #[test]
1220 fn test_timestamp() {
1221 fn compare_time(std_time: Duration) {
1222 let ts_time: TimestampV49 = std_time.into();
1223 assert_eq!(<TimestampV49 as Into<Duration>>::into(ts_time), std_time);
1224 assert_eq!(ts_time.subsec_nanos(), std_time.subsec_nanos());
1225 assert_eq!(ts_time.as_secs(), std_time.as_secs());
1226 assert_eq!(ts_time.as_nanos() as u128, std_time.as_nanos());
1227 }
1228 compare_time(Duration::from_nanos(0));
1229 compare_time(Duration::from_nanos(u64::MAX));
1230 compare_time(SystemTime::now().duration_since(UNIX_EPOCH).unwrap());
1231
1232 let ts: TimestampV49 = Duration::from_secs(u64::MAX - 1).into();
1233 assert_eq!(ts.nanos, u64::MAX);
1234
1235 let ts: TimestampV49 = (Duration::from_nanos(u64::MAX).add(Duration::from_nanos(1))).into();
1236 assert_eq!(ts.nanos, u64::MAX);
1237 }
1238}