Module time_store

Source
Expand description

Saving/loading timestamps to disk

Storing timestamps on disk is not so straightforward. We need to use wall clock time in order to survive restarts. But wall clocks can be wrong, so we need at least to apply some sanity checks.

This module encapsulates those checks, and some error handling choices. It allows Instants to be used while the system is running, with bespoke types for loading/saving. See Loading::load_future for the load/save guarantees provided.

The initial entrypoints are Storing::start and Loading::start.

Granularity is 1 second and the precise rounding behaviour is not specified.

§Data model

To mitigate clock skew, we store the wall clock time at which each timestamp was saved to disk (Reference) and the offset from now to that timestamp (FutureTimestamp).

The same storage time can be used for multiple timestamps that are stored together.

§Example

use serde::{Serialize, Deserialize};
use std::time::{Duration, Instant};
use tor_rtcompat::{PreferredRuntime, SleepProvider as _};

use crate::time_store;

let runtime = PreferredRuntime::create().unwrap();

#[derive(Serialize, Deserialize, Debug)]
struct Stored {
    time_ref: time_store::Reference,
    t0: time_store::FutureTimestamp,
}

let t0: Instant = runtime.now() + Duration::from_secs(60);

let storing = time_store::Storing::start(&runtime);
let data = Stored {
    time_ref: storing.store_ref(),
    t0: storing.store_future(t0),
};

let json = serde_json::to_string(&data).unwrap();

// later:

let data: Stored = serde_json::from_str(&json).unwrap();
let loading = time_store::Loading::start(&runtime, data.time_ref);
let t0: Instant = loading.load_future(data.t0);

assert!(t0 - runtime.now() <= Duration::from_secs(60));

§Time arithmetic overflows and stupid system time settings

Arithmetic is done with signed 64-bit numbers of seconds. So overflow cannot occur unless the clock is completely ludicrous. If the clock is ludicrous, time calculations are going to be a mess. We treat this as clock skew, using saturating arithmetic, rather than returning errors. Reasonable operation will resume when the clock becomes sane.

Macros§

derive_deftly_template_RawConversions 🔒
Define as_raw and from_raw methods (for a struct with a single field)
derive_deftly_template_SerdeStringOrTransparent 🔒
Define Serialize and Deserialize via string rep or transparently, depending

Structs§

DeserializeFutureTimestampStringVisitor 🔒
Visitor for deserializing from a string
DeserializeReferenceStringVisitor 🔒
Visitor for deserializing from a string
FutureTimestamp
Representation of an absolute time, in the future, suitable for storing to disk
Loading
Context for loading Instants from disk
Now 🔒
The two notions of the current time, for internal use
ParseError
Error parsing a timestamp or reference
Reference
On-disk representation of a reference time, used as context for stored timestamps
Storing
Context for storing Instants to disk

Functions§

system_time_max 🔒
Maximum value of SystemTime
system_time_min 🔒
Minimum value of SystemTime
system_time_to_time_t 🔒
Convert a SystemTime to an i64 time_t
time_t_to_system_time 🔒
Convert a SystemTime to an i64 time_t