From 4fc06ee233d1c0990ff92694df350339b472190c Mon Sep 17 00:00:00 2001 From: kronecker <2026692687@qq.com> Date: Thu, 29 Oct 2026 17:13:17 +0800 Subject: [PATCH] perf(delivery): release copied large source pages --- .../crates/sandbox/src/restore_copy/files.rs | 12 ++++ judge/crates/sandbox/src/restore_copy/main.rs | 64 +++++++++++++++++++ scripts/release/README.md | 2 + 3 files changed, 78 insertions(+) diff --git a/judge/crates/sandbox/src/restore_copy/files.rs b/judge/crates/sandbox/src/restore_copy/files.rs index fbf0411..21bc87b 100644 --- a/judge/crates/sandbox/src/restore_copy/files.rs +++ b/judge/crates/sandbox/src/restore_copy/files.rs @@ -414,6 +414,18 @@ fn transfer(input: &mut File, output: &mut File, bytes: u64, deadline: u64) -> R return Err(Error::Bytes); } total += count as u64; + if bytes > kf_contracts::restore_io::MAX_BATCH_BYTES { + // A large singleton cannot share source pages with another batch. + // Only release the already copied range of this read-only object; + // destination sync, complete readback and every witness still follow. + rustix::fs::fadvise( + &*input, + total - count as u64, + std::num::NonZeroU64::new(count as u64), + rustix::fs::Advice::DontNeed, + ) + .map_err(|_| Error::Filesystem)?; + } } remaining(deadline)?; if input.read(&mut [0; 1]).map_err(|_| Error::Filesystem)? != 0 { diff --git a/judge/crates/sandbox/src/restore_copy/main.rs b/judge/crates/sandbox/src/restore_copy/main.rs index 1e8611c..cbc3c15 100644 --- a/judge/crates/sandbox/src/restore_copy/main.rs +++ b/judge/crates/sandbox/src/restore_copy/main.rs @@ -630,4 +630,68 @@ mod tests { assert!(request(&mut &b""[..]).is_err()); assert!(request(&mut &vec![b' '; restore_io::MAX_REQUEST_BYTES + 1][..]).is_err()); } + + #[test] + fn large_singleton_keeps_complete_source_and_destination_after_cache_advice() { + let fixture = files::Fixture::new(); + let roots = Arc::new(fixture.roots()); + let data = vec![b's'; restore_io::MAX_BATCH_BYTES as usize + 17]; + 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 stamp = |m: fs::Metadata| { + ( + m.dev(), + m.ino(), + m.mode(), + m.nlink(), + m.uid(), + m.gid(), + m.size(), + (m.mtime(), m.mtime_nsec()), + (m.ctime(), m.ctime_nsec()), + ) + }; + let owner = fs::metadata(&source).unwrap(); + let before = stamp(fs::metadata(&source).unwrap()); + let rows = vec![restore_io::RestoreFile { + path: "artifacts/large-singleton".into(), + uid: owner.uid(), + gid: owner.gid(), + mode: 0o644, + bytes: data.len() as u64, + sha256: hash, + }]; + // Validate the real wire owner policy separately from the unprivileged + // ordinary fixture's owner. Production never accepts the host test UID. + let mut wire_rows = rows.clone(); + wire_rows[0].uid = 1200; + wire_rows[0].gid = 1200; + Request::Batch { + schema_version: SchemaVersion, + batch_id: 1, + files: wire_rows, + } + .validate() + .unwrap(); + assert_eq!(rows.len(), 1); + let pool = Pool::new(Arc::clone(&roots)).unwrap_or_else(|_| panic!("pool")); + let verified = pool + .materialize(rows, &roots, now().unwrap() + 30_000_000_000) + .unwrap_or_else(|_| panic!("large singleton verified")); + assert_eq!(verified.len(), 1); + roots + .final_file(&verified[0]) + .unwrap_or_else(|_| panic!("final witness")); + assert_eq!( + fs::read(fixture.target().join("large-singleton")).unwrap(), + data + ); + assert_eq!(fs::read(&source).unwrap(), data); + assert_eq!(stamp(fs::metadata(&source).unwrap()), before); + drop(pool); + roots.unchanged().unwrap_or_else(|_| panic!("root anchors")); + } } diff --git a/scripts/release/README.md b/scripts/release/README.md index 04f0346..9453050 100644 --- a/scripts/release/README.md +++ b/scripts/release/README.md @@ -637,3 +637,5 @@ outside public API, Git and CI artifacts. [namespace interface](https://github.com/systemd/systemd/blob/v262/man/systemd.exec.xml), [journal configuration](https://github.com/systemd/systemd/blob/v262/man/journald.conf.xml). - Linux: [proc mountinfo](https://github.com/torvalds/linux/blob/v6.18/fs/proc_namespace.c). + +恢复大于 64 MiB 的单对象文件时,复制器仅对已复制的只读源区间发出有界缓存回收建议,避免源和目标页面同时占满原恢复单元。目标仍在原同步屏障后完整读回、逐字节/SHA 校验,并在结束前复核全部文件身份;原内存、CPU、线程、期限和失败保留规则保持不变。