Implement exact bootstrap recovery and artifact GC

This commit is contained in:
ms2k 2026-07-17 05:38:43 +09:00
commit d25942596f

View file

@ -495,6 +495,9 @@ impl Participant {
| ParticipantState::Committed,
ParticipantState::ReleaseIntent,
) => validate_participant_release(self.ownership.as_ref(), next.ownership.as_ref()),
(ParticipantState::ReleaseIntent, ParticipantState::ReleaseIntent) => {
validate_participant_release(self.ownership.as_ref(), next.ownership.as_ref())
}
(old_state, new_state)
if old_state == new_state
&& matches!(
@ -502,7 +505,6 @@ impl Participant {
ParticipantState::LeaseHeld
| ParticipantState::Prepared
| ParticipantState::Committed
| ParticipantState::ReleaseIntent
| ParticipantState::Clean
)
&& self.ownership == next.ownership =>
@ -979,6 +981,15 @@ pub struct PreparedLowerOwnership {
pub path: Option<HostPath>,
pub device: Option<DeviceId>,
pub inode: Option<InodeId>,
pub released_state_anchor: Option<StateAnchorReleaseEvidence>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct StateAnchorReleaseEvidence {
pub daemon: PidfsProcessIdentityV1,
pub user_namespace: NamespaceIdentity,
pub mount_namespace: NamespaceIdentity,
pub mount: MountIdentity,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
@ -1043,6 +1054,7 @@ impl PreparedLowerOwnership {
path: None,
device: None,
inode: None,
released_state_anchor: None,
}
}
@ -1053,6 +1065,7 @@ impl PreparedLowerOwnership {
&& self.path.is_none()
&& self.device.is_none()
&& self.inode.is_none()
&& self.released_state_anchor.is_none()
}
fn is_lease_held(&self) -> bool {
@ -1062,6 +1075,7 @@ impl PreparedLowerOwnership {
&& self.path.is_some()
&& self.device.is_some()
&& self.inode.is_some()
&& self.released_state_anchor.is_none()
}
fn validate_progress_to(&self, next: &Self) -> Result<(), RecordTransitionError> {
@ -1073,7 +1087,11 @@ impl PreparedLowerOwnership {
validate_prepared_lower_lease_progress(self.lease_state, next.lease_state)?;
validate_option_progress(self.path.as_ref(), next.path.as_ref())?;
validate_option_progress(self.device.as_ref(), next.device.as_ref())?;
validate_option_progress(self.inode.as_ref(), next.inode.as_ref())
validate_option_progress(self.inode.as_ref(), next.inode.as_ref())?;
validate_option_progress(
self.released_state_anchor.as_ref(),
next.released_state_anchor.as_ref(),
)
}
fn validate_release_to(&self, next: &Self) -> Result<(), RecordTransitionError> {
@ -1085,6 +1103,15 @@ impl PreparedLowerOwnership {
{
return Err(RecordTransitionError::EvidenceChanged);
}
let release_evidence_valid = match self.lease_state {
Some(ParticipantState::ReleaseIntent) => {
self.released_state_anchor == next.released_state_anchor
}
_ => next.released_state_anchor.is_some() || self.released_state_anchor.is_none(),
};
if !release_evidence_valid {
return Err(RecordTransitionError::EvidenceChanged);
}
match (self.lease_state, next.lease_state) {
(None, None)
| (Some(ParticipantState::ReleaseIntent), Some(ParticipantState::ReleaseIntent)) => {