Skip to main content

RetryConfig

Struct RetryConfig 

Source
pub struct RetryConfig { /* private fields */ }
Expand description

Retry policy for failed drive reads.

Track and sector-range reads are split into chunks, and this policy is applied independently to each chunk. If a chunk read fails, the next attempt starts at the same LBA. Retry delays use capped exponential backoff. When adaptive chunk reduction is enabled, retries request fewer sectors from that LBA, down to the configured minimum. Chunks that were already read successfully are not repeated.

The default values are suitable for most drives. Unless you have specific requirements, using RetryConfig::default is recommended.

The default policy uses:

  • 4 attempts, including the initial read;
  • a 20 ms initial backoff;
  • a 300 ms maximum backoff;
  • adaptive chunk reduction;
  • a minimum chunk size of 1 sector.

Implementations§

Source§

impl RetryConfig

Source

pub fn with_max_attempts(self, attempts: u8) -> Self

Set the maximum attempts per chunk, including the initial read.

A value of zero is normalized to one attempt.

Examples found in repository?
examples/custom_retry.rs (line 26)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    let output_dir = common::fresh_output_dir("custom_retry")?;
14    let reader = CdReader::open_default()?;
15    let toc = reader.read_toc()?;
16
17    let first_audio = toc
18        .tracks
19        .iter()
20        .find(|t| t.is_audio)
21        .ok_or("no audio tracks found")?;
22
23    // More attempts, longer backoff, and sector reduction down to 1
24    // for maximum resilience on scratched media.
25    let retry = RetryConfig::default()
26        .with_max_attempts(8)
27        .with_initial_backoff(Duration::from_millis(50))
28        .with_max_backoff(Duration::from_secs(1))
29        .with_chunk_reduction(true)
30        .with_min_sectors_per_read(1);
31    let options = ReadOptions::default().with_retry(retry);
32
33    println!(
34        "Reading track {} with aggressive retry...",
35        first_audio.number
36    );
37    let data = reader.read_track_with_options(&toc, first_audio.number, &options)?;
38
39    let wav = create_wav(data);
40    let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
41    std::fs::write(&output_path, wav)?;
42    println!("Saved {}", output_path.display());
43
44    Ok(())
45}
Source

pub fn with_initial_backoff(self, backoff: Duration) -> Self

Set the delay before the second attempt.

The first attempt is always immediate.

Examples found in repository?
examples/custom_retry.rs (line 27)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    let output_dir = common::fresh_output_dir("custom_retry")?;
14    let reader = CdReader::open_default()?;
15    let toc = reader.read_toc()?;
16
17    let first_audio = toc
18        .tracks
19        .iter()
20        .find(|t| t.is_audio)
21        .ok_or("no audio tracks found")?;
22
23    // More attempts, longer backoff, and sector reduction down to 1
24    // for maximum resilience on scratched media.
25    let retry = RetryConfig::default()
26        .with_max_attempts(8)
27        .with_initial_backoff(Duration::from_millis(50))
28        .with_max_backoff(Duration::from_secs(1))
29        .with_chunk_reduction(true)
30        .with_min_sectors_per_read(1);
31    let options = ReadOptions::default().with_retry(retry);
32
33    println!(
34        "Reading track {} with aggressive retry...",
35        first_audio.number
36    );
37    let data = reader.read_track_with_options(&toc, first_audio.number, &options)?;
38
39    let wav = create_wav(data);
40    let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
41    std::fs::write(&output_path, wav)?;
42    println!("Saved {}", output_path.display());
43
44    Ok(())
45}
Source

pub fn with_max_backoff(self, backoff: Duration) -> Self

Set the upper bound for exponential backoff delays.

A duration of zero disables retry delays.

Examples found in repository?
examples/custom_retry.rs (line 28)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    let output_dir = common::fresh_output_dir("custom_retry")?;
14    let reader = CdReader::open_default()?;
15    let toc = reader.read_toc()?;
16
17    let first_audio = toc
18        .tracks
19        .iter()
20        .find(|t| t.is_audio)
21        .ok_or("no audio tracks found")?;
22
23    // More attempts, longer backoff, and sector reduction down to 1
24    // for maximum resilience on scratched media.
25    let retry = RetryConfig::default()
26        .with_max_attempts(8)
27        .with_initial_backoff(Duration::from_millis(50))
28        .with_max_backoff(Duration::from_secs(1))
29        .with_chunk_reduction(true)
30        .with_min_sectors_per_read(1);
31    let options = ReadOptions::default().with_retry(retry);
32
33    println!(
34        "Reading track {} with aggressive retry...",
35        first_audio.number
36    );
37    let data = reader.read_track_with_options(&toc, first_audio.number, &options)?;
38
39    let wav = create_wav(data);
40    let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
41    std::fs::write(&output_path, wav)?;
42    println!("Saved {}", output_path.display());
43
44    Ok(())
45}
Source

pub fn with_chunk_reduction(self, enabled: bool) -> Self

Enable or disable requesting fewer sectors after a failed chunk read.

Examples found in repository?
examples/custom_retry.rs (line 29)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    let output_dir = common::fresh_output_dir("custom_retry")?;
14    let reader = CdReader::open_default()?;
15    let toc = reader.read_toc()?;
16
17    let first_audio = toc
18        .tracks
19        .iter()
20        .find(|t| t.is_audio)
21        .ok_or("no audio tracks found")?;
22
23    // More attempts, longer backoff, and sector reduction down to 1
24    // for maximum resilience on scratched media.
25    let retry = RetryConfig::default()
26        .with_max_attempts(8)
27        .with_initial_backoff(Duration::from_millis(50))
28        .with_max_backoff(Duration::from_secs(1))
29        .with_chunk_reduction(true)
30        .with_min_sectors_per_read(1);
31    let options = ReadOptions::default().with_retry(retry);
32
33    println!(
34        "Reading track {} with aggressive retry...",
35        first_audio.number
36    );
37    let data = reader.read_track_with_options(&toc, first_audio.number, &options)?;
38
39    let wav = create_wav(data);
40    let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
41    std::fs::write(&output_path, wav)?;
42    println!("Saved {}", output_path.display());
43
44    Ok(())
45}
Source

pub fn with_min_sectors_per_read(self, sectors: u32) -> Self

Set the minimum sectors per command when adaptive reduction is enabled.

A value of zero is normalized to one sector.

Examples found in repository?
examples/custom_retry.rs (line 30)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    let output_dir = common::fresh_output_dir("custom_retry")?;
14    let reader = CdReader::open_default()?;
15    let toc = reader.read_toc()?;
16
17    let first_audio = toc
18        .tracks
19        .iter()
20        .find(|t| t.is_audio)
21        .ok_or("no audio tracks found")?;
22
23    // More attempts, longer backoff, and sector reduction down to 1
24    // for maximum resilience on scratched media.
25    let retry = RetryConfig::default()
26        .with_max_attempts(8)
27        .with_initial_backoff(Duration::from_millis(50))
28        .with_max_backoff(Duration::from_secs(1))
29        .with_chunk_reduction(true)
30        .with_min_sectors_per_read(1);
31    let options = ReadOptions::default().with_retry(retry);
32
33    println!(
34        "Reading track {} with aggressive retry...",
35        first_audio.number
36    );
37    let data = reader.read_track_with_options(&toc, first_audio.number, &options)?;
38
39    let wav = create_wav(data);
40    let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
41    std::fs::write(&output_path, wav)?;
42    println!("Saved {}", output_path.display());
43
44    Ok(())
45}

Trait Implementations§

Source§

impl Clone for RetryConfig

Source§

fn clone(&self) -> RetryConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RetryConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for RetryConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.