ciruela 0.6.12

A peer-to-peer synchronization software for servers in datacenters.
Documentation
use std::fmt;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::hash::Hash;
use std::time::{Instant, Duration};

use abstract_ns::Name;


const RETRY_TIME: Duration = Duration::from_secs(1);
const SLOW_RETRY_TIME: Duration = Duration::from_secs(10);


pub type HostFailures = Failures<SocketAddr, DefaultPolicy>;
pub type SlowHostFailures = Failures<SocketAddr, SlowerPolicy>;
pub type DnsFailures = Failures<Name, DefaultPolicy>;

#[derive(Debug)]
pub struct DefaultPolicy;

#[derive(Debug)]
pub struct SlowerPolicy;

#[derive(Debug)]
pub struct Failures<K: Eq + Hash, P> {
    items: HashMap<K, Failure>,
    policy: P,
}

#[derive(Debug)]
pub struct Failure {
    subsequent: u32,
    last: Instant,
}

pub trait Policy: fmt::Debug {
    fn can_try(&self, entry: &Failure) -> bool;
}

impl Policy for DefaultPolicy {
    fn can_try(&self, entry: &Failure) -> bool {
        let since = Instant::now() - entry.last;
        return since > RETRY_TIME * entry.subsequent;
    }
}

impl Policy for SlowerPolicy {
    fn can_try(&self, entry: &Failure) -> bool {
        let since = Instant::now() - entry.last;
        return since > SLOW_RETRY_TIME * entry.subsequent;
    }
}

impl<K: Clone + Eq + Hash> Failures<K, DefaultPolicy> {
    pub fn new_default() -> Failures<K, DefaultPolicy> {
        Failures {
            policy: DefaultPolicy,
            items: HashMap::new(),
        }
    }
}

impl<K: Clone + Eq + Hash> Failures<K, SlowerPolicy> {
    pub fn new_slow() -> Failures<K, SlowerPolicy> {
        Failures {
            policy: SlowerPolicy,
            items: HashMap::new(),
        }
    }
}

impl<K: Clone + Eq + Hash, P: Policy> Failures<K, P> {
    pub fn add_failure(&mut self, name: K) {
        let entry = self.items.entry(name)
            .or_insert(Failure {
                subsequent: 0,
                last: Instant::now(),
            });
        entry.subsequent = entry.subsequent.saturating_add(1);
        entry.last = Instant::now();
    }
    pub fn reset(&mut self, name: &K) {
        self.items.remove(name);
    }
    pub fn can_try(&self, name: &K) -> bool {
        self.items.get(name)
            .map(|f| self.policy.can_try(f))
            .unwrap_or(true)
    }
}