1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
//! Wall-clock time as this node sees it, in Unix milliseconds: commit stamps, alive
//! stamps, remake deadlines and votes, archive and quarantine times.
//!
//! Every such reading goes through the node's [`Clock`], so tests can put one node's
//! clock ahead of or behind the others (`docs/trust.md`, "What depends on clocks").
//! Elapsed time within a node (timeouts, keepalives) uses tokio's monotonic clock and
//! isn't affected.
use std::sync::atomic::{AtomicI64, Ordering};
/// The node's wall clock: the system clock plus an offset (zero outside tests).
#[derive(Debug, Default)]
pub(crate) struct Clock {
offset_ms: AtomicI64,
}
impl Clock {
/// Now, in Unix milliseconds.
pub(crate) fn now_millis(&self) -> u64 {
let offset = self.offset_ms.load(Ordering::Relaxed);
system_millis().saturating_add_signed(offset)
}
/// Puts this clock `offset_ms` ahead of the system clock (behind if negative).
#[cfg(test)]
pub(crate) fn set_offset_ms(&self, offset_ms: i64) {
self.offset_ms.store(offset_ms, Ordering::Relaxed);
}
}
/// The system clock, in Unix milliseconds; 0 if it is before 1970.
fn system_millis() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn offset_moves_the_clock() {
let clock = Clock::default();
let before = clock.now_millis();
clock.set_offset_ms(3_600_000);
let ahead = clock.now_millis();
assert!(ahead >= before + 3_600_000);
clock.set_offset_ms(-3_600_000);
assert!(clock.now_millis() < before);
}
}
|