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.
107 lines
2.7 KiB
Rust
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"
|
|
);
|
|
}
|
|
}
|