// Package sync provides synchronisation primitives for the mitbringsl backend. // The Hybrid Logical Clock (HLC) combines a physical wall-clock with a logical // counter so that every event gets a strictly monotonically increasing int64 // timestamp that is compatible with client-generated HLC values. // // Encoding: the top 48 bits hold wall-clock milliseconds since the Unix epoch; // the bottom 16 bits hold a counter that disambiguates events within the same // millisecond. This lets us store the full HLC value in a single BIGINT column // while still being orderable and human-readable. package sync import ( "sync" "time" ) const ( // counterBits is the number of bits reserved for the intra-ms counter. counterBits = 16 // maxCounter is the maximum value the intra-ms counter can hold. maxCounter = (1 << counterBits) - 1 ) // clock is the process-global HLC state. All exported functions are safe for // concurrent use via the embedded mutex. var clock struct { mu sync.Mutex last int64 } // Now returns the current HLC value without advancing the state. // Useful for initialisation checks; prefer Tick for actual event timestamps. func Now() int64 { clock.mu.Lock() defer clock.mu.Unlock() return tick(clock.last) } // Tick advances the global HLC past the given external value (e.g. a // client-supplied hlc_ts) and returns the new value. It is safe to call with // 0 when there is no external value to incorporate. // // Guarantees: // - result > last (strictly monotonic) // - result >= externalHLC (causal ordering preserved) func Tick(externalHLC int64) int64 { clock.mu.Lock() defer clock.mu.Unlock() wall := wallMS() prev := clock.last // Determine the maximum physical time we're aware of. maxWall := max3(wall, wallOf(prev), wallOf(externalHLC)) var counter int64 switch { case maxWall == wallOf(prev) && maxWall == wallOf(externalHLC): // Both are in the same ms bucket: take the larger counter + 1. c := counterOf(prev) if ec := counterOf(externalHLC); ec > c { c = ec } counter = c + 1 case maxWall == wallOf(prev): counter = counterOf(prev) + 1 case maxWall == wallOf(externalHLC): counter = counterOf(externalHLC) + 1 default: // Wall time advanced; reset counter. counter = 0 } if counter > maxCounter { // Counter overflow: steal a millisecond from the future. maxWall++ counter = 0 } next := (maxWall << counterBits) | counter clock.last = next return next } // After reports whether a causally follows b (i.e. a > b as integers). func After(a, b int64) bool { return a > b } // wallMS returns the current Unix epoch time in milliseconds. func wallMS() int64 { return time.Now().UnixMilli() } // wallOf extracts the wall-clock ms from an HLC value. func wallOf(hlc int64) int64 { return hlc >> counterBits } // counterOf extracts the logical counter from an HLC value. func counterOf(hlc int64) int64 { return hlc & maxCounter } // tick is the internal (lock-held) Tick implementation against wall time only. func tick(last int64) int64 { wall := wallMS() maxWall := wallOf(last) if wall > maxWall { return wall << counterBits } counter := counterOf(last) + 1 if counter > maxCounter { maxWall++ counter = 0 } return (maxWall << counterBits) | counter } func max3(a, b, c int64) int64 { if b > a { a = b } if c > a { a = c } return a }