use crate::error::{Error, Result};
const DEFAULT_ELECTION_TIMEOUT_MIN: u64 = 1500;
const DEFAULT_ELECTION_TIMEOUT_MAX: u64 = 3000;
const DEFAULT_HEARTBEAT_INTERVAL: u64 = 500;
#[derive(Debug, Clone)]
pub struct Options {
election_timeout_min: u64,
election_timeout_max: u64,
heartbeat_interval: u64,
quorum: Quorum,
}
#[derive(Debug, Copy, Clone)]
pub enum Quorum {
Major,
Any(u32),
}
impl Default for Quorum {
#[inline]
fn default() -> Self {
Quorum::Major
}
}
impl Options {
#[inline]
pub const fn new() -> Self {
Options {
election_timeout_min: DEFAULT_ELECTION_TIMEOUT_MIN,
election_timeout_max: DEFAULT_ELECTION_TIMEOUT_MAX,
heartbeat_interval: DEFAULT_HEARTBEAT_INTERVAL,
quorum: Quorum::Major,
}
}
#[inline]
pub fn random_election_timeout(&self) -> u64 {
fastrand::u64(self.election_timeout_min..self.election_timeout_max)
}
#[inline]
pub const fn election_timeout_min(&self) -> u64 {
self.election_timeout_min
}
#[inline]
pub const fn heartbeat_interval(&self) -> u64 {
self.heartbeat_interval
}
#[inline]
pub const fn quorum(&self) -> Quorum {
self.quorum
}
#[inline]
pub const fn builder() -> OptionsBuilder {
OptionsBuilder::new()
}
}
impl Default for Options {
#[inline]
fn default() -> Self {
Options::new()
}
}
#[derive(Debug, Default)]
pub struct OptionsBuilder {
election_timeout_min: Option<u64>,
election_timeout_max: Option<u64>,
heartbeat_interval: Option<u64>,
quorum: Option<Quorum>,
}
impl OptionsBuilder {
#[inline]
pub const fn new() -> Self {
OptionsBuilder {
election_timeout_min: None,
election_timeout_max: None,
heartbeat_interval: None,
quorum: None,
}
}
#[inline]
pub const fn election_timeout_min(mut self, val: u64) -> Self {
self.election_timeout_min = Some(val);
self
}
#[inline]
pub const fn election_timeout_max(mut self, val: u64) -> Self {
self.election_timeout_max = Some(val);
self
}
#[inline]
pub const fn heartbeat_interval(mut self, val: u64) -> Self {
self.heartbeat_interval = Some(val);
self
}
#[inline]
pub const fn quorum(mut self, quorum: Quorum) -> Self {
self.quorum = Some(quorum);
self
}
#[inline]
pub fn build(self) -> Result<Options> {
let election_timeout_min = self.election_timeout_min.unwrap_or(DEFAULT_ELECTION_TIMEOUT_MIN);
let election_timeout_max = self.election_timeout_max.unwrap_or(DEFAULT_ELECTION_TIMEOUT_MAX);
if election_timeout_min >= election_timeout_max {
return Err(Error::InvalidOptions(try_format!(
"election timeout min({}) & max({}) are invalid: max must be greater than min",
election_timeout_min,
election_timeout_max
)?));
}
let heartbeat_interval = self.heartbeat_interval.unwrap_or(DEFAULT_HEARTBEAT_INTERVAL);
if election_timeout_min <= heartbeat_interval {
return Err(Error::InvalidOptions(try_format!(
"election_timeout_min({}) must be greater than heartbeat_interval({})",
election_timeout_min,
heartbeat_interval
)?));
}
let quorum = self.quorum.unwrap_or(Quorum::Major);
Ok(Options {
election_timeout_min,
election_timeout_max,
heartbeat_interval,
quorum,
})
}
}