use std::{
collections::{BTreeMap, HashMap, HashSet},
ops::{Deref, Sub},
};
use serde::{Deserialize, Serialize};
use zenoh::{key_expr::OwnedKeyExpr, sample::SampleKind, time::Timestamp};
use super::{
digest::Fingerprint,
log::{Event, EventMetadata, LogLatestKey},
};
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum EventRemoval {
NotFound,
KeptNewer,
RemovedOlder(Event),
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum EventLookup<'a> {
NotFound,
NewerOrIdentical(&'a Event),
Older,
}
#[derive(Deserialize, Serialize, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
#[repr(transparent)]
pub struct IntervalIdx(pub(crate) u64);
impl Deref for IntervalIdx {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<u64> for IntervalIdx {
fn from(value: u64) -> Self {
Self(value)
}
}
impl Sub<u64> for IntervalIdx {
type Output = IntervalIdx;
fn sub(self, rhs: u64) -> Self::Output {
(self.0 - rhs).into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub(crate) struct Interval {
fingerprint: Fingerprint,
sub_intervals: BTreeMap<SubIntervalIdx, SubInterval>,
}
impl<const N: usize> From<[(SubIntervalIdx, SubInterval); N]> for Interval {
fn from(sub_intervals: [(SubIntervalIdx, SubInterval); N]) -> Self {
Self {
fingerprint: sub_intervals
.iter()
.fold(Fingerprint::default(), |acc, (_, sub_interval)| {
acc ^ sub_interval.fingerprint
}),
sub_intervals: sub_intervals.into(),
}
}
}
impl Interval {
#[cfg(debug_assertions)]
pub(crate) fn assert_only_one_event_per_key_expr(
&self,
events: &mut HashSet<LogLatestKey>,
) -> bool {
for sub_interval in self.sub_intervals.values() {
if !sub_interval.assert_only_one_event_per_key_expr(events) {
return false;
}
}
true
}
pub(crate) fn fingerprint(&self) -> Fingerprint {
self.fingerprint
}
pub(crate) fn sub_intervals(&self) -> impl Iterator<Item = (&SubIntervalIdx, &SubInterval)> {
self.sub_intervals.iter()
}
pub(crate) fn sub_interval_at(
&self,
sub_interval_idx: &SubIntervalIdx,
) -> Option<&SubInterval> {
self.sub_intervals.get(sub_interval_idx)
}
pub(crate) fn sub_intervals_fingerprints(&self) -> HashMap<SubIntervalIdx, Fingerprint> {
self.sub_intervals
.iter()
.filter(|(_, sub_interval)| sub_interval.fingerprint != Fingerprint::default())
.map(|(sub_interval_idx, sub_interval)| (*sub_interval_idx, sub_interval.fingerprint))
.collect()
}
pub(crate) fn insert_unchecked(&mut self, sub_interval_idx: SubIntervalIdx, event: Event) {
self.fingerprint ^= event.fingerprint();
self.sub_intervals
.entry(sub_interval_idx)
.or_default()
.insert_unchecked(event);
}
pub(crate) fn remove_older(&mut self, event_to_remove: &EventMetadata) -> EventRemoval {
let mut sub_interval_idx_to_remove = None;
let mut result = EventRemoval::NotFound;
for (sub_interval_idx, sub_interval) in self.sub_intervals.iter_mut() {
result = sub_interval.remove_older(event_to_remove);
if let EventRemoval::RemovedOlder(ref old_event) = result {
self.fingerprint ^= old_event.fingerprint();
if sub_interval.events.is_empty() {
sub_interval_idx_to_remove = Some(*sub_interval_idx);
}
}
if !matches!(result, EventRemoval::NotFound) {
break;
}
}
if let Some(sub_interval_idx) = sub_interval_idx_to_remove {
self.sub_intervals.remove(&sub_interval_idx);
}
result
}
pub(crate) fn remove_event(
&mut self,
sub_interval_idx: &SubIntervalIdx,
event_to_remove: &EventMetadata,
) -> Option<Event> {
let removed_event = self
.sub_intervals
.get_mut(sub_interval_idx)
.and_then(|sub_interval| sub_interval.remove_event(event_to_remove));
if let Some(event) = &removed_event {
self.fingerprint ^= event.fingerprint();
}
removed_event
}
pub(crate) fn remove_events_overridden_by_wildcard_update(
&mut self,
prefix: Option<&OwnedKeyExpr>,
wildcard_key_expr: &OwnedKeyExpr,
wildcard_timestamp: &Timestamp,
wildcard_kind: SampleKind,
) -> HashSet<Event> {
let mut overridden_events = HashSet::new();
for sub_interval in self.sub_intervals.values_mut() {
self.fingerprint ^= sub_interval.fingerprint;
overridden_events.extend(sub_interval.remove_events_overridden_by_wildcard_update(
prefix,
wildcard_key_expr,
wildcard_timestamp,
wildcard_kind,
));
self.fingerprint ^= sub_interval.fingerprint;
}
overridden_events
}
}
#[derive(Deserialize, Serialize, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
#[repr(transparent)]
pub struct SubIntervalIdx(pub(crate) u64);
impl Deref for SubIntervalIdx {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<u64> for SubIntervalIdx {
fn from(value: u64) -> Self {
Self(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub(crate) struct SubInterval {
fingerprint: Fingerprint,
events: HashMap<LogLatestKey, Event>,
}
impl<const N: usize> From<[Event; N]> for SubInterval {
fn from(events: [Event; N]) -> Self {
let fingerprint = events.iter().fold(Fingerprint::default(), |acc, event| {
acc ^ event.fingerprint()
});
Self {
fingerprint,
events: events
.into_iter()
.map(|event| (event.log_key(), event))
.collect(),
}
}
}
impl SubInterval {
#[cfg(debug_assertions)]
fn assert_only_one_event_per_key_expr(&self, events: &mut HashSet<LogLatestKey>) -> bool {
for event_log_key in self.events.keys() {
if !events.insert(event_log_key.clone()) {
tracing::error!(
"FATAL ERROR, REPLICATION LOG INVARIANT VIOLATED, KEY APPEARS MULTIPLE TIMES: \
< {event_log_key:?} >"
);
return false;
}
}
true
}
pub(crate) fn fingerprint(&self) -> Fingerprint {
self.fingerprint
}
pub(crate) fn events(&self) -> impl Iterator<Item = &Event> {
self.events.values()
}
fn insert_unchecked(&mut self, event: Event) {
self.fingerprint ^= event.fingerprint();
if let Some(replaced_event) = self.events.insert(event.log_key(), event) {
tracing::warn!(
"Call to `insert_unchecked` replaced an Event in the replication Log, this should \
NOT have happened: {replaced_event:?}"
);
self.fingerprint ^= replaced_event.fingerprint();
}
}
fn remove_older(&mut self, event_to_remove: &EventMetadata) -> EventRemoval {
if let Some((key_expr, event)) = self.events.remove_entry(&event_to_remove.log_key()) {
if event.timestamp() < &event_to_remove.timestamp {
self.fingerprint ^= event.fingerprint();
return EventRemoval::RemovedOlder(event);
} else {
self.events.insert(key_expr, event);
return EventRemoval::KeptNewer;
}
}
EventRemoval::NotFound
}
pub(crate) fn lookup(&self, event_to_lookup: &EventMetadata) -> EventLookup<'_> {
match self.events.get(&event_to_lookup.log_key()) {
Some(event) => {
if event.timestamp >= event_to_lookup.timestamp {
EventLookup::NewerOrIdentical(event)
} else {
EventLookup::Older
}
}
None => EventLookup::NotFound,
}
}
fn remove_event(&mut self, event_to_remove: &EventMetadata) -> Option<Event> {
let removed_event = self.events.remove(&event_to_remove.log_key());
if let Some(event) = &removed_event {
self.fingerprint ^= event.fingerprint();
}
removed_event
}
fn remove_events_overridden_by_wildcard_update(
&mut self,
prefix: Option<&OwnedKeyExpr>,
wildcard_key_expr: &OwnedKeyExpr,
wildcard_timestamp: &Timestamp,
wildcard_kind: SampleKind,
) -> HashSet<Event> {
let overridden_events =
crate::replication::core::remove_events_overridden_by_wildcard_update(
&mut self.events,
prefix,
wildcard_key_expr,
wildcard_timestamp,
wildcard_kind,
);
overridden_events
.iter()
.for_each(|overridden_event| self.fingerprint ^= overridden_event.fingerprint());
overridden_events
}
}
#[cfg(test)]
#[path = "./tests/classification.test.rs"]
mod tests;