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
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
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
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
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
@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