use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt::Debug;
use std::time::Duration;
use std::{cmp, mem};
#[cfg(feature = "rkyv-support")]
use rkyv::{Archive, Deserialize, Serialize};
use crate::timestamp::HLCTimestamp;
pub type Key = u64;
pub type StateChanges = Vec<(Key, HLCTimestamp)>;
pub const FORGIVENESS_PERIOD: Duration = if cfg!(test) {
Duration::from_secs(0)
} else {
Duration::from_secs(3_600)
};
#[cfg(feature = "rkyv")]
#[derive(Debug, thiserror::Error)]
#[error("The set cannot be (de)serialized from the provided set of bytes.")]
pub struct BadState;
#[derive(Debug, Clone)]
#[repr(C)]
#[cfg_attr(feature = "rkyv", derive(Serialize, Deserialize, Archive))]
#[cfg_attr(feature = "rkyv", archive(compare(PartialEq), check_bytes))]
pub struct NodeVersions<const N: usize> {
nodes_max_stamps: [BTreeMap<u8, HLCTimestamp>; N],
safe_last_stamps: BTreeMap<u8, HLCTimestamp>,
}
impl<const N: usize> Default for NodeVersions<N> {
fn default() -> Self {
let stamps_template = [(); N];
Self {
nodes_max_stamps: stamps_template.map(|_| BTreeMap::new()),
safe_last_stamps: BTreeMap::new(),
}
}
}
impl<const N: usize> NodeVersions<N> {
fn merge(&mut self, other: NodeVersions<N>) {
let mut nodes = HashSet::new();
for (source, other_nodes) in other.nodes_max_stamps.into_iter().enumerate() {
let existing_nodes = &mut self.nodes_max_stamps[source];
for (node, ts) in other_nodes {
nodes.insert(node);
match existing_nodes.entry(node) {
Entry::Occupied(mut entry) => {
if &ts < entry.get() {
continue;
}
entry.insert(ts);
},
Entry::Vacant(v) => {
v.insert(ts);
},
}
}
}
for node in nodes {
self.compute_safe_last_stamp(node);
}
}
fn try_update_max_stamp(&mut self, source: usize, ts: HLCTimestamp) -> bool {
match self.nodes_max_stamps[source].entry(ts.node()) {
Entry::Occupied(mut entry) => {
if &ts < entry.get() {
self.compute_safe_last_stamp(ts.node());
return false;
}
entry.insert(ts);
},
Entry::Vacant(v) => {
v.insert(ts);
},
}
self.compute_safe_last_stamp(ts.node());
true
}
fn compute_safe_last_stamp(&mut self, node: u8) {
let min = self
.nodes_max_stamps
.iter()
.map(|stamps| {
stamps.get(&node).copied().unwrap_or_else(|| {
HLCTimestamp::new(Duration::from_secs(0), 0, node)
})
})
.min();
if let Some(min) = min {
let ts = HLCTimestamp::new(
min.datacake_timestamp().saturating_sub(FORGIVENESS_PERIOD),
min.counter(),
min.node(),
);
self.safe_last_stamps.insert(node, ts);
}
}
fn is_ts_before_last_observed_event(&self, ts: HLCTimestamp) -> bool {
self.safe_last_stamps
.get(&ts.node())
.map(|v| &ts < v)
.unwrap_or_default()
}
}
#[derive(Debug, Default, Clone)]
#[repr(C)]
#[cfg_attr(feature = "rkyv", derive(Serialize, Deserialize, Archive))]
#[cfg_attr(feature = "rkyv", archive(compare(PartialEq), check_bytes))]
pub struct OrSWotSet<const N: usize = 1> {
entries: BTreeMap<Key, HLCTimestamp>,
dead: HashMap<Key, HLCTimestamp>,
versions: NodeVersions<N>,
}
impl<const N: usize> OrSWotSet<N> {
#[cfg(feature = "rkyv")]
pub fn from_bytes(data: &[u8]) -> Result<Self, BadState> {
let deserialized = rkyv::from_bytes::<Self>(data).map_err(|_| BadState)?;
Ok(deserialized)
}
#[cfg(feature = "rkyv")]
pub fn as_bytes(&self) -> Result<Vec<u8>, BadState> {
Ok(rkyv::to_bytes::<_, 2048>(self)
.map_err(|_| BadState)?
.into_vec())
}
pub fn diff(&self, other: &OrSWotSet<N>) -> (StateChanges, StateChanges) {
let mut changes = Vec::new();
let mut removals = Vec::new();
for (key, ts) in other.entries.iter() {
self.check_self_then_insert_to(*key, *ts, &mut changes);
}
for (key, ts) in other.dead.iter() {
self.check_self_then_insert_to(*key, *ts, &mut removals);
}
(changes, removals)
}
fn check_self_then_insert_to(
&self,
key: Key,
ts: HLCTimestamp,
values: &mut Vec<(Key, HLCTimestamp)>,
) {
if let Some(existing_insert) = self.entries.get(&key) {
if existing_insert < &ts {
values.push((key, ts));
}
} else if let Some(existing_delete) = self.dead.get(&key) {
if existing_delete < &ts {
values.push((key, ts));
}
} else if !self.versions.is_ts_before_last_observed_event(ts) {
values.push((key, ts))
}
}
pub fn merge(&mut self, other: OrSWotSet<N>) {
let base_entries = other.entries.into_iter().map(|(k, ts)| (k, ts, false));
let remote_versions = other.versions;
let mut entries_log = Vec::from_iter(base_entries);
entries_log.extend(other.dead.into_iter().map(|(k, ts)| (k, ts, true)));
entries_log.sort_by_key(|v| v.1);
let mut old_entries = mem::take(&mut self.entries);
for (key, ts, is_delete) in entries_log {
if is_delete && self.versions.is_ts_before_last_observed_event(ts) {
continue;
}
if is_delete {
if let Some(entry) = self.entries.remove(&key) {
if ts < entry {
self.entries.insert(key, entry);
continue;
}
}
self.dead
.entry(key)
.and_modify(|v| {
(*v) = cmp::max(*v, ts);
})
.or_insert_with(|| ts);
continue;
}
let mut timestamp = ts;
if let Some(existing_ts) = old_entries.remove(&key) {
timestamp = cmp::max(timestamp, existing_ts);
}
if let Some(deleted_ts) = self.dead.remove(&key) {
if timestamp < deleted_ts {
self.dead.insert(key, deleted_ts);
continue;
}
}
self.entries.insert(key, timestamp);
}
for (key, ts) in old_entries {
if remote_versions.is_ts_before_last_observed_event(ts) {
continue;
}
if let Some(deleted) = self.dead.remove(&key) {
if ts < deleted {
self.dead.insert(key, deleted);
continue;
}
}
self.entries.insert(key, ts);
}
self.versions.merge(remote_versions);
}
pub fn get(&self, k: &Key) -> Option<&HLCTimestamp> {
self.entries.get(k)
}
pub fn purge_old_deletes(&mut self) -> StateChanges {
let mut deleted_keys = vec![];
for (k, stamp) in mem::take(&mut self.dead) {
if !self.versions.is_ts_before_last_observed_event(stamp) {
self.dead.insert(k, stamp);
} else {
deleted_keys.push((k, stamp));
}
}
deleted_keys
}
pub fn add_raw_tombstones(&mut self, tombstones: StateChanges) {
for (key, stamp) in tombstones {
self.dead.insert(key, stamp);
}
}
pub fn will_apply(&self, key: Key, ts: HLCTimestamp) -> bool {
if self.versions.is_ts_before_last_observed_event(ts) {
return false;
}
if let Some(entry) = self.entries.get(&key) {
return entry < &ts;
}
if let Some(entry) = self.dead.get(&key) {
return entry < &ts;
}
true
}
pub fn insert(&mut self, k: Key, ts: HLCTimestamp) -> bool {
self.insert_with_source(0, k, ts)
}
pub fn insert_with_source(
&mut self,
source: usize,
k: Key,
ts: HLCTimestamp,
) -> bool {
debug_assert!(source < N);
let mut has_set = false;
if !self.versions.try_update_max_stamp(source, ts) {
return has_set;
}
if let Some(deleted_ts) = self.dead.remove(&k) {
if ts < deleted_ts {
self.dead.insert(k, deleted_ts);
return has_set;
}
}
self.entries
.entry(k)
.and_modify(|v| {
if *v < ts {
has_set = true;
(*v) = ts;
}
})
.or_insert_with(|| {
has_set = true;
ts
});
has_set
}
pub fn delete(&mut self, k: Key, ts: HLCTimestamp) -> bool {
self.delete_with_source(0, k, ts)
}
pub fn delete_with_source(
&mut self,
source: usize,
k: Key,
ts: HLCTimestamp,
) -> bool {
debug_assert!(source < N);
let mut has_set = false;
if !self.versions.try_update_max_stamp(source, ts) {
return has_set;
}
if let Some(existing_ts) = self.entries.remove(&k) {
if ts <= existing_ts {
self.entries.insert(k, existing_ts);
return has_set;
}
}
self.dead
.entry(k)
.and_modify(|v| {
if *v < ts {
has_set = true;
(*v) = ts;
}
})
.or_insert_with(|| {
has_set = true;
ts
});
has_set
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::*;
#[test]
fn test_op_order() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(node_a.datacake_timestamp(), 0, 1);
let mut node_a_set = OrSWotSet::<1>::default();
let ts_a = node_a.send().unwrap();
let ts_b = node_b.send().unwrap();
node_a_set.insert(1, ts_a);
node_a_set.insert(1, ts_b);
let retrieved = node_a_set.get(&1);
assert_eq!(retrieved, Some(&ts_b), "Node B should win the operation.");
let mut node_a_set = OrSWotSet::<1>::default();
let mut node_b_set = OrSWotSet::<1>::default();
node_a_set.insert(1, ts_a);
node_b_set.insert(1, ts_b);
node_a_set.merge(node_b_set.clone());
node_b_set.merge(node_a_set.clone());
let retrieved = node_a_set.get(&1);
assert_eq!(
retrieved,
Some(&ts_b),
"Node B should win the operation after merging set A."
);
let retrieved = node_b_set.get(&1);
assert_eq!(
retrieved,
Some(&ts_b),
"Node B should win the operation after merging set B."
);
}
#[test]
fn test_basic_insert_merge() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(node_a.datacake_timestamp(), 0, 1);
let mut node_a_set = OrSWotSet::<1>::default();
node_a_set.insert(1, node_a.send().unwrap());
node_a_set.insert(2, node_a.send().unwrap());
node_a_set.insert(3, node_a.send().unwrap());
let mut node_b_set = OrSWotSet::<1>::default();
node_b_set.insert(1, node_b.send().unwrap());
node_b_set.insert(4, node_b.send().unwrap());
node_a_set.merge(node_b_set);
assert!(
node_a_set.dead.is_empty(),
"Expected no entries to be marked as dead."
);
assert!(
node_a_set.entries.get(&1).is_some(),
"Expected entry with key 1 to exist."
);
assert!(
node_a_set.entries.get(&2).is_some(),
"Expected entry with key 2 to exist."
);
assert!(
node_a_set.entries.get(&3).is_some(),
"Expected entry with key 3 to exist."
);
assert!(
node_a_set.entries.get(&4).is_some(),
"Expected entry with key 4 to exist."
);
}
#[test]
fn test_same_time_conflict_convergence() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(node_a.datacake_timestamp(), 0, 1);
let mut node_a_set = OrSWotSet::<1>::default();
node_a_set.insert(3, node_a.send().unwrap());
node_a_set.insert(1, node_a.send().unwrap());
node_a_set.insert(2, node_a.send().unwrap());
let mut node_b_set = OrSWotSet::<1>::default();
node_b_set.insert(1, node_b.send().unwrap());
node_b_set.delete(3, node_b.send().unwrap());
node_a_set.merge(node_b_set.clone());
assert!(
node_a_set.dead.contains_key(&3),
"SET A: Expected key 3 to be marked as dead."
);
assert!(
node_a_set.entries.get(&1).is_some(),
"SET A: Expected entry with key 1 to exist."
);
assert!(
node_a_set.entries.get(&2).is_some(),
"SET A: Expected entry with key 2 to exist."
);
assert!(
node_a_set.entries.get(&3).is_none(),
"SET A: Expected entry with key 3 to NOT exist."
);
node_b_set.merge(node_a_set);
assert!(
node_b_set.dead.contains_key(&3),
"SET B: Expected key 3 to be marked as dead."
);
assert!(
node_b_set.entries.get(&1).is_some(),
"SET B: Expected entry with key 1 to exist."
);
assert!(
node_b_set.entries.get(&2).is_some(),
"SET B: Expected entry with key 2 to exist."
);
assert!(
node_b_set.entries.get(&3).is_none(),
"SET B: Expected entry with key 3 to NOT exist."
);
}
#[test]
fn test_basic_delete_merge() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(
node_a.datacake_timestamp() + Duration::from_secs(1),
0,
1,
);
let mut node_a_set = OrSWotSet::<1>::default();
node_a_set.insert(1, node_a.send().unwrap());
node_a_set.insert(2, node_a.send().unwrap());
node_a_set.insert(3, node_a.send().unwrap());
let mut node_b_set = OrSWotSet::<1>::default();
node_b_set.insert(1, node_b.send().unwrap());
node_b_set.delete(3, node_b.send().unwrap());
node_a_set.merge(node_b_set.clone());
assert!(
node_a_set.dead.contains_key(&3),
"Expected key 3 to be marked as dead."
);
assert!(
node_a_set.entries.get(&1).is_some(),
"Expected entry with key 1 to exist."
);
assert!(
node_a_set.entries.get(&2).is_some(),
"Expected entry with key 2 to exist."
);
assert!(
node_a_set.entries.get(&3).is_none(),
"Expected entry with key 3 to NOT exist."
);
}
#[test]
fn test_purge_delete_merge() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(
node_a.datacake_timestamp() + Duration::from_secs(1),
0,
1,
);
let mut node_a_set = OrSWotSet::<1>::default();
node_a_set.insert(1, node_a.send().unwrap());
node_a_set.insert(2, node_a.send().unwrap());
node_a_set.insert(3, node_a.send().unwrap());
let mut node_b_set = OrSWotSet::<1>::default();
node_b_set.insert(1, node_b.send().unwrap());
node_b_set.delete(3, node_b.send().unwrap());
node_a_set.merge(node_b_set.clone());
node_a_set.insert(4, node_a.send().unwrap());
node_b_set.insert(4, node_b.send().unwrap());
node_a_set.merge(node_b_set.clone());
node_a_set.purge_old_deletes();
assert!(
node_a_set.dead.is_empty(),
"Expected dead entries to be empty."
);
assert!(
node_a_set.entries.get(&1).is_some(),
"Expected entry with key 1 to exist."
);
assert!(
node_a_set.entries.get(&2).is_some(),
"Expected entry with key 2 to exist."
);
assert!(
node_a_set.entries.get(&3).is_none(),
"Expected entry with key 3 to NOT exist."
);
assert!(
node_a_set.entries.get(&4).is_some(),
"Expected entry with key 4 to exist."
);
}
#[test]
fn test_purge_some_entries() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(
node_a.datacake_timestamp() + Duration::from_secs(1),
0,
1,
);
let mut node_a_set = OrSWotSet::<1>::default();
node_a_set.insert(1, node_a.send().unwrap());
node_a_set.insert(2, node_a.send().unwrap());
node_a_set.insert(3, node_a.send().unwrap());
std::thread::sleep(Duration::from_millis(1));
let mut node_b_set = OrSWotSet::<1>::default();
node_b_set.insert(1, node_b.send().unwrap());
node_b_set.delete(3, node_b.send().unwrap());
node_a_set.merge(node_b_set.clone());
node_a_set.insert(4, node_a.send().unwrap());
node_a_set.delete(2, node_a.send().unwrap());
node_a_set.insert(5, node_a.send().unwrap());
node_a_set.merge(node_b_set.clone());
node_a_set.purge_old_deletes();
node_b_set.merge(node_a_set.clone());
node_a_set.purge_old_deletes();
assert!(
node_a_set.dead.get(&3).is_some(),
"SET A: Expected key 3 to be left in dead set."
);
assert!(
node_a_set.dead.get(&2).is_none(),
"SET A: Expected key 2 to be purged from dead set."
);
assert!(
node_a_set.entries.get(&1).is_some(),
"SET A: Expected entry with key 1 to exist."
);
assert!(
node_a_set.entries.get(&2).is_none(),
"SET A: Expected entry with key 2 to exist."
);
assert!(
node_a_set.entries.get(&3).is_none(),
"SET A: Expected entry with key 3 to NOT exist."
);
assert!(
node_a_set.entries.get(&4).is_some(),
"SET A: Expected entry with key 4 to exist."
);
assert!(
node_b_set.dead.get(&3).is_some(),
"SET B: Expected key 3 to be left in dead set."
);
assert!(
node_b_set.dead.get(&2).is_none(),
"SET B: Expected key 2 to be purged from dead set."
);
assert!(
node_b_set.entries.get(&1).is_some(),
"SET B: Expected entry with key 1 to exist."
);
assert!(
node_b_set.entries.get(&2).is_none(),
"SET B: Expected entry with key 2 to exist."
);
assert!(
node_b_set.entries.get(&3).is_none(),
"SET B: Expected entry with key 3 to NOT exist."
);
assert!(
node_b_set.entries.get(&4).is_some(),
"SET B: Expected entry with key 4 to exist."
);
}
#[test]
fn test_insert_no_op() {
let mut node_a = HLCTimestamp::now(0, 0);
let old_ts = node_a.send().unwrap();
let mut node_a_set = OrSWotSet::<1>::default();
let did_add = node_a_set.insert(1, node_a.send().unwrap());
assert!(did_add, "Expected entry insert to be added.");
let did_add = node_a_set.insert(1, old_ts);
assert!(
!did_add,
"Expected entry insert with old timestamp to be ignored"
);
}
#[test]
fn test_delete_no_op() {
let mut node_a = HLCTimestamp::now(0, 0);
let old_ts = node_a.send().unwrap();
let mut node_a_set = OrSWotSet::<1>::default();
let did_add = node_a_set.insert(1, node_a.send().unwrap());
assert!(did_add, "Expected entry insert to be added.");
let did_add = node_a_set.delete(1, old_ts);
assert!(
!did_add,
"Expected entry delete with old timestamp to be ignored"
);
}
#[test]
fn test_set_diff() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(
node_a.datacake_timestamp() + Duration::from_secs(5),
0,
1,
);
let mut node_a_set = OrSWotSet::<1>::default();
let mut node_b_set = OrSWotSet::<1>::default();
let insert_ts_1 = node_a.send().unwrap();
node_a_set.insert(1, insert_ts_1);
let (changed, removed) = OrSWotSet::<1>::default().diff(&node_a_set);
assert_eq!(
changed,
vec![(1, insert_ts_1)],
"Expected set diff to contain key `1`."
);
assert!(
removed.is_empty(),
"Expected there to be no difference between sets."
);
let delete_ts_3 = node_a.send().unwrap();
node_a_set.delete(3, delete_ts_3);
let insert_ts_2 = node_b.send().unwrap();
node_b_set.insert(2, insert_ts_2);
let (changed, removed) = node_a_set.diff(&node_b_set);
assert_eq!(
changed,
vec![(2, insert_ts_2)],
"Expected set a to only be marked as missing key `2`"
);
assert!(
removed.is_empty(),
"Expected set a to not be missing any delete markers."
);
let (changed, removed) = node_b_set.diff(&node_a_set);
assert_eq!(
changed,
vec![(1, insert_ts_1)],
"Expected set b to have key `1` marked as changed."
);
assert_eq!(
removed,
vec![(3, delete_ts_3)],
"Expected set b to have key `3` marked as deleted."
);
}
#[test]
fn test_set_diff_with_conflicts() {
let mut node_a = HLCTimestamp::now(0, 0);
let mut node_b = HLCTimestamp::new(
node_a.datacake_timestamp() + Duration::from_secs(5),
0,
1,
);
let mut node_a_set = OrSWotSet::<1>::default();
let mut node_b_set = OrSWotSet::<1>::default();
node_a_set.insert(1, node_a.send().unwrap());
node_a_set.insert(2, node_a.send().unwrap());
std::thread::sleep(Duration::from_millis(500));
let delete_ts_3 = node_a.send().unwrap();
node_a_set.delete(3, delete_ts_3);
let insert_ts_2 = node_b.send().unwrap();
node_b_set.insert(2, insert_ts_2);
let insert_ts_1 = node_b.send().unwrap();
node_b_set.insert(1, insert_ts_1);
let (changed, removed) = node_a_set.diff(&node_b_set);
assert_eq!(
changed,
vec![(1, insert_ts_1), (2, insert_ts_2)],
"Expected set a to be marked as updating keys `1, 2`"
);
assert!(
removed.is_empty(),
"Expected set a to not be missing any delete markers."
);
let (changed, removed) = node_b_set.diff(&node_a_set);
assert_eq!(
changed,
vec![],
"Expected set b to have no changed keys marked."
);
assert_eq!(
removed,
vec![(3, delete_ts_3)],
"Expected set b to have key `3` marked as deleted."
);
}
#[test]
fn test_tie_breakers() {
let node_a = HLCTimestamp::now(0, 0);
let node_b = HLCTimestamp::new(node_a.datacake_timestamp(), 0, 1);
let mut node_a_set = OrSWotSet::<1>::default();
let mut node_b_set = OrSWotSet::<1>::default();
node_a_set.insert(1, node_a);
node_b_set.delete(1, node_b);
let (changed, removed) = node_a_set.diff(&node_b_set);
assert_eq!(changed, vec![]);
assert_eq!(removed, vec![(1, node_b)]);
let (changed, removed) = node_b_set.diff(&node_a_set);
assert_eq!(changed, vec![]);
assert_eq!(removed, vec![]);
node_a_set.merge(node_b_set.clone());
node_b_set.merge(node_a_set.clone());
assert!(
node_a_set.get(&1).is_none(),
"Set a should no longer have key 1."
);
assert!(node_b_set.get(&1).is_none(), "Set b should not have key 1.");
let (changed, removed) = node_b_set.diff(&node_a_set);
assert_eq!(changed, vec![]);
assert_eq!(removed, vec![]);
let (changed, removed) = node_a_set.diff(&node_b_set);
assert_eq!(changed, vec![]);
assert_eq!(removed, vec![]);
let has_changed = node_a_set.insert(1, node_a);
assert!(!has_changed, "Set a should not insert the value.");
let has_changed = node_b_set.insert(1, node_a);
assert!(
!has_changed,
"Set b should not insert the value with node a's timestamp."
);
let has_changed = node_a_set.insert(1, node_b);
assert!(
has_changed,
"Set a should insert the value with node b's timestamp."
);
let has_changed = node_b_set.insert(1, node_b);
assert!(has_changed, "Set b should insert the value.");
let mut node_a_set = OrSWotSet::<1>::default();
let mut node_b_set = OrSWotSet::<1>::default();
node_a_set.delete(1, node_a);
node_b_set.insert(1, node_b);
let (changed, removed) = node_a_set.diff(&node_b_set);
assert_eq!(changed, vec![(1, node_b)]);
assert_eq!(removed, vec![]);
let (changed, removed) = node_b_set.diff(&node_a_set);
assert_eq!(changed, vec![]);
assert_eq!(removed, vec![]);
node_a_set.merge(node_b_set.clone());
node_b_set.merge(node_a_set.clone());
assert!(
node_a_set.get(&1).is_some(),
"Set a should no longer have key 1."
);
assert!(node_b_set.get(&1).is_some(), "Set b should not have key 1.");
}
#[test]
fn test_multi_source_handling() {
let mut clock = HLCTimestamp::now(0, 0);
let mut node_set = OrSWotSet::<1>::default();
node_set.insert_with_source(0, 1, clock.send().unwrap());
node_set.delete_with_source(0, 1, clock.send().unwrap());
node_set.insert_with_source(0, 3, clock.send().unwrap());
node_set.insert_with_source(0, 4, clock.send().unwrap());
let purged = node_set
.purge_old_deletes()
.into_iter()
.map(|(key, _)| key)
.collect::<Vec<_>>();
assert_eq!(purged, vec![1]);
let mut node_set = OrSWotSet::<2>::default();
node_set.insert_with_source(0, 1, clock.send().unwrap());
node_set.insert_with_source(1, 2, clock.send().unwrap());
node_set.delete_with_source(0, 1, clock.send().unwrap());
node_set.insert_with_source(0, 3, clock.send().unwrap());
node_set.insert_with_source(0, 4, clock.send().unwrap());
let purged = node_set.purge_old_deletes();
assert!(purged.is_empty());
node_set.insert_with_source(1, 3, clock.send().unwrap());
let purged = node_set
.purge_old_deletes()
.into_iter()
.map(|(key, _)| key)
.collect::<Vec<_>>();
assert_eq!(purged, vec![1]);
let old_ts = clock.send().unwrap();
let initial_ts = clock.send().unwrap();
assert!(node_set.delete_with_source(0, 4, initial_ts));
assert!(node_set.delete_with_source(1, 3, old_ts));
assert!(!node_set.delete_with_source(0, 3, old_ts));
assert!(node_set.insert_with_source(0, 5, initial_ts));
assert!(node_set.insert_with_source(1, 6, old_ts));
assert!(!node_set.insert_with_source(0, 5, old_ts));
assert!(node_set.insert_with_source(0, 6, initial_ts));
assert!(node_set.delete_with_source(1, 4, clock.send().unwrap()));
assert!(node_set.delete_with_source(0, 3, clock.send().unwrap()));
assert!(!node_set.delete_with_source(1, 4, initial_ts));
}
#[test]
fn test_will_apply() {
let ts = Duration::from_secs(1);
let mut node_set = OrSWotSet::<1>::default();
assert!(node_set.will_apply(1, HLCTimestamp::new(ts, 0, 0)));
node_set.insert(1, HLCTimestamp::new(ts, 0, 0));
assert!(!node_set.will_apply(1, HLCTimestamp::new(ts, 0, 0)));
assert!(node_set.will_apply(3, HLCTimestamp::new(Duration::from_secs(3), 0, 0)));
node_set.delete(3, HLCTimestamp::new(Duration::from_secs(5), 0, 0));
assert!(!node_set.will_apply(3, HLCTimestamp::new(Duration::from_secs(4), 0, 0)));
}
}