loonfs_objectstore/timing.rs
1//! Local monotonic elapsed-time boundary for self-enforced deadlines and
2//! budgets.
3//!
4//! This module is the one place storage and writer code observes time.
5//! Deadlines bound retry loops and budgets bound a writer's own
6//! write-to-publish window so the GC grace window is deterministically safe;
7//! they gate only the observer's next action (stop retrying,
8//! abandon-and-rebuild). No validator compares timestamps, nothing on the
9//! wire carries these readings, and commit validity never consults time.
10//! `loonfs-core` re-exports these types; the trait is an injection seam the
11//! external simulation harness also consumes.
12
13use std::sync::OnceLock;
14use std::time::Instant;
15
16/// Supplies monotonic milliseconds for retry deadlines and deterministic test injection.
17pub trait MonotonicTimer: std::fmt::Debug + Send + Sync {
18 /// Milliseconds since an arbitrary per-timer origin. Never goes
19 /// backward; only differences are meaningful.
20 fn monotonic_now_ms(&self) -> u64;
21}
22
23/// Process-clock implementation backed by [`std::time::Instant`].
24#[derive(Debug, Default)]
25pub struct StdMonotonicTimer {
26 origin: OnceLock<Instant>,
27}
28
29impl MonotonicTimer for StdMonotonicTimer {
30 fn monotonic_now_ms(&self) -> u64 {
31 // The explicit timing boundary the workspace lint points to: this is
32 // a self-imposed deadline source, not an input to commit validity.
33 #[allow(clippy::disallowed_methods)]
34 let now = Instant::now();
35 let origin = self.origin.get_or_init(|| now);
36 u64::try_from(now.saturating_duration_since(*origin).as_millis()).unwrap_or(u64::MAX)
37 }
38}