loonfs_core/namespace/
status.rs1use crate::checkpoint::load_namespace_manifest_envelope;
5use crate::error::MetadataProjectionLoadError;
6use crate::error::{CoreError, Result};
7use crate::namespace::basis::{read_head_and_metadata_basis, resolve_retention_floor_seq};
8use crate::wal::{count_visible_wal_tail_segments, WalChainLoadRequest};
9use loonfs_api::wire::control::NamespaceState;
10use loonfs_api::{ChangeSeq, ManifestId, NamespaceId};
11use loonfs_objectstore::ObjectStore;
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16pub struct NamespaceHeadSummary {
17 pub namespace_id: NamespaceId,
18 pub head_seq: ChangeSeq,
19 pub current_manifest_id: Option<ManifestId>,
23 pub wal_tail_segments: u64,
31 pub retention_floor_seq: ChangeSeq,
32}
33
34pub async fn load_namespace_head_summary<S: ObjectStore + ?Sized>(
35 store: &S,
36 expected_namespace_id: &NamespaceId,
37) -> Result<NamespaceHeadSummary> {
38 let loaded = read_head_and_metadata_basis(store, expected_namespace_id)
39 .await
40 .map_err(|error| {
41 CoreError::MetadataProjection(MetadataProjectionLoadError::LoadHead(error))
42 })?;
43 let head = loaded.head.envelope.state;
44 if head.state == NamespaceState::Deleted {
45 return Err(CoreError::NamespaceDeleted {
46 namespace_id: expected_namespace_id.clone(),
47 });
48 }
49 let (current_manifest_id, basis_head_seq) = match loaded.basis.manifest() {
52 Some(basis) => {
53 let manifest = load_namespace_manifest_envelope(
54 store,
55 &basis.owner_namespace_id,
56 &basis.manifest_object_id,
57 )
58 .await
59 .map_err(|error| {
60 CoreError::MetadataProjection(MetadataProjectionLoadError::ManifestLoad(error))
61 })?;
62 let own_manifest_id = loaded
63 .basis
64 .is_owned_by(expected_namespace_id)
65 .then_some(basis.manifest_id);
66 (own_manifest_id, manifest.payload.head_seq)
67 }
68 None => (None, ChangeSeq(0)),
69 };
70 let wal_tail_segments = count_visible_wal_tail_segments(
71 store,
72 WalChainLoadRequest {
73 namespace_id: expected_namespace_id,
74 chain_base_seq: basis_head_seq,
75 head_seq: head.seq,
76 visible_tip: head.visible_wal_tip.clone(),
77 stop_after_seq: None,
78 recent_segments: &head.recent_segments,
79 },
80 )
81 .await
82 .map_err(|error| {
83 CoreError::MetadataProjection(MetadataProjectionLoadError::WalChainLoad(error))
84 })?;
85 let retention_floor_seq = resolve_retention_floor_seq(store, &head)
86 .await
87 .map_err(|error| {
88 CoreError::MetadataProjection(MetadataProjectionLoadError::LoadHead(error))
89 })?;
90 Ok(NamespaceHeadSummary {
91 namespace_id: head.namespace_id,
92 head_seq: head.seq,
93 current_manifest_id,
94 wal_tail_segments,
95 retention_floor_seq,
96 })
97}
98
99pub async fn load_deleted_namespace_head_summary<S: ObjectStore + ?Sized>(
107 store: &S,
108 expected_namespace_id: &NamespaceId,
109) -> Result<NamespaceHeadSummary> {
110 let head = crate::namespace::control::read_head_object(store, expected_namespace_id)
111 .await
112 .map_err(|error| {
113 CoreError::MetadataProjection(MetadataProjectionLoadError::LoadHead(error))
114 })?
115 .envelope
116 .state;
117 if head.state != NamespaceState::Deleted {
118 return Err(CoreError::Internal(format!(
119 "namespace `{expected_namespace_id}` is not deleted; the live head summary serves it"
120 )));
121 }
122 let retention_floor_seq = resolve_retention_floor_seq(store, &head)
123 .await
124 .map_err(|error| {
125 CoreError::MetadataProjection(MetadataProjectionLoadError::LoadHead(error))
126 })?;
127 Ok(NamespaceHeadSummary {
128 namespace_id: head.namespace_id,
129 head_seq: head.seq,
130 current_manifest_id: None,
131 wal_tail_segments: 0,
132 retention_floor_seq,
133 })
134}