use core::time::Duration;
#[derive(Debug, Default)]
pub(crate) struct HostRefreshCursor {
next: usize,
}
impl HostRefreshCursor {
pub(crate) fn claim_next(
&mut self,
host_count: usize,
mut claim: impl FnMut(usize) -> bool,
) -> Option<usize> {
if host_count == 0 {
self.next = 0;
return None;
}
let start = self.next % host_count;
for offset in 0..host_count {
let index = (start + offset) % host_count;
if claim(index) {
self.next = (index + 1) % host_count;
return Some(index);
}
}
None
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct RefreshRetryBackoff {
next: Duration,
}
impl RefreshRetryBackoff {
pub(crate) const MIN_DELAY: Duration = Duration::from_millis(1);
pub(crate) const MAX_DELAY: Duration = Duration::from_millis(100);
pub(crate) fn next_delay(&mut self) -> Duration {
let delay = self.next;
self.next = self.next.saturating_mul(2).min(Self::MAX_DELAY);
delay
}
pub(crate) fn reset(&mut self) {
self.next = Self::MIN_DELAY;
}
}
impl Default for RefreshRetryBackoff {
fn default() -> Self {
Self {
next: Self::MIN_DELAY,
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub(crate) enum HostRefreshState {
#[default]
Idle,
Queued,
Probing,
DirtyAgain,
Disabled,
}
impl HostRefreshState {
pub(crate) fn mark_dirty(&mut self) {
*self = match *self {
Self::Idle => Self::Queued,
Self::Queued => Self::Queued,
Self::Probing => Self::DirtyAgain,
Self::DirtyAgain => Self::DirtyAgain,
Self::Disabled => Self::Disabled,
};
}
pub(crate) fn begin_probe(&mut self) -> bool {
if *self != Self::Queued {
return false;
}
*self = Self::Probing;
true
}
pub(crate) fn defer_probe(&mut self) {
*self = match *self {
Self::Probing | Self::DirtyAgain => Self::Queued,
state => state,
};
}
pub(crate) fn finish_probe(&mut self) -> bool {
match *self {
Self::Probing => {
*self = Self::Idle;
false
}
Self::DirtyAgain => {
*self = Self::Queued;
true
}
Self::Idle | Self::Queued | Self::Disabled => false,
}
}
pub(crate) fn finish_initial_probe(&mut self) -> bool {
self.finish_probe()
}
pub(crate) const fn is_queued(self) -> bool {
matches!(self, Self::Queued)
}
pub(crate) const fn is_enabled(self) -> bool {
!matches!(self, Self::Disabled)
}
pub(crate) fn disable(&mut self) {
*self = Self::Disabled;
}
}