class Uuidx::Version6

UUID Version 6 defined by the RFC 4122 BIS-01 Draft.

To construct a new UUID v6 value create a generator, then use generate.

g = Uuidx::Version6.new
g.generate # => "1eda9761-9f6f-6414-8c5f-fd61f1239907"

The implementation will use SecureRandom to populate the Node and Clock Sequence bits with a random value at module load time.

Generation is thread-safe, but if you are using multi-process clusters you should call reset! at the start of each process to reduce the chance of two processes generating the same value.

If you have need to make sure that the clock resolution is sufficient for the v6 specification you can call ::verify_clock_resolution! and handle the ClockResolutionError as you see fit.

begin
  Uuidx::Version6.verify_clock_resolution!
rescue Uuidx::ClockResolutionError
  # ...
end

The necessary clock resolution for v6 is 100ns.

A Note on Clock Timings

To combat clock drift, leap-second smearing, and other clock value changes that can appear without requiring additional compute cost this implementation always increments the clock sequence number.

Public Class Methods

new() click to toggle source

Construct a new UUID v6 generator.

# File lib/uuidx/version6.rb, line 48
def initialize
  reset!
end
verify_clock_resolution!() click to toggle source

Verify that the clock resolution is capable of 100ns resolution.

Raises ClockResolutionError when the clock resolution is insufficient.

# File lib/uuidx/version6.rb, line 73
def self.verify_clock_resolution!
  ns_res = Process.clock_getres(Process::CLOCK_REALTIME, :nanosecond)
  raise ClockResolutionError, "Detected #{ns_res}ns resolution, need <= 100ns" if ns_res > 100

  true
end

Public Instance Methods

generate() click to toggle source

Construct a UUID v6 value.

# File lib/uuidx/version6.rb, line 53
def generate
  @clock_sequence = (@clock_sequence + CLOCK_SEQ_INCREMENT) & CLOCK_SEQ_MASK

  ts = GREGORIAN_MICROSECOND_TENTHS + (Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) / TS_NS_FACTOR)
  ts = ((ts << TS_MASK_SHIFT) & TS_HIGH_MID_MASK) | (ts & TS_LOW_MASK)

  Uuidx.format(VERSION_VARIANT | (ts << TS_POSITIONAL_SHIFT) | @clock_sequence | @node_id)
end
reset!() click to toggle source

Reset the generator with a new random node ID and clock sequence.

This method is not thread-safe and should only be called at application or child process start.

# File lib/uuidx/version6.rb, line 65
def reset!
  @node_id = (SecureRandom.bytes(8).unpack1("Q") & NODE_ID_MASK) | NODE_ID_MC_BIT
  @clock_sequence = SecureRandom.bytes(4).unpack1("L") << CLOCK_SEQ_SHIFT
end