v0.17.10: bounded-cache writeback pipeline for big sequential writes

Pass 1 sweep speed on a healthy disc previously dipped from ~15 MB/s
to ~1 MB/s every ~30 s on a host with default Linux dirty-page
settings. Empirical cause: the kernel's vm.dirty_ratio (~20% of RAM)
lets hundreds of MB of dirty pages accumulate, then bursts a flush at
99% disk utilisation that blocks app writes for ~1 s. Confirmed on
the BU40N test bed — dirty pages grew 112 → 563 MB between bursts;
lowering vm.dirty_bytes to 64 MB at the host sysctl level eliminated
the dips. Shipping the equivalent inside libfreemkv so users do not
need to tune the host kernel.

- New crate::io::Writer: drop-in File wrapper (impl Write + Seek).
  Wraps a per-platform WritebackPipeline that on Linux schedules
  sync_file_range(WRITE) + lagging sync_file_range(WAIT_AFTER) +
  posix_fadvise(DONTNEED) in 32 MB chunks, bounding dirty cache at
  ~64 MB. macOS and Windows ship a no-op stub.
- Disc::sweep wraps its output File in Writer. Loop body unchanged.
- Module is purpose-built so any large sequential output (patch,
  mux) can adopt the same wrapper as a one-line change later.
This commit is contained in:
2026-05-08 19:54:25 -07:00
parent 75f6df529c
commit 1085eb1e39
9 changed files with 271 additions and 2 deletions
+5 -1
View File
@@ -1414,7 +1414,11 @@ impl Disc {
f
};
let mut file = file;
// Wrap the raw `File` in our bounded-cache writer so the
// kernel's writeback queue drains continuously instead of
// accumulating hundreds of MB of dirty pages and then bursting
// a flush that blocks app writes (see `crate::io`).
let mut file = crate::io::Writer::new(file).map_err(|e| Error::IoError { source: e })?;
let batch: u16 = match opts.batch_sectors {
Some(b) => b,
None if opts.skip_on_error => ecc_sectors(self.format),