disc/patch: adaptive batching — 32 sectors, drop to 1 on failure
Pass N now reads at 32 sectors per attempt and drops to 1 only on batch-read failure to probe each sector individually. After 16 consecutive clean single-sector reads it climbs back to 32. Net effect: NonTrimmed regions walk ~32x faster in clean stretches without sacrificing per-sector recovery quality — the drop-to-1 retry from the same cursor position guarantees every sector in a failed batch is individually attempted. Design contract: - A batch-read failure (count > 1) is NOT a recorded failure: no NonTrimmed mark, no consecutive_failures bump, no damage_window push, cursor stays put. We just drop current_batch to 1 and the loop re-attempts the same position at single-sector granularity. - A single-sector failure (count == 1) follows the existing path: NonTrimmed mark, consecutive_failures++, damage_window.push(false), post-failure pause, wedge probes. - Backtrack always at count=1: this path fills a gap that the main loop's damage-window skip jumped over. Using batched reads there would lump good sectors into NonTrimmed marks when the gap contains even one bad sector. State machine adds: - `initial_batch` (from opts.block_sectors, default 32 in patch_internal) - `current_batch` (mutable, starts at initial_batch, drops to 1 on batch failure) - `consecutive_singles_ok` (counter, resets on upscale + failure) - `ADAPTIVE_UPSCALE_THRESHOLD = 16` (matches sweep's pattern for "16 consecutive good = back to fast mode") Tests: - pass_n_size_aware_skip.rs PatternedSectorReader now fills each sector with its OWN LBA byte (not the starting LBA's byte). This matches real drive behavior — the pre-0.18.13 fixture's "fill whole batch with one byte" was a shortcut that only worked when patch read 1 sector at a time. Existing recovery-quality assertions all still pass under adaptive batching. User spec: "try 32, pass, great, fail -> do 1 sector"
This commit is contained in:
@@ -70,8 +70,14 @@ impl SectorReader for PatternedSectorReader {
|
||||
});
|
||||
}
|
||||
}
|
||||
for chunk in buf.chunks_mut(SECTOR_SIZE) {
|
||||
chunk.fill((lba & 0xff) as u8);
|
||||
// Fill each sector with ITS OWN LBA byte, not the starting LBA's
|
||||
// byte. This matches real drive behavior: a multi-sector READ
|
||||
// returns per-sector-correct data. Pre-0.18.13 only single-sector
|
||||
// reads were exercised by patch tests, so the cheaper "fill the
|
||||
// whole batch with one byte" worked; adaptive batching needs the
|
||||
// per-sector pattern to verify correct positioning.
|
||||
for (i, chunk) in buf.chunks_mut(SECTOR_SIZE).enumerate() {
|
||||
chunk.fill(((lba + i as u32) & 0xff) as u8);
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user