Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

124 lines (110 sloc) 3.705 kb
# encoding: utf-8
module Cql
# A variant of UUID which can extract its time component.
#
class TimeUuid < Uuid
include Comparable
# Returns the time component from this UUID as a Time.
#
# @return [Time]
#
def to_time
t = time_bits - GREGORIAN_OFFSET
seconds = t/10_000_000
microseconds = (t - seconds * 10_000_000)/10.0
Time.at(seconds, microseconds).utc
end
def <=>(other)
c = self.value <=> other.value
return c if c == 0
self.time_bits <=> other.time_bits
end
protected
def time_bits
n = (value >> 64)
t = 0
t |= (n & 0x0000000000000fff) << 48
t |= (n & 0x00000000ffff0000) << 16
t |= (n & 0xffffffff00000000) >> 32
t
end
private
LOWER_HALF_MASK = 0xffffffff_ffffffff
public
# A UUID version 1, variant 1 generator. It can generate a sequence of UUIDs
# with reasonable uniqueness guarantees:
#
# * The clock ID and node ID components are set to random numbers when the
# generator is created.
# * If two calls to {#next} happen within the time afforded by the system
# clock resolution a counter is incremented and added to the time
# component.
# * If the clock moves backwards the clock ID is reset to a new random
# number.
#
# Instances of this class are absolutely not threadsafe. You should
# never share instances between threads.
#
class Generator
# Create a new UUID generator.
#
# @param [Integer] node_id an alternate node ID (defaults to a random number)
# @param [Integer] clock_id an alternate clock ID (defaults to a random number)
#
def initialize(node_id=nil, clock_id=nil, clock=Time)
@node_id = node_id || (rand(2**47) | 0x010000000000)
@clock_id = clock_id || rand(2**16)
@clock = clock
end
# Returns a new UUID with a time component that is the current time.
#
# @return [Cql::TimeUuid] a new UUID
#
def next
now = @clock.now
usecs = now.to_i * 1_000_000 + now.usec
if @last_usecs && @last_usecs - @sequence <= usecs && usecs <= @last_usecs
@sequence += 1
elsif @last_usecs && @last_usecs > usecs
@sequence = 0
@clock_id = rand(2**16)
else
@sequence = 0
end
@last_usecs = usecs + @sequence
from_usecs(@last_usecs)
end
# Returns a new UUID with a time component based on the specified Time.
# A piece of jitter is added to ensure that multiple calls with the same
# time do not generate the same UUID (if you want determinism you can set
# the second parameter to zero).
#
# @param [Time] time the time to encode into the UUID
# @param [Integer] jitter a number of microseconds to add to the time to make it unique
# @return [Cql::TimeUuid] a new UUID
#
def from_time(time, jitter=rand(2**16))
usecs = time.to_i * 1_000_000 + time.usec + jitter
from_usecs(usecs)
end
# @private
def from_usecs(usecs)
t = GREGORIAN_OFFSET + usecs * 10
time_hi = t & 0x0fff000000000000
time_mid = t & 0x0000ffff00000000
time_low = t & 0x00000000ffffffff
version = 1
clock_id = @clock_id & 0x3fff
node_id = @node_id & 0xffffffffffff
variant = 0x8000
n = (time_low << 96) | (time_mid << 48) | (time_hi << 16)
n |= version << 76
n |= (clock_id | variant) << 48
n |= node_id
TimeUuid.new(n)
end
end
private
GREGORIAN_OFFSET = 122192928000000000
end
end
Jump to Line
Something went wrong with that request. Please try again.