Skip to main content

TimestampGenerator

Struct TimestampGenerator 

Source
pub struct TimestampGenerator { /* private fields */ }
Expand description

High-precision timestamp generator using TSC.

This generator provides strictly monotonic timestamps with sub-nanosecond resolution and zero syscall overhead after initialization.

§Single-owner invariant

Each producer should own a dedicated TimestampGenerator. The type is Send + Sync and next() is safe to call concurrently — monotonicity is preserved by compare_exchange_weak — but the CAS loop degenerates into a spin under sustained contention. The whole design rests on the loop almost never iterating: that’s only true when one writer at a time accesses the generator.

The codebase enforces this structurally rather than at runtime:

  • Shard owns its TimestampGenerator by value (not behind Arc).
  • TimestampGenerator is not Clone, so duplicating one is a deliberate mem::replace / Default::default() away — visible in code review.
  • The shard’s surrounding Mutex<Shard> serializes producers, so next() is invoked by exactly one caller at a time per shard.

If you find yourself reaching for Arc<TimestampGenerator>, stop — give each producer its own instance instead. Every additional concurrent caller is one more thread potentially CAS-spinning on last.

Implementations§

Source§

impl TimestampGenerator

Source

pub fn new() -> Self

Create a new timestamp generator.

This performs a one-time calibration against the system clock. Subsequent timestamp reads use TSC directly.

Source

pub fn next(&self) -> u64

Generate the next timestamp.

Returns a strictly monotonically increasing value in nanoseconds since this generator was constructed. This operation is lock-free and does not invoke any syscalls.

Previously returned the raw TSC tick count. The docstring claimed nanoseconds, but on a 3.5 GHz core the value was ~3.5× larger than ns-since-epoch, breaking any consumer that read insertion_ts and tried to correlate it with wall-clock-derived timestamps from elsewhere. Converting via delta_as_nanos here costs ~1ns extra per call and gives consumers a unit they can actually use.

§Performance
  • Single-threaded: ~6-12ns per call
  • Under contention: may loop due to CAS, but still lock-free
Source

pub fn now_raw(&self) -> u64

Get the current raw timestamp without incrementing.

This does NOT guarantee monotonicity and is only useful for measuring elapsed time or debugging.

Source

pub fn raw_to_nanos(&self, raw: u64) -> u64

Convert a raw timestamp to nanoseconds since this generator was constructed (i.e. since baseline_raw). Output units match next(): the value returned by raw_to_nanos(self.now_raw()) is comparable to recently-next()-returned timestamps from the same generator (modulo the monotonicity floor next() enforces).

Note: NOT “nanoseconds since UNIX epoch”. The reference point is the per-generator construction moment, so two generators created at different times produce values with different offsets. For wall-clock-anchored debugging, combine with SystemTime::now() at generator-construction time (recorded externally).

Pre-fix this called delta_as_nanos(0, raw), where the 0 baseline was an unspecified quanta-internal reference (typically system boot under Windows QPC or the clock’s first-call moment elsewhere). The returned ns values were in the order of system uptime — not comparable to next() output, despite the function’s previous “ns since epoch” doc-claim. Aligning both to baseline_raw makes the surface consistent.

Source

pub fn last(&self) -> u64

Get the last generated timestamp.

Trait Implementations§

Source§

impl Default for TimestampGenerator

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more