Skip to main content
← PSoXide SDK guides and examples · SDK f2fec1c301f1 · All Cargo features enabled; check feature gates before use.

psx_residency/
backoff.rs

1//! Retry backoff for failed reads.
2//!
3//! Lifted from the grid scheduler (`stream_retry_backoff_windows`): the first
4//! retry waits `base_windows` scheduling windows, every further consecutive
5//! failure doubles the wait up to `base_windows << max_shift`. A success
6//! resets the count, so a transient drive hiccup recovers fast while a
7//! permanently bad chunk settles into one retry every few seconds instead of
8//! one per frame. A resource is never abandoned.
9
10/// Backoff schedule, in scheduling windows (one window per
11/// [`crate::Residency::step`] call).
12#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13pub struct Backoff {
14    /// Wait after the first failure.
15    pub base_windows: u32,
16    /// The wait doubles per failure at most this many times.
17    pub max_shift: u32,
18}
19
20impl Backoff {
21    /// The grid scheduler's schedule: 16 windows, doubling up to 16 << 5 = 512
22    /// (about 0.27 s to 8.5 s when a window is one 60 Hz frame).
23    pub const GRID_DEFAULT: Backoff = Backoff {
24        base_windows: 16,
25        max_shift: 5,
26    };
27
28    /// Windows to wait after `failure_count` consecutive failures (0 when the
29    /// count is 0).
30    pub const fn windows(self, failure_count: u8) -> u32 {
31        if failure_count == 0 {
32            return 0;
33        }
34        let shift = failure_count as u32 - 1;
35        let shift = if shift > self.max_shift {
36            self.max_shift
37        } else {
38            shift
39        };
40        self.base_windows << shift
41    }
42}
43
44impl Default for Backoff {
45    fn default() -> Self {
46        Self::GRID_DEFAULT
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn doubles_per_failure_up_to_the_cap() {
56        let backoff = Backoff::GRID_DEFAULT;
57        assert_eq!(backoff.windows(0), 0);
58        assert_eq!(backoff.windows(1), 16);
59        assert_eq!(backoff.windows(2), 32);
60        assert_eq!(backoff.windows(5), 256);
61        assert_eq!(backoff.windows(6), 512);
62        assert_eq!(backoff.windows(7), 512);
63        assert_eq!(backoff.windows(255), 512);
64    }
65}