query_runtime/observability/
clock.rs1use std::{
4 sync::atomic::{AtomicU64, Ordering},
5 time::{Instant, SystemTime, UNIX_EPOCH},
6};
7
8pub trait RuntimeObservationClock: Send + Sync + 'static {
10 fn monotonic_ns(&self) -> u64;
12
13 fn unix_epoch_ns(&self) -> Option<u64>;
15}
16
17#[derive(Debug)]
19pub(crate) struct SystemRuntimeObservationClock {
20 origin: Instant,
21 unix_epoch_ns: Option<u64>,
22}
23
24impl SystemRuntimeObservationClock {
25 pub fn new() -> Self {
27 let unix_epoch_ns = SystemTime::now()
28 .duration_since(UNIX_EPOCH)
29 .ok()
30 .and_then(|duration| u64::try_from(duration.as_nanos()).ok());
31 Self { origin: Instant::now(), unix_epoch_ns }
32 }
33}
34
35impl Default for SystemRuntimeObservationClock {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl RuntimeObservationClock for SystemRuntimeObservationClock {
42 fn monotonic_ns(&self) -> u64 {
43 u64::try_from(self.origin.elapsed().as_nanos()).unwrap_or(u64::MAX)
44 }
45
46 fn unix_epoch_ns(&self) -> Option<u64> {
47 self.unix_epoch_ns
48 }
49}
50
51#[derive(Debug)]
53pub struct DeterministicRuntimeObservationClock {
54 monotonic_ns: AtomicU64,
55 unix_epoch_ns: Option<u64>,
56}
57
58impl DeterministicRuntimeObservationClock {
59 pub const fn new(unix_epoch_ns: Option<u64>) -> Self {
61 Self { monotonic_ns: AtomicU64::new(0), unix_epoch_ns }
62 }
63
64 pub fn set_monotonic_ns(&self, monotonic_ns: u64) {
66 self.monotonic_ns.store(monotonic_ns, Ordering::Release);
67 }
68
69 pub fn advance(&self, nanoseconds: u64) -> u64 {
71 self.monotonic_ns.fetch_add(nanoseconds, Ordering::AcqRel).saturating_add(nanoseconds)
72 }
73}
74
75impl RuntimeObservationClock for DeterministicRuntimeObservationClock {
76 fn monotonic_ns(&self) -> u64 {
77 self.monotonic_ns.load(Ordering::Acquire)
78 }
79
80 fn unix_epoch_ns(&self) -> Option<u64> {
81 self.unix_epoch_ns
82 }
83}