use super::super::replica::ReplicaId;
use super::super::Merge;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct VClock {
entries: HashMap<ReplicaId, u64>,
}
impl VClock {
pub fn new() -> Self {
Self::default()
}
pub fn increment(&mut self, replica: ReplicaId) -> u64 {
let entry = self.entries.entry(replica).or_insert(0);
*entry += 1;
*entry
}
pub fn get(&self, replica: ReplicaId) -> u64 {
*self.entries.get(&replica).unwrap_or(&0)
}
pub fn dominates(&self, other: &Self) -> bool {
for (&replica, &count) in &other.entries {
if self.get(replica) < count {
return false;
}
}
true
}
pub fn concurrent(&self, other: &Self) -> bool {
!self.dominates(other) && !other.dominates(self)
}
pub fn merge_vclock(&mut self, other: &Self) {
for (&replica, &count) in &other.entries {
let entry = self.entries.entry(replica).or_insert(0);
*entry = (*entry).max(count);
}
}
pub fn replicas(&self) -> impl Iterator<Item = &ReplicaId> {
self.entries.keys()
}
}
impl Merge for VClock {
fn merge(&mut self, other: &Self) {
self.merge_vclock(other);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vclock_new() {
let clock = VClock::new();
assert_eq!(clock.get(42), 0);
}
#[test]
fn test_vclock_increment() {
let mut clock = VClock::new();
assert_eq!(clock.increment(42), 1);
assert_eq!(clock.increment(42), 2);
assert_eq!(clock.get(42), 2);
}
#[test]
fn test_vclock_merge() {
let mut a = VClock::new();
let mut b = VClock::new();
a.increment(1);
a.increment(1);
b.increment(2);
a.merge(&b);
assert_eq!(a.get(1), 2);
assert_eq!(a.get(2), 1);
}
#[test]
fn test_vclock_dominates() {
let mut a = VClock::new();
let mut b = VClock::new();
a.increment(1);
a.increment(1);
b.increment(1);
assert!(a.dominates(&b));
assert!(!b.dominates(&a));
}
#[test]
fn test_vclock_concurrent() {
let mut a = VClock::new();
let mut b = VClock::new();
a.increment(1);
b.increment(2);
assert!(a.concurrent(&b));
}
}