v0.17.11: sweep producer/consumer split — overlap drive read with file write
Pre-0.17.11 sweep ran strictly serialised: SCSI read → decrypt → seek + write → mapfile.record → next read. Drive idled for the post-read work; throughput capped at the sum of both costs. On a healthy disc that's ~7-12 ms read + ~5-15 ms write/record per 64 KB batch, limiting sustained throughput to ~10-12 MB/s on the test bed (BU40N + UHD inner zone), well below the ~14-16 MB/s drive ceiling. Decouples them: producer thread (caller's) owns SectorReader + read_error state + decrypt + set_speed + halt; consumer thread (one spawn) owns Writer + Mapfile, receives WorkItem messages, applies file write + mapfile record. Bounded mpsc::sync_channel(4) gives natural back-pressure. While the consumer writes batch N, the producer is already reading batch N+1 — steady-state throughput is now bound by the slower of the two pipelines (drive on healthy discs), not their sum. Side effects: - Bisect path now decrypts. Pre-0.17.11 the bisect inner loop wrote raw cyphertext for single-sector recoveries on encrypted discs — quiet correctness bug exercised only by batch-fail-then- bisect-succeed on encrypted media. New producer-side decrypt covers main + bisect success paths uniformly. - All read_ctx state stays single-threaded on producer (damage window, jump multiplier, etc.). No locking added. - Mapfile remains single-writer on consumer. No locking. - Halt latency: producer breaks loop, sends Finish, consumer drains ≤4 in-flight items + sync_all. ~1 batch (~12 ms) typical. - BU40N + Initio bridge wedge concern unchanged: still single SCSI command in flight, error-path timing identical, no new retries. New module: src/disc/sweep_pipeline.rs (WorkItem, ProgressSnapshot, ConsumerInputs, spawn_consumer, consumer_loop, helpers). Public API unchanged — Disc::copy / CopyOptions / CopyResult identical. Patch (Pass N) is NOT changed; it's bound by drive recovery time, not the read/write serialisation.
This commit is contained in:
+1
-5
@@ -12,7 +12,7 @@
|
||||
//!
|
||||
//! See `super::writeback::linux` for the pathology and the strategy.
|
||||
|
||||
use std::fs::{File, Metadata};
|
||||
use std::fs::File;
|
||||
use std::io::{self, Seek, SeekFrom, Write};
|
||||
|
||||
use super::writeback::WritebackPipeline;
|
||||
@@ -40,10 +40,6 @@ impl Writer {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn metadata(&self) -> io::Result<Metadata> {
|
||||
self.file.metadata()
|
||||
}
|
||||
|
||||
/// Drain in-flight writeback then issue a full fsync. Use this in
|
||||
/// place of `File::sync_all`.
|
||||
pub(crate) fn sync_all(&mut self) -> io::Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user