use crate::store::StoreError;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc;
use std::time::Instant;
pub(crate) fn now_us() -> i64 {
let micros = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_micros();
i64::try_from(micros).unwrap_or(i64::MAX)
}
pub(crate) fn wall_ms_from_timestamp_us(timestamp_us: i64) -> Result<u64, StoreError> {
if timestamp_us < 0 {
return Err(StoreError::InvalidClock {
timestamp_us,
reason: "timestamp_us must be >= 0 microseconds since Unix epoch".into(),
});
}
Ok((timestamp_us / 1000).cast_unsigned())
}
pub(crate) fn now_wall_ns_saturating() -> i64 {
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
i64::try_from(nanos).unwrap_or(i64::MAX)
}
struct MonotonicAnchor {
anchor_instant: Instant,
anchor_boot_ns: u64,
}
impl MonotonicAnchor {
fn get() -> &'static Self {
use std::sync::OnceLock;
static ANCHOR: OnceLock<MonotonicAnchor> = OnceLock::new();
ANCHOR.get_or_init(|| {
let wall_ns = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
let anchor_boot_ns = u64::try_from(wall_ns).unwrap_or(u64::MAX);
MonotonicAnchor {
anchor_instant: Instant::now(),
anchor_boot_ns,
}
})
}
}
pub(crate) fn now_mono_ns() -> i64 {
let anchor = MonotonicAnchor::get();
let elapsed = anchor.anchor_instant.elapsed().as_nanos();
i64::try_from(elapsed).unwrap_or(i64::MAX)
}
pub(crate) fn process_boot_ns() -> u64 {
MonotonicAnchor::get().anchor_boot_ns
}
#[derive(Clone)]
pub(crate) struct MonotonicClock {
inner: Arc<dyn Fn() -> i64 + Send + Sync>,
last: Arc<AtomicI64>,
}
impl MonotonicClock {
pub(crate) fn wrap(inner: Arc<dyn Fn() -> i64 + Send + Sync>) -> Self {
Self {
inner,
last: Arc::new(AtomicI64::new(i64::MIN)),
}
}
pub(crate) fn now_us(&self) -> i64 {
let raw = (self.inner)();
loop {
let prev = self.last.load(Ordering::Acquire);
if raw >= prev {
match self
.last
.compare_exchange(prev, raw, Ordering::AcqRel, Ordering::Acquire)
{
Ok(_) => return raw,
Err(_) => continue, }
} else {
tracing::error!("user clock regressed: prev={} new={}", prev, raw);
return prev;
}
}
}
}