| 116 | }; |
| 117 | |
| 118 | inline std::optional< std::array< std::uint8_t, 16 > > |
| 119 | UUIDv7Generator::generate() |
| 120 | { |
| 121 | std::uint64_t real_ms = absl::ToUnixMillis( absl::Now() ); |
| 122 | |
| 123 | unsigned fail_count = 0; |
| 124 | unsigned backoff_us = kBackoffSleepUs; |
| 125 | |
| 126 | // Main CAS loop |
| 127 | for( ;; ) |
| 128 | { |
| 129 | std::uint64_t old = g_state.load( std::memory_order_acquire ); |
| 130 | std::uint64_t old_ts = old >> 16; |
| 131 | std::uint16_t old_seq = |
| 132 | static_cast< std::uint16_t >( old & 0xFFFF ); |
| 133 | |
| 134 | // Enforce drift cap: limit how fast we can catch up to real time |
| 135 | if( real_ms > old_ts + kMaxDriftMs ) |
| 136 | real_ms = old_ts + kMaxDriftMs; |
| 137 | |
| 138 | std::uint64_t ts = old_ts; |
| 139 | std::uint16_t seq = old_seq; |
| 140 | |
| 141 | if( real_ms > old_ts ) |
| 142 | { |
| 143 | // Time advanced: use new timestamp with fresh random sequence |
| 144 | ts = real_ms; |
| 145 | seq = fresh_sequence(); |
| 146 | } |
| 147 | else |
| 148 | { |
| 149 | // Same millisecond: increment sequence or handle wraparound |
| 150 | if( old_seq == 0 && real_ms == old_ts ) |
| 151 | seq = fresh_sequence(); // Reset from zero to preserve |
| 152 | // ordering |
| 153 | else |
| 154 | seq = |
| 155 | static_cast< std::uint16_t >( ( seq + 1 ) & kSeqMask ); |
| 156 | |
| 157 | if( seq == 0 ) |
| 158 | { |
| 159 | // Sequence wrapped: advance virtual time by 1ms |
| 160 | if( old_ts + 1 > real_ms + kMaxDriftMs ) |
| 161 | return std::nullopt; // Would exceed drift limit |
| 162 | ts += 1; |
| 163 | seq = fresh_sequence(); |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | if( ts > real_ms + kMaxDriftMs ) |
| 168 | return std::nullopt; |
| 169 | |
| 170 | // Attempt atomic update |
| 171 | const std::uint64_t next = ( ts << 16 ) | seq; |
| 172 | if( g_state.compare_exchange_weak( old, next, |
| 173 | std::memory_order_acq_rel, std::memory_order_relaxed ) ) |
| 174 | return encode_uuid( ts, seq ); |
| 175 | |