class AnyFlake

Pure ruby independent ID generator like the SnowFlake, ChiliFlake. @see github.com/twitter/snowflake @see github.com/ma2shita/chiliflake

Constants

MAX_NODE_ID
MAX_SEQUENCE
NODE_ID_BITS
SEQUENCE_BITS
TIMESTAMP_BITS

Public Class Methods

new(target_epoch, node_id, sequence = 0) click to toggle source
# File lib/anyflake.rb, line 19
def initialize(target_epoch, node_id, sequence = 0)
  raise OverflowError, "invalid node_id (#{node_id} >= #{MAX_NODE_ID})" if node_id >= MAX_NODE_ID
  raise OverflowError, "invalid sequence (#{sequence} >= #{MAX_SEQUENCE})" if sequence >= MAX_SEQUENCE
  @target_epoch = target_epoch
  @node_id      = node_id % MAX_NODE_ID
  @sequence     = sequence % MAX_SEQUENCE
  @last_time    = current_time
end
parse(flake_id, target_epoch) click to toggle source
# File lib/anyflake.rb, line 50
def self.parse(flake_id, target_epoch)
  hash = {}
  hash[:epoch_time] = flake_id >> (SEQUENCE_BITS + NODE_ID_BITS)
  hash[:time]       = Time.at((hash[:epoch_time] + target_epoch) / 1000.0)
  hash[:node_id]    = (flake_id >> SEQUENCE_BITS).to_s(2)[-NODE_ID_BITS, NODE_ID_BITS].to_i(2)
  hash[:sequence]   = flake_id.to_s(2)[-SEQUENCE_BITS, SEQUENCE_BITS].to_i(2)
  hash
end

Public Instance Methods

next_id() click to toggle source
# File lib/anyflake.rb, line 28
def next_id
  time = current_time

  raise InvalidSystemClockError, "(#{time} < #{@last_time})" if time < @last_time

  if time == @last_time
    @sequence = (@sequence + 1) % MAX_SEQUENCE
    # NOTE: Distributed in node_id so if more than MAX_SEQUENCE, or wait until the next time.
    # time = till_next_time if @sequence == 0
  else
    @sequence = 0
  end

  @last_time = time

  compose(@last_time, @node_id, @sequence)
end
parse(flake_id) click to toggle source
# File lib/anyflake.rb, line 46
def parse(flake_id)
  AnyFlake.parse(flake_id, @target_epoch)
end

Private Instance Methods

compose(last_time, node_id, sequence) click to toggle source
# File lib/anyflake.rb, line 61
def compose(last_time, node_id, sequence)
  ((last_time - @target_epoch) << (SEQUENCE_BITS + NODE_ID_BITS)) +
    (node_id << SEQUENCE_BITS) +
    sequence
end
current_time() click to toggle source
# File lib/anyflake.rb, line 67
def current_time
  Time.now.strftime('%s%L').to_i
end