Skip to main content

shuttle_engine/runtime/task/
clock.rs

1use crate::runtime::task::TaskId;
2use std::cmp::{Ordering, PartialOrd};
3
4#[cfg(all(any(test, feature = "vector-clocks"), not(feature = "bench-no-vector-clocks")))]
5mod vector_clock {
6    use super::*;
7    use crate::runtime::task::DEFAULT_INLINE_TASKS;
8    use smallvec::{smallvec, SmallVec};
9
10    #[derive(Clone, Debug, PartialEq, Eq)]
11    pub struct VectorClock {
12        pub time: SmallVec<[u32; DEFAULT_INLINE_TASKS]>,
13    }
14
15    impl VectorClock {
16        pub const fn new() -> Self {
17            Self {
18                time: SmallVec::new_const(),
19            }
20        }
21
22        // Zero extend clock to accommodate `task_id` tasks.
23        pub fn extend(&mut self, task_id: TaskId) {
24            let num_new_tasks = 1 + task_id.0 - self.time.len();
25            let clock: SmallVec<[_; DEFAULT_INLINE_TASKS]> = smallvec![0u32; num_new_tasks];
26            self.time.extend_from_slice(&clock);
27        }
28
29        pub fn increment(&mut self, task_id: TaskId) {
30            self.time[task_id.0] += 1;
31        }
32
33        // Update the clock of `self` with the clock from `other`
34        pub fn update(&mut self, other: &Self) {
35            let n1 = self.time.len();
36            let n2 = other.time.len();
37            for i in 0..n1.min(n2) {
38                self.time[i] = self.time[i].max(other.time[i])
39            }
40            for i in n1..n2 {
41                // could be empty
42                self.time.push(other.time[i]);
43            }
44        }
45
46        pub fn get(&self, i: usize) -> u32 {
47            self.time[i]
48        }
49    }
50
51    impl<const N: usize> From<&[u32; N]> for VectorClock {
52        fn from(v: &[u32; N]) -> Self {
53            Self {
54                time: SmallVec::from(&v[..]),
55            }
56        }
57    }
58
59    impl From<&[u32]> for VectorClock {
60        fn from(v: &[u32]) -> Self {
61            Self {
62                time: SmallVec::from(v),
63            }
64        }
65    }
66
67    impl std::ops::Deref for VectorClock {
68        type Target = [u32];
69        fn deref(&self) -> &Self::Target {
70            &self.time[..]
71        }
72    }
73
74    fn unify(a: Ordering, b: Ordering) -> Option<Ordering> {
75        use Ordering::*;
76
77        match (a, b) {
78            (Equal, Equal) => Some(Equal),
79            (Less, Greater) | (Greater, Less) => None,
80            (Less, _) | (_, Less) => Some(Less),
81            (Greater, _) | (_, Greater) => Some(Greater),
82        }
83    }
84
85    impl PartialOrd for VectorClock {
86        // Compare vector clocks
87        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
88            let n1 = self.time.len();
89            let n2 = other.time.len();
90            // if (n1<n2), then other can't have happened before self, similarly for (n1>n2)
91            let mut ord = n1.cmp(&n2);
92            for i in 0..n1.min(n2) {
93                ord = unify(ord, self.time[i].cmp(&other.time[i]))?; // return if incomparable
94            }
95            Some(ord)
96        }
97    }
98}
99
100/// A dummy VectorClock implementation which only provides no-op stubs to improve testing throughput when
101/// vector clocks are not necessary
102#[cfg(any(not(any(test, feature = "vector-clocks")), feature = "bench-no-vector-clocks"))]
103mod vector_clock {
104    use super::*;
105
106    #[derive(Clone, Debug, PartialEq, Eq)]
107    pub struct VectorClock;
108
109    impl VectorClock {
110        pub const fn new() -> Self {
111            Self
112        }
113
114        pub fn extend(&mut self, _task_id: TaskId) {
115            // No-op when vector clocks are disabled
116        }
117
118        pub fn increment(&mut self, _task_id: TaskId) {
119            // No-op when vector clocks are disabled
120        }
121
122        pub fn update(&mut self, _other: &Self) {
123            // No-op when vector clocks are disabled
124        }
125
126        pub fn get(&self, _i: usize) -> u32 {
127            0
128        }
129    }
130
131    impl<const N: usize> From<&[u32; N]> for VectorClock {
132        fn from(_v: &[u32; N]) -> Self {
133            Self
134        }
135    }
136
137    impl From<&[u32]> for VectorClock {
138        fn from(_v: &[u32]) -> Self {
139            Self
140        }
141    }
142
143    impl std::ops::Deref for VectorClock {
144        type Target = [u32];
145        fn deref(&self) -> &Self::Target {
146            &[]
147        }
148    }
149
150    impl PartialOrd for VectorClock {
151        fn partial_cmp(&self, _other: &Self) -> Option<Ordering> {
152            Some(Ordering::Equal)
153        }
154    }
155}
156
157pub use vector_clock::VectorClock;
158
159#[cfg(test)]
160mod test {
161    use super::*;
162
163    #[test]
164    fn vector_clock() {
165        let v1 = VectorClock::from(&[1, 2, 3, 4]);
166        let v2 = VectorClock::from(&[1, 2, 4, 5]);
167        let v3 = VectorClock::from(&[1, 2, 3, 1]);
168        let v4 = VectorClock::from(&[1, 2, 4, 1]);
169        let v5 = VectorClock::from(&[1, 2, 3, 4]);
170        assert!(v1 < v2 && v1 > v3 && v1 == v5);
171        assert!(v2 > v3 && v2 > v4);
172        assert!(v3 < v4);
173        assert_eq!(v1.partial_cmp(&v4), None);
174
175        let v1 = VectorClock::from(&[1, 2, 3, 4]);
176        let v2 = VectorClock::from(&[1, 2, 2]);
177        let v3 = VectorClock::from(&[1, 2, 3]);
178        let v4 = VectorClock::from(&[1, 2, 4]);
179        assert!(v1 > v2);
180        assert!(v1 > v3);
181        assert_eq!(v1.partial_cmp(&v4), None);
182
183        let v1 = VectorClock::from(&[]);
184        let v2 = VectorClock::from(&[1]);
185        assert!(v1 < v2);
186
187        let v1 = VectorClock::from(&[1, 2, 1]);
188        let v2 = VectorClock::from(&[1, 3]);
189        let v3 = VectorClock::from(&[1, 1, 1, 2]);
190        let v4 = VectorClock::from(&[1, 1, 2]);
191
192        let mut v = v1.clone();
193        v.update(&v2);
194        assert_eq!(v, VectorClock::from(&[1, 3, 1]));
195
196        let mut v = v1.clone();
197        v.update(&v3);
198        assert_eq!(v, VectorClock::from(&[1, 2, 1, 2]));
199
200        let mut v = v1.clone();
201        v.update(&v4);
202        assert_eq!(v, VectorClock::from(&[1, 2, 2]));
203
204        let mut v = v1.clone();
205        v.update(&VectorClock::new());
206        assert_eq!(v, v1);
207    }
208}