Implement exact bootstrap recovery and artifact GC
This commit is contained in:
parent
0f4845d4f8
commit
d25942596f
3 changed files with 1631 additions and 48 deletions
|
|
@ -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)) => {
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ fn prepared_ownership() -> PreparedLowerOwnership {
|
|||
path: Some(HostPath::new(vec![b'/', 0xff])),
|
||||
device: Some(DeviceId::new(27)),
|
||||
inode: Some(InodeId::new(28)),
|
||||
released_state_anchor: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -514,6 +514,51 @@ fn prepared_lower_release_changes_only_the_lease_phase() {
|
|||
.unwrap();
|
||||
assert_eq!(active.validate_transition_to(&release), Ok(()));
|
||||
|
||||
let ParticipantOwnership::PreparedLower(mut with_anchor_evidence) =
|
||||
release_ownership(ParticipantRole::PreparedLower)
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
with_anchor_evidence.released_state_anchor = Some(StateAnchorReleaseEvidence {
|
||||
daemon: process(120),
|
||||
user_namespace: namespace(),
|
||||
mount_namespace: NamespaceIdentity {
|
||||
device: DeviceId::new(121),
|
||||
inode: InodeId::new(122),
|
||||
},
|
||||
mount: mount(),
|
||||
});
|
||||
let release_with_anchor_evidence = Participant::snapshot(
|
||||
generation_id(),
|
||||
ParticipantRole::PreparedLower,
|
||||
ParticipantState::ReleaseIntent,
|
||||
Some(ParticipantOwnership::PreparedLower(
|
||||
with_anchor_evidence.clone(),
|
||||
)),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
active.validate_transition_to(&release_with_anchor_evidence),
|
||||
Ok(())
|
||||
);
|
||||
with_anchor_evidence
|
||||
.released_state_anchor
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.mount
|
||||
.mount_id = MountId::new(123);
|
||||
let changed_release_evidence = Participant::snapshot(
|
||||
generation_id(),
|
||||
ParticipantRole::PreparedLower,
|
||||
ParticipantState::ReleaseIntent,
|
||||
Some(ParticipantOwnership::PreparedLower(with_anchor_evidence)),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
release_with_anchor_evidence.validate_transition_to(&changed_release_evidence),
|
||||
Err(RecordTransitionError::EvidenceChanged)
|
||||
);
|
||||
|
||||
let ParticipantOwnership::PreparedLower(mut changed) =
|
||||
release_ownership(ParticipantRole::PreparedLower)
|
||||
else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue