use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;
use crate::error::RetrievalError;
use crate::event_dag::accumulator::{compute_ancestry_from_dag, is_descendant_dag, EventAccumulator};
use crate::retrieval::GetEvents;
use ankurah_proto::{Event, EventId};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum CausalRelation {
Descends,
Ascends,
Concurrent,
}
pub(crate) struct EventLayers<E: GetEvents> {
accumulator: EventAccumulator<E>,
current_head_ancestry: BTreeSet<EventId>,
children_index: BTreeMap<EventId, Vec<EventId>>,
dag: Arc<BTreeMap<EventId, Vec<EventId>>>,
processed: BTreeSet<EventId>,
frontier: BTreeSet<EventId>,
}
impl<E: GetEvents> EventLayers<E> {
pub(crate) fn new(accumulator: EventAccumulator<E>, meet: Vec<EventId>, current_head: Vec<EventId>) -> Self {
let mut children_index: BTreeMap<EventId, Vec<EventId>> = BTreeMap::new();
for (id, parents) in accumulator.dag() {
for parent in parents {
children_index.entry(parent.clone()).or_default().push(id.clone());
}
}
let current_head_ancestry = compute_ancestry_from_dag(accumulator.dag(), ¤t_head);
let dag = Arc::new(accumulator.dag().clone());
let processed: BTreeSet<EventId> = meet.iter().cloned().collect();
let frontier: BTreeSet<EventId> = accumulator
.dag()
.keys()
.filter(|id| !processed.contains(*id))
.filter(|id| {
accumulator
.dag()
.get(*id)
.map(|ps| ps.iter().all(|p| processed.contains(p) || !accumulator.dag().contains_key(p)))
.unwrap_or(true)
})
.cloned()
.collect();
Self { accumulator, current_head_ancestry, children_index, dag, processed, frontier }
}
pub(crate) async fn next(&mut self) -> Result<Option<EventLayer>, RetrievalError> {
if self.frontier.is_empty() {
return Ok(None);
}
let mut to_apply = Vec::new();
let mut already_applied = Vec::new();
let layer_frontier: Vec<EventId> = std::mem::take(&mut self.frontier).into_iter().collect();
for id in &layer_frontier {
if self.processed.contains(id) {
continue;
}
self.processed.insert(id.clone());
let event = self.accumulator.get_event(id).await?;
if self.current_head_ancestry.contains(id) {
already_applied.push(event);
} else {
to_apply.push(event);
}
}
let mut next_frontier = BTreeSet::new();
for id in &layer_frontier {
if let Some(children) = self.children_index.get(id) {
for child in children {
if !self.processed.contains(child) && !next_frontier.contains(child) {
let all_parents_done = self
.accumulator
.dag()
.get(child)
.map(|ps| ps.iter().all(|p| self.processed.contains(p) || !self.accumulator.dag().contains_key(p)))
.unwrap_or(false);
if all_parents_done {
next_frontier.insert(child.clone());
}
}
}
}
}
self.frontier = next_frontier;
if to_apply.is_empty() && already_applied.is_empty() {
return Ok(None);
}
Ok(Some(EventLayer { to_apply, already_applied, dag: Arc::clone(&self.dag) }))
}
}
#[derive(Debug, Clone)]
pub struct EventLayer {
pub(crate) already_applied: Vec<Event>,
pub(crate) to_apply: Vec<Event>,
dag: Arc<BTreeMap<EventId, Vec<EventId>>>,
}
impl EventLayer {
pub(crate) fn new(already_applied: Vec<Event>, to_apply: Vec<Event>, dag: Arc<BTreeMap<EventId, Vec<EventId>>>) -> Self {
Self { already_applied, to_apply, dag }
}
pub(crate) fn dag_contains(&self, id: &EventId) -> bool { self.dag.contains_key(id) }
pub(crate) fn compare(&self, a: &EventId, b: &EventId) -> CausalRelation {
if a == b {
return CausalRelation::Descends;
}
if is_descendant_dag(&self.dag, a, b) {
return CausalRelation::Descends;
}
if is_descendant_dag(&self.dag, b, a) {
return CausalRelation::Ascends;
}
CausalRelation::Concurrent
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_layer_compare() {
let mut dag = BTreeMap::new();
let a = EventId::from_bytes([1; 32]);
let b = EventId::from_bytes([2; 32]);
let c = EventId::from_bytes([3; 32]);
dag.insert(a.clone(), vec![]);
dag.insert(b.clone(), vec![a.clone()]);
dag.insert(c.clone(), vec![a.clone()]);
let layer = EventLayer { to_apply: vec![], already_applied: vec![], dag: Arc::new(dag) };
assert_eq!(layer.compare(&b, &a), CausalRelation::Descends);
assert_eq!(layer.compare(&a, &b), CausalRelation::Ascends);
assert_eq!(layer.compare(&b, &c), CausalRelation::Concurrent);
assert_eq!(layer.compare(&a, &a), CausalRelation::Descends); }
#[test]
fn test_event_layer_dag_contains() {
let mut dag = BTreeMap::new();
let a = EventId::from_bytes([1; 32]);
let b = EventId::from_bytes([2; 32]);
let c = EventId::from_bytes([3; 32]);
dag.insert(a.clone(), vec![]);
dag.insert(b.clone(), vec![a.clone()]);
let layer = EventLayer { to_apply: vec![], already_applied: vec![], dag: Arc::new(dag) };
assert!(layer.dag_contains(&a));
assert!(layer.dag_contains(&b));
assert!(!layer.dag_contains(&c)); }
}