From a436c659e93d07680996d0fd6e818042c3053158 Mon Sep 17 00:00:00 2001 From: kronecker <2026692687@qq.com> Date: Wed, 28 Oct 2026 21:35:41 +0800 Subject: [PATCH] perf(delivery): stream verified restore file pages --- .../crates/sandbox/src/restore_copy/files.rs | 6 +++ judge/crates/sandbox/src/restore_copy/main.rs | 40 +++++++++++++++++++ scripts/release/README.md | 5 +++ 3 files changed, 51 insertions(+) diff --git a/judge/crates/sandbox/src/restore_copy/files.rs b/judge/crates/sandbox/src/restore_copy/files.rs index 908b0f4..c2699f7 100644 --- a/judge/crates/sandbox/src/restore_copy/files.rs +++ b/judge/crates/sandbox/src/restore_copy/files.rs @@ -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 { diff --git a/judge/crates/sandbox/src/restore_copy/main.rs b/judge/crates/sandbox/src/restore_copy/main.rs index 5c53814..7bbe250 100644 --- a/judge/crates/sandbox/src/restore_copy/main.rs +++ b/judge/crates/sandbox/src/restore_copy/main.rs @@ -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!( diff --git a/scripts/release/README.md b/scripts/release/README.md index 2b473b1..74fc599 100644 --- a/scripts/release/README.md +++ b/scripts/release/README.md @@ -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