Skip to main content

synckit_core/sync/
mod.rs

1//! Synchronization primitives
2//!
3//! This module contains the core synchronization algorithms:
4//! - Vector clocks for causality tracking
5//! - Timestamps for LWW conflict resolution
6//! - LWW merge algorithm
7//! - Delta computation
8
9pub mod delta;
10pub mod lww;
11pub mod vector_clock;
12
13pub use delta::{apply_delta, compute_delta, merge_deltas, Delta};
14pub use lww::LWWField;
15pub use vector_clock::VectorClock;
16
17use crate::ClientID;
18use serde::{Deserialize, Serialize};
19
20/// Timestamp for Last-Write-Wins conflict resolution
21///
22/// Contains both a logical clock value and a client ID for deterministic tie-breaking.
23/// This ensures that concurrent writes to the same field converge to the same value
24/// across all replicas.
25#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
26pub struct Timestamp {
27    /// Logical clock value (higher = more recent)
28    pub clock: u64,
29
30    /// Client ID for tie-breaking when clocks are equal
31    pub client_id: ClientID,
32}
33
34impl Timestamp {
35    /// Create a new timestamp
36    pub fn new(clock: u64, client_id: ClientID) -> Self {
37        Self { clock, client_id }
38    }
39
40    /// Compare two timestamps for LWW conflict resolution
41    ///
42    /// Returns:
43    /// - Ordering::Greater if self is more recent
44    /// - Ordering::Less if other is more recent
45    /// - Ordering::Equal if timestamps are identical (same clock and client)
46    pub fn compare_lww(&self, other: &Timestamp) -> std::cmp::Ordering {
47        match self.clock.cmp(&other.clock) {
48            std::cmp::Ordering::Equal => {
49                // Tie-breaking by client ID (deterministic)
50                self.client_id.cmp(&other.client_id)
51            }
52            ordering => ordering,
53        }
54    }
55
56    /// Check if this timestamp is more recent than another (for LWW)
57    pub fn is_newer_than(&self, other: &Timestamp) -> bool {
58        self.compare_lww(other) == std::cmp::Ordering::Greater
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_timestamp_comparison() {
68        let ts1 = Timestamp::new(1, "c1".to_string());
69        let ts2 = Timestamp::new(2, "c1".to_string());
70
71        // Higher clock wins
72        assert!(ts2.is_newer_than(&ts1));
73        assert!(!ts1.is_newer_than(&ts2));
74    }
75
76    #[test]
77    fn test_timestamp_tie_breaking() {
78        let ts1 = Timestamp::new(1, "c1".to_string());
79        let ts2 = Timestamp::new(1, "c2".to_string());
80
81        // Same clock, break tie by client ID
82        // "c2" > "c1" lexicographically
83        assert!(ts2.is_newer_than(&ts1));
84        assert!(!ts1.is_newer_than(&ts2));
85    }
86
87    #[test]
88    fn test_timestamp_equality() {
89        let ts1 = Timestamp::new(1, "c1".to_string());
90        let ts2 = Timestamp::new(1, "c1".to_string());
91
92        assert_eq!(ts1.compare_lww(&ts2), std::cmp::Ordering::Equal);
93        assert!(!ts1.is_newer_than(&ts2));
94        assert!(!ts2.is_newer_than(&ts1));
95    }
96}