class Cassandra::Uuid::Generator

A UUID generator.

This class can be used to genereate Apache Cassandra timeuuid and uuid values.

@see Cassandra::Uuid::Generator#now Generating a sequence time UUIDs

with reasonable uniqueness guarantees.

@see Cassandra::Uuid::Generator#at Generating a time UUID for a given

time object or unix timestamp.

@see Cassandra::Uuid::Generator#uuid Generating completely random v4

UUIDs.

@note Instances of this class are absolutely not threadsafe. You should

never share instances between threads.

Public Class Methods

new(node_id = (::SecureRandom.random_number(2**47) | 0x010000000000), clock_id = ::SecureRandom.random_number(65536), clock = ::Time) click to toggle source

Create a new UUID generator.

The clock ID and node ID components are set to random numbers when the generator is created. These are used for generation of time UUIDs only.

@param [Integer] node_id an alternate node ID @param [Integer] clock_id an alternate clock ID @param [Object<#now>] clock used to generate timeuuid from current time

@raise [ArgumentError] if clock doesn't respond to `now`

   # File lib/cassandra/uuid/generator.rb
47 def initialize(node_id = (::SecureRandom.random_number(2**47) | 0x010000000000),
48                clock_id = ::SecureRandom.random_number(65536),
49                clock = ::Time)
50   raise ::ArgumentError, 'invalid clock' unless clock.respond_to?(:now)
51 
52   @node_id    = Integer(node_id)
53   @clock_id   = Integer(clock_id)
54   @clock      = clock
55   @last_usecs = nil
56 end

Public Instance Methods

at(*args) click to toggle source

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).

@overload at(time, jitter = SecureRandom.random_number(65536))

@param [Time] time a Time instance
@param [Integer] jitter a number of microseconds to add to the time
@return [Cassandra::TimeUuid] a new UUID

@overload at(seconds_with_frac, jitter = SecureRandom.random_number(65536))

@param [Numeric] seconds_with_frac can be {Integer}, {Float},
  {Rational}, or other {Numeric}
@param [Integer] jitter a number of microseconds to add to the time
@return [Cassandra::TimeUuid] a new UUID

@overload at(seconds, microseconds_with_frac, jitter = SecureRandom.random_number(65536))

@param [Integer] seconds
@param [Numeric] microseconds_with_frac can be {Integer}, {Float},
  {Rational}, or other {Numeric}
@param [Integer] jitter a number of microseconds to add to the time
@return [Cassandra::TimeUuid] a new UUID

@note the `jitter` argument accepted by all variants of this method is

required to add randomness to generated {Cassandra::TimeUuid} and
might affect the order of generated timestamps. You should set
`jitter` to 0 when the source time(stamp)s are unique.

@example Creating a TimeUuid from a Time instance

generator = Cassandra::Uuid::Generator.new
timeuuid  = generator.at(Time.at(1413582460))

puts timeuuid.to_time

# Outputs:
# 2014-10-17 21:47:40 UTC

@example Creating a TimeUuid from a timestamp

generator = Cassandra::Uuid::Generator.new
timeuuid  = generator.at(1413582423)

puts timeuuid.to_time

# Outputs:
# 2014-10-17 21:47:03 UTC

@example Avoid jitter in generated TimeUuid

timestamp = 1413582418
generator = Cassandra::Uuid::Generator.new
timeuuid  = generator.at(timestamp, 0)

puts timeuuid.to_time.to_i

# Outputs:
# 1413582418

@raise [ArgumentError] when given no arguments or more than 3 arguments

@see Time.at

    # File lib/cassandra/uuid/generator.rb
157 def at(*args)
158   raise ::ArgumentError, 'not enough arguments' if args.empty?
159   raise ::ArgumentError, 'too many arguments'   if args.size > 3
160 
161   if args.first.is_a?(::Time)
162     time   = args.shift
163     jitter = args.empty? ? ::SecureRandom.random_number(65536) : Integer(args.shift)
164   else
165     jitter = args.size > 2 ? Integer(args.pop) : ::SecureRandom.random_number(65536)
166     time   = ::Time.at(*args)
167   end
168 
169   from_usecs(time.to_i * 1_000_000 + time.usec + jitter)
170 end
now() click to toggle source

Returns a new UUID with a time component that is the current time.

If two calls to {#now} 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.

@example Creating a sequential TimeUuids for the current time

generator = Cassandra::Uuid::Generator.new
timeuuids = 5.times.map { generator.now }

puts timeuuids.zip(timeuuids.map(&:to_time)).map(&:inspect)

# Outputs:
# [8614b7d0-5646-11e4-8e54-6761d3995ef3, 2014-10-17 21:42:42 UTC]
# [8614b91a-5646-11e4-8e54-6761d3995ef3, 2014-10-17 21:42:42 UTC]
# [8614b960-5646-11e4-8e54-6761d3995ef3, 2014-10-17 21:42:42 UTC]
# [8614b99c-5646-11e4-8e54-6761d3995ef3, 2014-10-17 21:42:42 UTC]
# [8614b9ce-5646-11e4-8e54-6761d3995ef3, 2014-10-17 21:42:42 UTC]

@see Time.now

@return [Cassandra::TimeUuid] a new UUID

   # File lib/cassandra/uuid/generator.rb
83 def now
84   now   = @clock.now
85   usecs = now.to_i * 1_000_000 + now.usec
86 
87   if @last_usecs && @last_usecs - @sequence <= usecs && usecs <= @last_usecs
88     @sequence += 1
89   elsif @last_usecs && @last_usecs > usecs
90     @sequence = 0
91     @clock_id = ::SecureRandom.random_number(65536)
92   else
93     @sequence = 0
94   end
95 
96   @last_usecs = usecs + @sequence
97   from_usecs(@last_usecs)
98 end
uuid() click to toggle source

Returns a completely random version 4 UUID.

@example Generating a random Uuid

generator = Cassandra::Uuid::Generator.new
uuid      = generator.uuid

puts uuid

# Outputs:
# 664dedae-e162-4bc0-9066-b9f1968252aa

@see SecureRandom.uuid

@return [Cassandra::Uuid] a new UUID

    # File lib/cassandra/uuid/generator.rb
186 def uuid
187   Uuid.new(::SecureRandom.uuid)
188 end

Private Instance Methods

from_usecs(usecs) click to toggle source

@private

    # File lib/cassandra/uuid/generator.rb
193 def from_usecs(usecs)
194   t = TimeUuid::GREGORIAN_OFFSET + usecs * 10
195   time_hi  = t & 0x0fff000000000000
196   time_mid = t & 0x0000ffff00000000
197   time_low = t & 0x00000000ffffffff
198   version  = 1
199   clock_id = @clock_id & 0x3fff
200   node_id  = @node_id & 0xffffffffffff
201   variant  = 0x8000
202 
203   n  = (time_low << 96) | (time_mid << 48) | (time_hi << 16)
204   n |= version << 76
205   n |= (clock_id | variant) << 48
206   n |= node_id
207 
208   TimeUuid.new(n)
209 end