perf(delivery): stream verified restore file pages
This commit is contained in:
@@ -335,6 +335,12 @@ impl Roots {
|
||||
retain,
|
||||
&mut buffer,
|
||||
)?;
|
||||
// These historical destination bytes have already been synchronized
|
||||
// and fully verified. Keep their clean pages out of this finite
|
||||
// restore working set; all descriptor/path witnesses still follow.
|
||||
remaining(deadline)?;
|
||||
rustix::fs::fadvise(&input, 0, None, rustix::fs::Advice::DontNeed)
|
||||
.map_err(|_| Error::Filesystem)?;
|
||||
if stamp(&input.metadata().map_err(|_| Error::Filesystem)?)? != pending.witness
|
||||
|| anchor.observed(name)? != pending.witness
|
||||
{
|
||||
|
||||
@@ -487,6 +487,46 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn streamed_verified_pages_preserve_repeated_large_bytes_and_all_witnesses() {
|
||||
let fixture = files::Fixture::new();
|
||||
let roots = Arc::new(fixture.roots());
|
||||
let data = vec![b'v'; 8 * 1024 * 1024];
|
||||
let hash = format!("{:x}", Sha256::digest(&data));
|
||||
let source = fixture.source().join(&hash);
|
||||
fs::write(&source, &data).unwrap();
|
||||
fs::set_permissions(&source, fs::Permissions::from_mode(0o600)).unwrap();
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
let owner = fs::metadata(&source).unwrap();
|
||||
let rows = (0..3)
|
||||
.map(|index| restore_io::RestoreFile {
|
||||
path: format!("artifacts/stream-{index}"),
|
||||
uid: owner.uid(),
|
||||
gid: owner.gid(),
|
||||
mode: 0o644,
|
||||
bytes: data.len() as u64,
|
||||
sha256: hash.clone(),
|
||||
})
|
||||
.collect();
|
||||
let pool = Pool::new(Arc::clone(&roots)).unwrap_or_else(|_| panic!("pool"));
|
||||
let verified = pool
|
||||
.materialize(rows, &roots, now().unwrap() + 10_000_000_000)
|
||||
.unwrap_or_else(|_| panic!("streamed verified copies"));
|
||||
assert_eq!(verified.len(), 3);
|
||||
for row in &verified {
|
||||
roots
|
||||
.final_file(row)
|
||||
.unwrap_or_else(|_| panic!("final witness"));
|
||||
let name = row.row.path.strip_prefix("artifacts/").unwrap();
|
||||
assert_eq!(fs::read(fixture.target().join(name)).unwrap(), data);
|
||||
roots
|
||||
.final_file(row)
|
||||
.unwrap_or_else(|_| panic!("unchanged witness"));
|
||||
}
|
||||
drop(pool);
|
||||
roots.unchanged().unwrap_or_else(|_| panic!("root anchors"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn request_line_requires_finite_complete_frame() {
|
||||
assert!(matches!(
|
||||
|
||||
@@ -515,6 +515,11 @@ The native restore helper keeps two joined threads and partitions each fixed bat
|
||||
into contiguous groups that minimize the heavier byte count. Ties prefer balanced
|
||||
file counts. Copy order, synchronization, complete byte readback and final
|
||||
nine-field witnesses are preserved; no extra worker or batch capacity is added.
|
||||
After synchronization and complete byte verification, the native helper asks the
|
||||
kernel to release clean cached pages for that restored file. Descriptor and path
|
||||
witnesses are still checked afterwards. This per-file streaming hint avoids
|
||||
retaining historical file contents in the fixed restore memory budget; it does
|
||||
not change file bytes, durability, limits or the live filesystem checks.
|
||||
Old configuration and maintenance receipts go into inactive
|
||||
`recovery/ID/history/`. The new boot's Sandbox preparation owns cgroup recreation.
|
||||
Unknown/nonempty targets and differing existing files are refused; partial restores
|
||||
|
||||
Reference in New Issue
Block a user