From 6b3014f3e84b2db6800ab1384b59bcaf1c8b43b0 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:04:37 -0700 Subject: [PATCH] progress: expose bytes_retryable so 'lost' counts only failed reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add PassProgress::bytes_retryable_total (NonTrimmed/NonScraped — failed and awaiting retry), distinct from bytes_pending_total which also folds in not-yet-attempted (NonTried) bytes. Set it at every construction site (Sweep from the snapshot, Patch from stats, 0 for sequential/placeholder paths). The disc-level 'lost' display in the CLI can now use unreadable+retryable instead of unreadable+pending, so a healthy in-progress rip no longer reports its unread remainder as lost. --- src/disc/extract.rs | 1 + src/disc/mod.rs | 24 ++++++++++++++++-------- src/disc/patch.rs | 1 + src/progress.rs | 5 +++++ src/verify.rs | 3 +++ 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/disc/extract.rs b/src/disc/extract.rs index 9833af8..d508ac6 100644 --- a/src/disc/extract.rs +++ b/src/disc/extract.rs @@ -613,6 +613,7 @@ fn report(opts: &ExtractOptions, done: u64, total: u64) -> bool { bytes_good_total: done, bytes_unreadable_total: 0, bytes_pending_total: 0, + bytes_retryable_total: 0, bytes_total_disc: total, disc_duration_secs: None, bytes_bad_in_main_title: 0, diff --git a/src/disc/mod.rs b/src/disc/mod.rs index e124098..dd8603e 100644 --- a/src/disc/mod.rs +++ b/src/disc/mod.rs @@ -3180,14 +3180,21 @@ impl Disc { // already sent — Anomaly B in the 0.18.1 prod test was // this regression: a stale early snapshot pinned the // display to 0 GB while bytes_done was already advancing. - let (bytes_good, bytes_unreadable, bytes_pending) = match &cached_snapshot { - Some(snap) => ( - snap.stats.bytes_good.max(bytes_done), - snap.stats.bytes_unreadable, - snap.stats.bytes_pending, - ), - None => (bytes_done, 0u64, total_bytes.saturating_sub(bytes_done)), - }; + let (bytes_good, bytes_unreadable, bytes_pending, bytes_retryable) = + match &cached_snapshot { + Some(snap) => ( + snap.stats.bytes_good.max(bytes_done), + snap.stats.bytes_unreadable, + snap.stats.bytes_pending, + snap.stats.bytes_retryable, + ), + None => ( + bytes_done, + 0u64, + total_bytes.saturating_sub(bytes_done), + 0u64, + ), + }; let pp = crate::progress::PassProgress { kind: crate::progress::PassKind::Sweep, work_done: pos, @@ -3195,6 +3202,7 @@ impl Disc { bytes_good_total: bytes_good, bytes_unreadable_total: bytes_unreadable, bytes_pending_total: bytes_pending, + bytes_retryable_total: bytes_retryable, bytes_total_disc: total_bytes, disc_duration_secs: main_title.map(|t| t.duration_secs), bytes_bad_in_main_title: main_title_bad, diff --git a/src/disc/patch.rs b/src/disc/patch.rs index 2bf94d0..9b22ab0 100644 --- a/src/disc/patch.rs +++ b/src/disc/patch.rs @@ -1629,6 +1629,7 @@ impl Disc { bytes_good_total: s.bytes_good, bytes_unreadable_total: s.bytes_unreadable, bytes_pending_total: s.bytes_pending, + bytes_retryable_total: s.bytes_retryable, bytes_total_disc: total_bytes, disc_duration_secs: main_title.map(|t| t.duration_secs), bytes_bad_in_main_title: main_title_bad, diff --git a/src/progress.rs b/src/progress.rs index c5dc617..fad4f7d 100644 --- a/src/progress.rs +++ b/src/progress.rs @@ -56,6 +56,11 @@ pub struct PassProgress { pub bytes_good_total: u64, pub bytes_unreadable_total: u64, pub bytes_pending_total: u64, + /// Bytes that FAILED to read and await retry (NonTrimmed/NonScraped) — + /// distinct from `bytes_pending_total` which also includes not-yet-attempted + /// (NonTried) bytes. Used so "lost" counts only failed reads, never unread + /// sectors. + pub bytes_retryable_total: u64, pub bytes_total_disc: u64, pub disc_duration_secs: Option, /// How many bytes of the worst-case damage (unreadable + pending) fall diff --git a/src/verify.rs b/src/verify.rs index e5ea180..b22f1bc 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -215,6 +215,7 @@ pub fn verify_title( bytes_good_total: (good + slow + recovered) * 2048, bytes_unreadable_total: bad * 2048, bytes_pending_total: 0, + bytes_retryable_total: 0, bytes_total_disc: total_sectors * 2048, disc_duration_secs: Some(title.duration_secs), bytes_bad_in_main_title: 0, @@ -264,6 +265,7 @@ pub fn verify_title( bytes_good_total: (good + slow + recovered) * 2048, bytes_unreadable_total: bad * 2048, bytes_pending_total: 0, + bytes_retryable_total: 0, bytes_total_disc: total_sectors * 2048, disc_duration_secs: Some(title.duration_secs), bytes_bad_in_main_title: 0, @@ -327,6 +329,7 @@ pub fn verify_title( bytes_good_total: (good + slow + recovered) * 2048, bytes_unreadable_total: bad * 2048, bytes_pending_total: 0, + bytes_retryable_total: 0, bytes_total_disc: total_sectors * 2048, disc_duration_secs: Some(title.duration_secs), bytes_bad_in_main_title: 0,