Expand description
SharedFenceClock - Hybrid Logical Clock (HLC) lifted to
cross-process MMF.
Each participating process registers an HLC slot in a shared
table and publishes its (physical_us, logical) HLC there on
every meaningful event. Any reader can walk the table to compute
global_fence = max(all slots) - the timestamp at which all
process events are causally observable. That fence is exactly
what distributed snapshot isolation needs.
§Why HLC instead of vector clocks
Vector clocks give exact causal ordering but cost O(N) per event (each event has to update N-dim coordinate). HLC gives total order that respects causality with two u64 fields per process, bounded difference from physical clock skew, and O(1) per event. For cross-process snapshots over modest N (say <256 processes), HLC’s tradeoff dominates VC.
§HLC update rules (Kulkarni et al.)
tick:wall = now(),new_phys = max(prev_phys, wall)new_log = if new_phys == prev_phys { prev_log + 1 } else { 0 }
merge(remote):new_phys = max(prev_phys, remote_phys, wall)new_log = max(prev_log, remote_log) + 1when both equal new_phys= prev_log + 1when only prev equals new_phys= remote_log + 1when only remote equals new_phys= 0when wall strictly dominates
§Layout
ONE MMF file: <base>.bin with HlcHeader (64B) +
HlcSlot[capacity] (64B each, one cache line so cross-process
writes don’t false-share).
§Race tolerance
Per-slot writes are: physical.store(Release) then
logical.store(Release). A reader may observe a fresh physical
with stale logical (or vice versa). That’s HLC-safe because:
- physical is monotonically non-decreasing
- logical only increases at a given physical
- the only invariant is total order, which lexicographic
(physical, logical)preserves even with one-field skew
For strict torn-write protection, wrap with SeqLock; we omit it here because HLC’s coarse-granularity guarantees absorb the single-cycle window.
Structs§
- Hlc
- HLC value:
(physical_us, logical). Total order is lexicographic. - HlcHeader
- HlcSlot
- HlcSlot
Snapshot - Shared
Fence Clock