Skip to main content

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}