Files
alkstore/alkstore-mem/src/clock.rs
T
glm-5.3-flash 7e8bfde12d review-wave-6 — the wave-6 gate passes, engine-mem.md flipped to stable
The born-pinned gate audited the mem engine against the contract and
ADR-024: the conformance read clean in mechanism substance (queue
state machine, scheduler collapse, outbox, streams, locks, clock,
validation, tx overlay, wake substrate — incl. a full guard-order and
panic-hygiene audit); the suite's third column read row-by-row and
25/25 green under the per-test current-thread flavor (24 engine-shared
rows + mem's payload_too_large non-occurrence arm + the factory-shape
test); three-way arithmetic equivalence green on all columns; the
wasm32 acceptance items verified (compile-clean, tokio sync+time,
no blocking, flavor enforced); the rider's two arms verified (Finding
1 discharged; Findings 2-3 stay parked for wave 7); workspace gates,
taskgraph validate green.

Three edge-domain fixes landed inline: the stream cursor read's
i64::MAX overflow (Bound::Excluded), trim_to's i64::MAX horizon
endpoint (Bound::Included), and the scheduler register path now
rejecting a parseable interval whose first boundary overflows with
InvalidSpec — the one engine-vs-engine divergence the read found,
aligned into the class-1 window — plus a pinning test and scaffold-
residue doc/comment cleanups (clock allows, tx per-stream wake
comment, wakes/stream module docs). Recorded findings with
dispositions in the task's Notes for the wave-7 pre-release pass:
the multi-thread publish-to-wake ordering tolerance, the heartbeat/
save_offset/EventReceiver-try_recv ADR-023 §2 classification gaps,
and the mem arithmetic being a suite-pinned transplant.

Verified: cargo build; cargo test --workspace green (mem 101 lib +
25 suite, sqlite 191+25, pg 124+25+9 server-less, core 25, harness 3);
clippy --all-targets -D warnings clean; fmt clean; taskgraph validate
(61 tasks). Gate record: tasks/review-wave-6.md (Notes + Summary),
implementation.md wave-6 row + review-rounds entry.
2026-10-10 13:17:18 +00:00

107 lines
2.7 KiB
Rust

//! The engine's clock — every timestamp the mem engine produces (unix
//! seconds stamps, visibility deadlines, TTLs, scheduler boundaries)
//! reads this one accessor ([`Clock::unix_now`]); the process clock is
//! all there is (engine-mem.md: no server clock to defer to).
//!
//! The single point exists so tests can observe timestamps
//! deterministically the way the SQL engines observe row shapes: a
//! `#[cfg(test)]` freeze/advance seam pins a wall value and every
//! accessor call returns it (see the unit pins below). Production
//! reads `std::time::SystemTime`.
#[cfg(test)]
use std::sync::Mutex;
#[cfg(test)]
use crate::state::Guard;
fn process_unix_now() -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|since| since.as_secs() as i64)
.unwrap_or(0)
}
/// The engine's single clock.
#[derive(Debug)]
pub(crate) struct Clock {
#[cfg(test)]
frozen: Mutex<Option<i64>>,
}
impl Default for Clock {
fn default() -> Self {
Self::new()
}
}
impl Clock {
pub(crate) fn new() -> Self {
Self {
#[cfg(test)]
frozen: Mutex::new(None),
}
}
/// Unix-seconds "now" — the one timestamp source of the engine.
pub(crate) fn unix_now(&self) -> i64 {
#[cfg(test)]
let frozen = { *self.frozen.guard() };
#[cfg(test)]
if let Some(unix) = frozen {
return unix;
}
process_unix_now()
}
#[cfg(test)]
pub(crate) fn freeze(&self, at_unix: i64) {
*self.frozen.guard() = Some(at_unix);
}
#[cfg(test)]
pub(crate) fn advance(&self, seconds: i64) {
let mut guard = self.frozen.guard();
*guard = Some(frozen_now(&guard).saturating_add(seconds));
}
#[cfg(test)]
pub(crate) fn unfreeze(&self) {
*self.frozen.guard() = None;
}
}
#[cfg(test)]
fn frozen_now(frozen: &Option<i64>) -> i64 {
frozen.unwrap_or_else(process_unix_now)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unfrozen_reads_a_plausible_process_time() {
let clock = Clock::new();
let now = clock.unix_now();
assert!(
now > 1_700_000_000,
"the accessor reads the process clock when unfrozen"
);
}
#[test]
fn frozen_reads_deterministically_and_advances() {
let clock = Clock::new();
clock.freeze(1_234_567);
assert_eq!(clock.unix_now(), 1_234_567);
clock.advance(10);
assert_eq!(clock.unix_now(), 1_234_577);
clock.unfreeze();
assert!(
clock.unix_now() > 1_700_000_000,
"unfreeze restores the process clock"
);
}
}