Skip to main content

fxfs/serialized_types/
types.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::blob_metadata::{BlobMetadata, BlobMetadataV53};
6use crate::lsm_tree::{
7    PersistentLayerHeader, PersistentLayerHeaderV39, PersistentLayerInfo, PersistentLayerInfoV39,
8};
9use crate::object_store::allocator::{
10    AllocatorInfo, AllocatorInfoV32, AllocatorKey, AllocatorKeyV32, AllocatorValue,
11    AllocatorValueV32,
12};
13use crate::object_store::journal::super_block::{
14    SuperBlockHeader, SuperBlockHeaderV32, SuperBlockHeaderV61, SuperBlockRecord,
15    SuperBlockRecordV56, SuperBlockRecordV59, SuperBlockRecordV62,
16};
17use crate::object_store::journal::{
18    JournalRecord, JournalRecordV56, JournalRecordV57, JournalRecordV59, JournalRecordV60,
19    JournalRecordV61, JournalRecordV62,
20};
21use crate::object_store::object_record::{
22    FsverityMetadata, FsverityMetadataV50, ObjectKey, ObjectKeyV54, ObjectValue, ObjectValueV56,
23    ObjectValueV59, ObjectValueV62,
24};
25use crate::object_store::transaction::{
26    Mutation, MutationV56, MutationV57, MutationV59, MutationV61, MutationV62,
27};
28use crate::object_store::{
29    EncryptedMutations, EncryptedMutationsV49, EncryptedTransaction, EncryptedTransactionV57,
30    EncryptedTransactionV59, EncryptedTransactionV61, EncryptedTransactionV62, StoreInfo,
31    StoreInfoV52,
32};
33use crate::serialized_types::{Version, Versioned, VersionedLatest, versioned_type};
34use std::collections::BTreeMap;
35
36/// The latest version of on-disk filesystem format.
37///
38/// If all layer files are compacted the the journal flushed, and super-block
39/// both rewritten, all versions should match this value.
40///
41/// If making a breaking change, please see EARLIEST_SUPPORTED_VERSION (below).
42///
43/// IMPORTANT: When changing this (major or minor), update the list of possible versions at
44/// https://cs.opensource.google/fuchsia/fuchsia/+/main:third_party/cobalt_config/fuchsia/local_storage/versions.txt.
45pub const LATEST_VERSION: Version = Version { major: 62, minor: 0 };
46
47/// The last version of the filesystem where keys in layer files used the old serialization format
48/// (prior to SerializeKey and delta encoding).
49pub const OLD_KEY_SERIALIZATION_VERSION: Version = Version { major: 57, minor: 0 };
50
51/// The earliest supported version of the on-disk filesystem format.
52///
53/// When a breaking change is made:
54/// 1) LATEST_VERSION should have it's major component increased (see above).
55/// 2) EARLIEST_SUPPORTED_VERSION should be set to the new LATEST_VERSION.
56/// 3) The SuperBlockHeader version (below) should also be set to the new LATEST_VERSION.
57///
58/// Also check the constant version numbers above for any code cleanup that can happen.
59pub const EARLIEST_SUPPORTED_VERSION: Version = Version { major: 56, minor: 0 };
60
61// From this version forward, the journal encryption uses AES-256-XTS instead of Chacha20, as well
62// as chunking the mutations together for a transaction.
63pub const AES_JOURNAL_ENCRYPTION_VERSION: Version = Version { major: 57, minor: 0 };
64
65/// This trait prevents types from showing up in `versioned_types` multiple times. `versioned_types`
66/// implements this trait for every type passed to it. If a type is listed multiple times then this
67/// trait will be implemented for the type multiple times which will fail to compile.
68#[allow(dead_code)]
69trait UniqueVersionForType {}
70
71trait HasVersion {
72    const VERSION: u32;
73}
74
75macro_rules! versioned_types {
76    ( $( $name:ident { $latest:literal.. => $latest_type:ty $(, $major:literal.. => $type:ty )* $(,)? } )+ ) => {
77        $(
78            static_assertions::assert_type_eq_all!($name, $latest_type);
79
80            versioned_type! {
81                $latest.. => $latest_type,
82                $( $major.. => $type ),*
83            }
84
85            impl UniqueVersionForType for $latest_type {}
86            $( impl UniqueVersionForType for $type {} )*
87
88            impl HasVersion for $latest_type {
89                const VERSION: u32 = $latest;
90            }
91
92        )+
93
94        pub fn get_type_fingerprints(version: Version) -> BTreeMap<String, String> {
95            let mut map = BTreeMap::new();
96            $(
97                let fingerprint = {
98                    let mut fp = None;
99                    const FINGERPRINTS: &[(u32, fn() -> String)] = &[
100                        ($latest, <$latest_type as fprint::TypeFingerprint>::fingerprint),
101                        $( ($major, <$type as fprint::TypeFingerprint>::fingerprint) ),*
102                    ];
103                    for (major, type_fp) in FINGERPRINTS {
104                        if version.major >= *major {
105                            fp = Some(type_fp());
106                            break;
107                        }
108                    }
109                    fp
110                };
111                if let Some(fp) = fingerprint {
112                    map.insert(stringify!($name).to_string(), fp.to_string());
113                }
114            )+
115            map
116        }
117    };
118}
119
120versioned_types! {
121    AllocatorInfo {
122        32.. => AllocatorInfoV32,
123    }
124    AllocatorKey {
125        32.. => AllocatorKeyV32,
126    }
127    AllocatorValue {
128        32.. => AllocatorValueV32,
129    }
130    EncryptedMutations {
131        49.. => EncryptedMutationsV49,
132    }
133    EncryptedTransaction {
134        62.. => EncryptedTransactionV62,
135        61.. => EncryptedTransactionV61,
136        59.. => EncryptedTransactionV59,
137        57.. => EncryptedTransactionV57,
138    }
139    FsverityMetadata {
140        50.. => FsverityMetadataV50,
141    }
142    JournalRecord {
143        62.. => JournalRecordV62,
144        61.. => JournalRecordV61,
145        60.. => JournalRecordV60,
146        59.. => JournalRecordV59,
147        57.. => JournalRecordV57,
148        56.. => JournalRecordV56,
149    }
150    Mutation {
151        62.. => MutationV62,
152        61.. => MutationV61,
153        59.. => MutationV59,
154        57.. => MutationV57,
155        56.. => MutationV56,
156    }
157    ObjectKey {
158        54.. => ObjectKeyV54,
159    }
160    ObjectValue {
161        62.. => ObjectValueV62,
162        59.. => ObjectValueV59,
163        56.. => ObjectValueV56,
164    }
165    PersistentLayerHeader {
166        39.. => PersistentLayerHeaderV39,
167    }
168    PersistentLayerInfo {
169        39.. => PersistentLayerInfoV39,
170    }
171    StoreInfo {
172        52.. => StoreInfoV52,
173    }
174    SuperBlockHeader {
175        61.. => SuperBlockHeaderV61,
176        32.. => SuperBlockHeaderV32,
177    }
178    SuperBlockRecord {
179        62.. => SuperBlockRecordV62,
180        59.. => SuperBlockRecordV59,
181        56.. => SuperBlockRecordV56,
182    }
183    BlobMetadata {
184        53.. => BlobMetadataV53,
185    }
186}
187
188// EncryptedTransaction is actually inside the Mutation type, but obscured by a layer of
189// encryption. This ensures that when the EncryptedTransaction type is incremented, so is the
190// Mutation and thus any types above that.
191static_assertions::const_assert!(
192    <EncryptedTransaction as HasVersion>::VERSION <= <Mutation as HasVersion>::VERSION
193);
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    #[fuchsia::test]
200    fn test_get_type_fingerprints() {
201        let latest = get_type_fingerprints(LATEST_VERSION);
202        assert!(!latest.is_empty());
203        assert!(latest.contains_key("JournalRecord"));
204        assert!(latest.contains_key("Mutation"));
205        assert!(latest.contains_key("ObjectKey"));
206
207        let earliest = get_type_fingerprints(EARLIEST_SUPPORTED_VERSION);
208        assert!(!earliest.is_empty());
209        assert!(earliest.contains_key("JournalRecord"));
210        assert!(!earliest.contains_key("EncryptedTransaction"));
211
212        let too_old = get_type_fingerprints(Version { major: 1, minor: 0 });
213        assert!(too_old.is_empty());
214    }
215}