loonfs_core/namespace/
basis.rs1use crate::error::CoreError;
18use crate::namespace::control::{
19 read_head_and_metadata_root_if_present, read_wal_floor_object, ControlObjectLoadError,
20 LoadedHeadObject,
21};
22use loonfs_api::wire::control::HeadState;
23use loonfs_api::{manifest_object_id_manifest_id, ChangeSeq, ManifestId, ManifestObjectId};
24use loonfs_api::{NamespaceId, ROOT_INODE_ID};
25use loonfs_objectstore::ObjectStore;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum MetadataBasis {
30 Genesis,
34 Manifest(BasisManifest),
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct BasisManifest {
42 pub owner_namespace_id: NamespaceId,
44 pub manifest_id: ManifestId,
46 pub manifest_object_id: ManifestObjectId,
47 pub manifest_payload_checksum: String,
49}
50
51impl MetadataBasis {
52 pub fn manifest(&self) -> Option<&BasisManifest> {
53 match self {
54 MetadataBasis::Genesis => None,
55 MetadataBasis::Manifest(manifest) => Some(manifest),
56 }
57 }
58
59 pub fn manifest_id(&self) -> ManifestId {
62 match self {
63 MetadataBasis::Genesis => ManifestId(0),
64 MetadataBasis::Manifest(manifest) => manifest.manifest_id,
65 }
66 }
67
68 pub fn is_owned_by(&self, namespace_id: &NamespaceId) -> bool {
71 self.manifest()
72 .is_some_and(|manifest| manifest.owner_namespace_id == *namespace_id)
73 }
74}
75
76pub(crate) struct LoadedNamespaceBasis {
78 pub(crate) head: LoadedHeadObject,
79 pub(crate) basis: MetadataBasis,
80}
81
82pub(crate) async fn read_head_and_metadata_basis<S: ObjectStore + ?Sized>(
84 store: &S,
85 namespace_id: &NamespaceId,
86) -> Result<LoadedNamespaceBasis, ControlObjectLoadError> {
87 let (head, root) = read_head_and_metadata_root_if_present(store, namespace_id).await?;
88 let basis = match root {
89 Some(root) => MetadataBasis::Manifest(BasisManifest {
90 owner_namespace_id: namespace_id.clone(),
91 manifest_id: root.envelope.state.manifest_id,
92 manifest_object_id: root.envelope.state.manifest_object_id,
93 manifest_payload_checksum: root.envelope.state.manifest_payload_checksum,
94 }),
95 None => metadata_basis_without_root(&head.envelope.state)?,
96 };
97 Ok(LoadedNamespaceBasis { head, basis })
98}
99
100pub(crate) fn metadata_basis_without_root(
104 head: &HeadState,
105) -> Result<MetadataBasis, ControlObjectLoadError> {
106 let Some(fork_basis) = &head.fork_basis else {
107 return Ok(MetadataBasis::Genesis);
108 };
109 let manifest_id = manifest_object_id_manifest_id(fork_basis.source_manifest_object_id.as_str())
110 .ok_or_else(|| ControlObjectLoadError::Codec {
111 object_key: loonfs_objectstore::keys::wal_head(head.namespace_id.as_str()),
112 message: format!(
113 "fork basis manifest object id `{}` does not encode a manifest id",
114 fork_basis.source_manifest_object_id
115 ),
116 })?;
117 Ok(MetadataBasis::Manifest(BasisManifest {
118 owner_namespace_id: fork_basis.source_namespace_id.clone(),
119 manifest_id,
120 manifest_object_id: fork_basis.source_manifest_object_id.clone(),
121 manifest_payload_checksum: fork_basis.source_manifest_checksum.clone(),
122 }))
123}
124
125pub(crate) fn genesis_next_inode_id() -> loonfs_api::InodeId {
128 loonfs_api::InodeId(ROOT_INODE_ID.0 + 1)
129}
130
131pub(crate) fn namespace_birth_seq(head: &HeadState) -> ChangeSeq {
134 head.fork_basis
135 .as_ref()
136 .map_or(ChangeSeq(0), |fork_basis| fork_basis.fork_seq)
137}
138
139pub(crate) async fn resolve_retention_floor_seq<S: ObjectStore + ?Sized>(
146 store: &S,
147 head: &HeadState,
148) -> Result<ChangeSeq, ControlObjectLoadError> {
149 match read_wal_floor_object(store, &head.namespace_id).await {
150 Ok(loaded) => Ok(loaded.envelope.state.floor_seq),
151 Err(ControlObjectLoadError::MissingObject { .. }) => Ok(namespace_birth_seq(head)),
152 Err(error) => Err(error),
153 }
154}
155
156pub(crate) fn advanced_floor_without_root(
162 namespace_id: &NamespaceId,
163 floor_seq: ChangeSeq,
164) -> CoreError {
165 CoreError::NamespaceCorrupt(format!(
166 "namespace `{namespace_id}` has no materialized metadata root but its retention floor \
167 stands at `{floor_seq}`; the root object is missing"
168 ))
169}