use log::{debug, error};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::time::SystemTime;
use dcs::config::{get_argument, SystemNodeArgs};
use dcs::membership::metadata::{BasicMetadata, CoordinationMetadataBuilder, SerializableMetadata};
use dcs::nodes::NodeRole;
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
pub struct RaftMetadata {
pub timeout: u64,
}
impl RaftMetadata {
pub fn new(timeout: u64) -> Self {
Self { timeout }
}
}
impl BasicMetadata for RaftMetadata {}
impl SerializableMetadata for RaftMetadata {}
impl Display for RaftMetadata {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
write!(formatter, "[Timeout: {}]", self.timeout)
}
}
#[derive(Default)]
pub struct RaftMetadataBuilder;
impl RaftMetadataBuilder {
fn randomize_timeout(original_timeout: u64) -> u64 {
let seed = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
let mut rng = ChaCha20Rng::seed_from_u64(seed);
let random_timeout = rng.gen_range(original_timeout..original_timeout * 6);
debug!("Random timeout: {}", random_timeout);
random_timeout
}
}
impl CoordinationMetadataBuilder<RaftMetadata> for RaftMetadataBuilder {
fn build(args: &SystemNodeArgs) -> RaftMetadata {
match args.role {
NodeRole::SENSOR(_) => {
let timeout = get_argument(args.clone().coordination.unwrap(), "timeout")
.and_then(|val| val.parse::<u64>().ok())
.unwrap_or_else(|| {
error!("TIMEOUT argument expected.");
panic!()
});
let timeout = RaftMetadataBuilder::randomize_timeout(timeout);
log::info!("Generated timeout of {} for Raft.", timeout);
RaftMetadata::new(timeout)
}
_ => {
error!(
"Shouldn't try to parse Raft metadata for an {:?}.",
args.role
);
panic!()
}
}
}
}