use futures::{Future, Poll};
use raftlog::election::Role;
use raftlog::{Error as RaftError, ErrorKind as RaftErrorKind};
use rand::{self, Rng};
use std::time::Duration;
use trackable::error::ErrorKindExt;
#[derive(Debug, Clone)]
pub struct Timer {
min_timeout: Duration,
max_timeout: Duration,
}
impl Timer {
pub fn new(min_timeout: Duration, max_timeout: Duration) -> Self {
assert!(min_timeout <= max_timeout);
Timer {
min_timeout,
max_timeout,
}
}
pub(crate) fn create_timeout(&self, role: Role) -> Timeout {
let duration = match role {
Role::Follower => self.max_timeout,
Role::Candidate => {
let min = duration_to_millis(self.min_timeout);
let max = duration_to_millis(self.max_timeout);
let millis = rand::thread_rng().gen_range(min, max);
Duration::from_millis(millis)
}
Role::Leader => self.min_timeout,
};
let inner = fibers::time::timer::timeout(duration);
Timeout(inner)
}
}
fn duration_to_millis(duration: Duration) -> u64 {
duration.as_secs() * 1000 + u64::from(duration.subsec_nanos()) / 1_000_000
}
#[derive(Debug)]
pub struct Timeout(fibers::time::timer::Timeout);
impl Future for Timeout {
type Item = ();
type Error = RaftError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
track!(self
.0
.poll()
.map_err(|e| RaftErrorKind::Other.cause(e).into(),))
}
}