surrealpatch/lib/src/kvs/clock.rs

106 lines
2.3 KiB
Rust
Raw Normal View History

use crate::dbs::node::Timestamp;
use crate::sql;
use sql::Duration;
use std::time::{SystemTime, UNIX_EPOCH};
// Traits cannot have async and we need sized structs for Clone + Send + Sync
#[allow(dead_code)]
#[derive(Clone, Copy)]
pub enum SizedClock {
System(SystemClock),
#[cfg(test)]
Fake(FakeClock),
#[cfg(test)]
Inc(IncFakeClock),
}
impl SizedClock {
pub async fn now(&mut self) -> Timestamp {
match self {
SizedClock::System(c) => c.now(),
#[cfg(test)]
SizedClock::Fake(c) => c.now().await,
#[cfg(test)]
SizedClock::Inc(c) => c.now().await,
}
}
}
/// FakeClock is a clock that is fully controlled externally.
/// Use this clock for when you are testing timestamps.
#[derive(Clone, Copy)]
pub struct FakeClock {
// Locks necessary for Send
now: Timestamp,
}
#[allow(dead_code)]
impl FakeClock {
pub fn new(now: Timestamp) -> Self {
FakeClock {
now,
}
}
pub async fn now(&self) -> Timestamp {
self.now
}
pub async fn set(&mut self, timestamp: Timestamp) {
self.now = timestamp;
}
}
/// IncFakeClock increments a local clock every time the clock is accessed, similar to a real clock.
/// This is useful when you need unique and partially deterministic timestamps for tests.
/// Partially deterministic, because you do not have direct control over how many times a clock
/// is accessed, and due to the nature of async - you neither have order guarantee.
#[derive(Clone, Copy)]
pub struct IncFakeClock {
// Locks necessary for Send
now: Timestamp,
increment: Duration,
}
#[allow(dead_code)]
impl IncFakeClock {
pub fn new(now: Timestamp, increment: Duration) -> Self {
IncFakeClock {
now,
increment,
}
}
pub async fn now(&mut self) -> Timestamp {
self.now = &self.now + &self.increment;
self.now
}
}
/// SystemClock is a clock that uses the system time.
/// Use this when there are no other alternatives.
#[derive(Clone, Copy)]
pub struct SystemClock;
impl SystemClock {
pub fn new() -> Self {
SystemClock
}
pub fn now(&self) -> Timestamp {
// Use a timestamp oracle if available
let now: u128 = match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(duration) => duration.as_millis(),
Err(error) => panic!("Clock may have gone backwards: {:?}", error.duration()),
};
Timestamp {
value: now as u64,
}
}
}
impl Default for SystemClock {
fn default() -> Self {
Self::new()
}
}