Complete nested prepared-lower reclaim ordering
This commit is contained in:
parent
0dfd7767b5
commit
898271c430
2 changed files with 74 additions and 4 deletions
|
|
@ -234,8 +234,8 @@ impl PreparedLowerStore {
|
||||||
.context("canonical replacement exists without quarantined old artifact")?;
|
.context("canonical replacement exists without quarantined old artifact")?;
|
||||||
require_identity(&quarantined, reclaiming.device, reclaiming.inode)?;
|
require_identity(&quarantined, reclaiming.device, reclaiming.inode)?;
|
||||||
let replacement = self
|
let replacement = self
|
||||||
.available_artifact(reclaiming.prepared_artifact_id)?
|
.catalog_artifact(reclaiming.prepared_artifact_id)?
|
||||||
.context("canonical replacement exists without available ownership")?;
|
.context("canonical replacement exists without catalog ownership")?;
|
||||||
require_identity(&canonical, replacement.device, replacement.inode)?;
|
require_identity(&canonical, replacement.device, replacement.inode)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -252,8 +252,8 @@ impl PreparedLowerStore {
|
||||||
row: CatalogRow::PreparedArtifact,
|
row: CatalogRow::PreparedArtifact,
|
||||||
}) => {
|
}) => {
|
||||||
let replacement = self
|
let replacement = self
|
||||||
.available_artifact(reclaiming.prepared_artifact_id)?
|
.catalog_artifact(reclaiming.prepared_artifact_id)?
|
||||||
.context("reclaim row changed without an available replacement")?;
|
.context("reclaim row changed without an owned replacement")?;
|
||||||
self.require_artifact_identity(&replacement)?;
|
self.require_artifact_identity(&replacement)?;
|
||||||
Ok(ReclaimOutcome::ReplacementPreserved)
|
Ok(ReclaimOutcome::ReplacementPreserved)
|
||||||
}
|
}
|
||||||
|
|
@ -334,6 +334,15 @@ impl PreparedLowerStore {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn catalog_artifact(&self, id: PreparedArtifactId) -> Result<Option<PreparedArtifact>> {
|
||||||
|
Ok(self
|
||||||
|
.catalog
|
||||||
|
.snapshot()?
|
||||||
|
.prepared_artifacts
|
||||||
|
.into_iter()
|
||||||
|
.find(|artifact| artifact.prepared_artifact_id == id))
|
||||||
|
}
|
||||||
|
|
||||||
fn require_artifact_identity(&self, artifact: &PreparedArtifact) -> Result<()> {
|
fn require_artifact_identity(&self, artifact: &PreparedArtifact) -> Result<()> {
|
||||||
let path = PathBuf::from(std::ffi::OsString::from_vec(
|
let path = PathBuf::from(std::ffi::OsString::from_vec(
|
||||||
artifact.path.as_bytes().to_vec(),
|
artifact.path.as_bytes().to_vec(),
|
||||||
|
|
|
||||||
|
|
@ -719,6 +719,67 @@ fn replacement_winning_before_reclaimer_resumes_still_cleans_old_quarantine() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replacement_reclaim_start_does_not_orphan_prior_quarantine() {
|
||||||
|
let fixture = Fixture::new();
|
||||||
|
let bytes = layer(&[Entry {
|
||||||
|
path: "payload",
|
||||||
|
kind: EntryType::Regular,
|
||||||
|
data: b"same",
|
||||||
|
target: None,
|
||||||
|
mode: 0o644,
|
||||||
|
}]);
|
||||||
|
let first_request = fixture.request(55, &[(bytes, OCI_TAR)]);
|
||||||
|
let first = fixture.store.prepare(&first_request).unwrap();
|
||||||
|
let first_reclaiming = fixture.catalog.begin_reclaim(&first).unwrap();
|
||||||
|
let replacement_request = PrepareRequest {
|
||||||
|
operation_id: PrepareOperationId::new([56; 32]),
|
||||||
|
..first_request
|
||||||
|
};
|
||||||
|
let replacement = fixture.store.prepare(&replacement_request).unwrap();
|
||||||
|
let replacement_reclaiming = fixture.catalog.begin_reclaim(&replacement).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
fixture.store.resume_reclaim(&first_reclaiming).unwrap(),
|
||||||
|
ReclaimOutcome::ReplacementPreserved
|
||||||
|
);
|
||||||
|
assert!(fixture.artifact_root(&replacement).is_dir());
|
||||||
|
assert!(
|
||||||
|
fixture
|
||||||
|
.root
|
||||||
|
.join("quarantine")
|
||||||
|
.read_dir()
|
||||||
|
.unwrap()
|
||||||
|
.next()
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fixture
|
||||||
|
.store
|
||||||
|
.resume_reclaim(&replacement_reclaiming)
|
||||||
|
.unwrap(),
|
||||||
|
ReclaimOutcome::Removed
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
fixture
|
||||||
|
.catalog
|
||||||
|
.snapshot()
|
||||||
|
.unwrap()
|
||||||
|
.prepared_artifacts
|
||||||
|
.is_empty()
|
||||||
|
);
|
||||||
|
assert!(!fixture.artifact_root(&replacement).exists());
|
||||||
|
assert!(
|
||||||
|
fixture
|
||||||
|
.root
|
||||||
|
.join("quarantine")
|
||||||
|
.read_dir()
|
||||||
|
.unwrap()
|
||||||
|
.next()
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reclaim_refuses_preexisting_foreign_quarantine_path() {
|
fn reclaim_refuses_preexisting_foreign_quarantine_path() {
|
||||||
let fixture = Fixture::new();
|
let fixture = Fixture::new();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue