use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::collections::HashMap;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct VectorClock {
clocks: HashMap<String, u64>,
server_ids: Vec<String>,
}
impl VectorClock {
pub fn new(server_ids: &[&str]) -> Self {
let mut clocks = HashMap::new();
let server_ids: Vec<String> = server_ids.iter().map(|s| s.to_string()).collect();
for server_id in &server_ids {
clocks.insert(server_id.clone(), 0);
}
VectorClock { clocks, server_ids }
}
pub fn increment(&mut self, server_id: &str) {
if let Some(clock) = self.clocks.get_mut(server_id) {
*clock += 1;
} else {
panic!("Unknown server_id: {}", server_id);
}
}
pub fn merge(&mut self, other: &VectorClock) {
for server_id in &self.server_ids {
let other_time = other.clocks.get(server_id).copied().unwrap_or(0);
let self_time = self.clocks.get(server_id).copied().unwrap_or(0);
self.clocks
.insert(server_id.clone(), self_time.max(other_time));
}
}
pub fn get(&self, server_id: &str) -> u64 {
self.clocks.get(server_id).copied().unwrap_or(0)
}
pub fn compare(&self, other: &VectorClock) -> Option<Ordering> {
let mut has_less = false;
let mut has_greater = false;
for server_id in &self.server_ids {
let self_time = self.clocks.get(server_id).copied().unwrap_or(0);
let other_time = other.clocks.get(server_id).copied().unwrap_or(0);
match self_time.cmp(&other_time) {
Ordering::Less => has_less = true,
Ordering::Greater => has_greater = true,
Ordering::Equal => {}
}
}
match (has_less, has_greater) {
(false, false) => Some(Ordering::Equal),
(true, false) => Some(Ordering::Less),
(false, true) => Some(Ordering::Greater),
(true, true) => None, }
}
pub fn happens_before(&self, other: &VectorClock) -> Option<bool> {
self.compare(other).map(|ord| ord == Ordering::Less)
}
pub fn happens_after(&self, other: &VectorClock) -> Option<bool> {
self.compare(other).map(|ord| ord == Ordering::Greater)
}
pub fn is_concurrent(&self, other: &VectorClock) -> bool {
self.compare(other).is_none()
}
pub fn server_ids(&self) -> &[String] {
&self.server_ids
}
pub fn as_vec(&self) -> Vec<(String, u64)> {
let mut result: Vec<_> = self.clocks.iter().map(|(k, v)| (k.clone(), *v)).collect();
result.sort_by(|a, b| a.0.cmp(&b.0));
result
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct VersionedValue<T: Clone> {
pub value: T,
pub version: VectorClock,
pub last_modified_by: String,
}
impl<T: Clone> VersionedValue<T> {
pub fn new(value: T, version: VectorClock, last_modified_by: String) -> Self {
VersionedValue {
value,
version,
last_modified_by,
}
}
pub fn happens_before(&self, other: &VersionedValue<T>) -> Option<bool> {
self.version.happens_before(&other.version)
}
pub fn is_concurrent(&self, other: &VersionedValue<T>) -> bool {
self.version.is_concurrent(&other.version)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum ConflictResolution<T: Clone> {
HighestLogicalTime,
ServerPriority,
ApplicationDefined(Vec<T>),
}
#[derive(Clone, Debug)]
pub enum WriteResult<T: Clone> {
Applied,
Ignored,
Conflict(Vec<T>),
}
pub type MergeFn<T> = fn(&VersionedValue<T>, &VersionedValue<T>) -> VersionedValue<T>;
pub fn apply_remote_write<T: Clone>(
local: &VersionedValue<T>,
remote: &VersionedValue<T>,
resolve_conflict: MergeFn<T>,
) -> (VersionedValue<T>, bool) {
match local.version.compare(&remote.version) {
Some(Ordering::Less) => {
(remote.clone(), true)
}
Some(Ordering::Greater) | Some(Ordering::Equal) => {
(local.clone(), false)
}
None => {
let resolved = resolve_conflict(local, remote);
(resolved, true)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vector_clock_creation() {
let vc = VectorClock::new(&["server1", "server2", "server3"]);
assert_eq!(vc.get("server1"), 0);
assert_eq!(vc.get("server2"), 0);
assert_eq!(vc.get("server3"), 0);
}
#[test]
fn test_vector_clock_increment() {
let mut vc = VectorClock::new(&["server1", "server2"]);
vc.increment("server1");
assert_eq!(vc.get("server1"), 1);
assert_eq!(vc.get("server2"), 0);
vc.increment("server1");
assert_eq!(vc.get("server1"), 2);
}
#[test]
fn test_vector_clock_happens_before() {
let mut vc1 = VectorClock::new(&["server1", "server2"]);
let mut vc2 = VectorClock::new(&["server1", "server2"]);
vc1.increment("server1");
vc1.merge(&vc2);
vc2.increment("server1");
vc2.increment("server2");
assert_eq!(vc1.happens_before(&vc2), Some(true));
assert_eq!(vc2.happens_before(&vc1), Some(false));
}
#[test]
fn test_vector_clock_concurrent() {
let mut vc1 = VectorClock::new(&["server1", "server2"]);
let mut vc2 = VectorClock::new(&["server1", "server2"]);
vc1.increment("server1");
vc2.increment("server2");
assert!(vc1.is_concurrent(&vc2));
assert!(vc2.is_concurrent(&vc1));
assert_eq!(vc1.compare(&vc2), None);
}
#[test]
fn test_vector_clock_merge() {
let mut vc1 = VectorClock::new(&["server1", "server2"]);
let mut vc2 = VectorClock::new(&["server1", "server2"]);
vc1.increment("server1");
vc1.increment("server1");
vc2.increment("server2");
vc1.merge(&vc2);
assert_eq!(vc1.get("server1"), 2);
assert_eq!(vc1.get("server2"), 1);
}
#[test]
fn test_vector_clock_equality() {
let mut vc1 = VectorClock::new(&["server1", "server2"]);
let mut vc2 = VectorClock::new(&["server1", "server2"]);
vc1.increment("server1");
vc2.increment("server1");
assert_eq!(vc1, vc2);
assert_eq!(vc1.compare(&vc2), Some(Ordering::Equal));
}
#[test]
fn test_versioned_value() {
let vc = VectorClock::new(&["server1", "server2"]);
let v = VersionedValue::new(42, vc, "server1".to_string());
assert_eq!(v.value, 42);
assert_eq!(v.last_modified_by, "server1");
}
#[test]
fn test_apply_remote_write_happens_before() {
let mut local_vc = VectorClock::new(&["server1", "server2"]);
let mut remote_vc = VectorClock::new(&["server1", "server2"]);
local_vc.increment("server1");
local_vc.merge(&remote_vc);
remote_vc.increment("server1");
remote_vc.increment("server2");
let local = VersionedValue::new(10, local_vc, "server1".to_string());
let remote = VersionedValue::new(20, remote_vc, "server2".to_string());
let resolve = |_l: &VersionedValue<i32>, r: &VersionedValue<i32>| r.clone();
let (result, changed) = apply_remote_write(&local, &remote, resolve);
assert!(changed);
assert_eq!(result.value, 20);
}
#[test]
fn test_apply_remote_write_happens_after() {
let mut local_vc = VectorClock::new(&["server1", "server2"]);
let mut remote_vc = VectorClock::new(&["server1", "server2"]);
remote_vc.increment("server1");
local_vc.increment("server1");
local_vc.increment("server2");
let local = VersionedValue::new(10, local_vc, "server2".to_string());
let remote = VersionedValue::new(20, remote_vc, "server1".to_string());
let resolve = |_l: &VersionedValue<i32>, r: &VersionedValue<i32>| r.clone();
let (result, changed) = apply_remote_write(&local, &remote, resolve);
assert!(!changed);
assert_eq!(result.value, 10);
}
#[test]
fn test_apply_remote_write_concurrent() {
let mut local_vc = VectorClock::new(&["server1", "server2"]);
let mut remote_vc = VectorClock::new(&["server1", "server2"]);
local_vc.increment("server1");
remote_vc.increment("server2");
let local = VersionedValue::new(10, local_vc, "server1".to_string());
let remote = VersionedValue::new(20, remote_vc, "server2".to_string());
let resolve = |_l: &VersionedValue<i32>, r: &VersionedValue<i32>| r.clone();
let (result, changed) = apply_remote_write(&local, &remote, resolve);
assert!(changed);
assert_eq!(result.value, 20); }
#[test]
fn test_vector_clock_as_vec() {
let mut vc = VectorClock::new(&["server1", "server2", "server3"]);
vc.increment("server1");
vc.increment("server3");
let vec = vc.as_vec();
assert_eq!(vec.len(), 3);
assert_eq!(vec[0], ("server1".to_string(), 1));
assert_eq!(vec[1], ("server2".to_string(), 0));
assert_eq!(vec[2], ("server3".to_string(), 1));
}
#[test]
fn test_causality_chain() {
let mut vc1 = VectorClock::new(&["server1", "server2"]);
let mut vc2 = VectorClock::new(&["server1", "server2"]);
let mut vc3 = VectorClock::new(&["server1", "server2"]);
vc1.increment("server1");
vc2.merge(&vc1);
vc2.increment("server2");
vc3.merge(&vc2);
vc3.increment("server1");
assert_eq!(vc1.happens_before(&vc2), Some(true));
assert_eq!(vc2.happens_before(&vc3), Some(true));
assert_eq!(vc1.happens_before(&vc3), Some(true));
}
#[test]
fn test_multiple_concurrent_events() {
let mut vc1 = VectorClock::new(&["server1", "server2", "server3"]);
let mut vc2 = VectorClock::new(&["server1", "server2", "server3"]);
let mut vc3 = VectorClock::new(&["server1", "server2", "server3"]);
vc1.increment("server1");
vc2.increment("server2");
vc3.increment("server3");
assert!(vc1.is_concurrent(&vc2));
assert!(vc2.is_concurrent(&vc3));
assert!(vc1.is_concurrent(&vc3));
}
}