use std::{
ops::Deref,
time::{SystemTime, UNIX_EPOCH},
};
use zenoh::{internal::bail, key_expr::OwnedKeyExpr, time::Timestamp, Result};
use zenoh_backend_traits::config::ReplicaConfig;
use super::{
classification::{IntervalIdx, SubIntervalIdx},
digest::Fingerprint,
};
#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) struct Configuration {
storage_key_expr: OwnedKeyExpr,
prefix: Option<OwnedKeyExpr>,
replica_config: ReplicaConfig,
fingerprint: Fingerprint,
}
impl Deref for Configuration {
type Target = ReplicaConfig;
fn deref(&self) -> &Self::Target {
&self.replica_config
}
}
impl Configuration {
pub fn new(
storage_key_expr: OwnedKeyExpr,
prefix: Option<OwnedKeyExpr>,
replica_config: ReplicaConfig,
) -> Self {
let mut hasher = xxhash_rust::xxh3::Xxh3::default();
hasher.update(storage_key_expr.as_bytes());
if let Some(prefix) = &prefix {
hasher.update(prefix.as_bytes());
}
hasher.update(&replica_config.interval.as_millis().to_le_bytes());
hasher.update(&replica_config.sub_intervals.to_le_bytes());
hasher.update(&replica_config.hot.to_le_bytes());
hasher.update(&replica_config.warm.to_le_bytes());
hasher.update(&replica_config.propagation_delay.as_millis().to_le_bytes());
Self {
storage_key_expr,
prefix,
replica_config,
fingerprint: Fingerprint::from(hasher.digest()),
}
}
pub fn prefix(&self) -> Option<&OwnedKeyExpr> {
self.prefix.as_ref()
}
pub fn fingerprint(&self) -> Fingerprint {
self.fingerprint
}
pub fn last_elapsed_interval(&self) -> Result<IntervalIdx> {
let duration_since_epoch = SystemTime::now().duration_since(UNIX_EPOCH)?;
let last_elapsed_interval = duration_since_epoch.as_millis() / self.interval.as_millis();
if last_elapsed_interval > u64::MAX as u128 {
bail!("Overflow detected, last elapsed interval is higher than u64::MAX");
}
Ok(IntervalIdx(last_elapsed_interval as u64))
}
pub fn hot_era_lower_bound(&self, hot_era_upper_bound: IntervalIdx) -> IntervalIdx {
(*hot_era_upper_bound - self.hot + 1).into()
}
pub fn warm_era_lower_bound(&self, hot_era_upper_bound: IntervalIdx) -> IntervalIdx {
(*hot_era_upper_bound - self.hot - self.warm + 1).into()
}
pub fn get_time_classification(
&self,
timestamp: &Timestamp,
) -> Result<(IntervalIdx, SubIntervalIdx)> {
let timestamp_ms_since_epoch = timestamp
.get_time()
.to_system_time()
.duration_since(UNIX_EPOCH)?
.as_millis();
let interval = timestamp_ms_since_epoch / self.interval.as_millis();
if interval > u64::MAX as u128 {
bail!(
"Overflow detected, interval associated with Timestamp < {} > is higher than \
u64::MAX",
timestamp.to_string()
);
}
let sub_interval = (timestamp_ms_since_epoch - (self.interval.as_millis() * interval))
/ (self.interval.as_millis() / self.sub_intervals as u128);
let interval = interval as u64;
Ok((
IntervalIdx::from(interval),
SubIntervalIdx::from(sub_interval as u64),
))
}
}
#[cfg(test)]
#[path = "tests/configuration.test.rs"]
mod test;