use std::hint;
use std::thread;
use std::time::Duration;
pub use crate::config::{CommitTrigger, WaitStrategy};
pub struct Backoff {
spins: u32,
config: WaitStrategy,
}
impl Backoff {
pub fn new(config: WaitStrategy) -> Self {
Self { spins: 0, config }
}
pub fn step(&mut self) {
self.spins = self.spins.saturating_add(1);
if self.spins <= self.config.spin_count {
hint::spin_loop();
} else if self.spins <= self.config.spin_count + self.config.yield_count {
thread::yield_now();
} else {
thread::sleep(self.config.park_duration);
}
}
pub fn reset(&mut self) {
self.spins = 0;
}
}
#[inline]
pub fn producer_backoff(spins: &mut u32) {
*spins = spins.saturating_add(1);
if *spins <= 64 {
hint::spin_loop();
} else if *spins <= 256 {
thread::yield_now();
} else {
thread::sleep(Duration::from_micros(100));
*spins = 128;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn backoff_resets() {
let mut bo = Backoff::new(WaitStrategy::default());
for _ in 0..10 {
bo.step();
}
assert!(bo.spins > 0);
bo.reset();
assert_eq!(bo.spins, 0);
}
#[test]
fn commit_trigger_defaults() {
let t = CommitTrigger::default();
assert_eq!(t.bytes, 256 * 1024);
assert_eq!(t.records, 1024);
assert_eq!(t.interval, Duration::from_millis(10));
}
}