module Uniqid::ClassMethods
@params worker_id @params server_id
Constants
- BAK_ID_LEN
2 bits reserved, (0-3)
- LOCAL_ID_LEN
7 bits for serial number in milliseconds, (0-127)
- MAX_BAK_NUM
- MAX_LOCAL_NUM
- MAX_SERVER_NUM
The maximum number of servers supported, result is 63
- MAX_TIMESTAMP
- MAX_WORKER_NUM
The maximum number of workers supported, -1:complement0b111111111
- SERVER_ID_LEN
6 bits for server ID, (0-63)
- TIMESTAMP_LEN
40 bits for time in milliseconds
- TIMESTAMP_START
Start timestamp, 2018-01-01 00:00:00
- TOTAL_LEN
64 bits
- WORKER_ID_LEN
9 bits for worker ID, (0-511)
Public Instance Methods
generate(worker_value, server_value, timestamp = nil)
click to toggle source
Generate ID
# File lib/uniqid.rb, line 88 def generate(worker_value, server_value, timestamp = nil) server_value = server_value(server_value) worker_value = worker_value(worker_value) # The reserved position is temporarily random, shifted by 7 bits to the left bak_value = (rand(MAX_BAK_NUM) << LOCAL_ID_LEN) local_timestamp = if timestamp (timestamp * 1000).to_i else (Time.now.to_f * 1000).to_i end # If the last generation time is the same as the current time, the sequence within milliseconds if local_timestamp == @last_timestamp # The sequence is self-increasing and only has 7 bits, # so it is ANDed with MAX_LOCAL_NUM and removes the high bits sequence = (@sequence + 1) & MAX_LOCAL_NUM # Check for overflow: whether the sequence exceeds 127 per millisecond, # when 127, it is equal to 0 after AND with MAX_LOCAL_NUM if sequence.zero? # Wait until the next millisecond local_timestamp = next_timestamp(@last_timestamp) end else # If it is different from the last generation time, reset the sequence # In order to ensure that the mantissa is more random, set a random number in the last digit @sequence = rand(1 << LOCAL_ID_LEN) sequence = @sequence end @last_timestamp = local_timestamp # Save the difference of timestamp(current timestamp - start timestamp) local_timestamp -= TIMESTAMP_START (local_timestamp << (TOTAL_LEN - TIMESTAMP_LEN)) | server_value | worker_value | bak_value | sequence end
get_timestamp(id)
click to toggle source
Reverse check timestamp
# File lib/uniqid.rb, line 132 def get_timestamp(id) timestamp = (id >> (TOTAL_LEN - TIMESTAMP_LEN)) / 1000.0 Time.at(timestamp + TIMESTAMP_START / 1000.0) end
next_timestamp(last_timestamp)
click to toggle source
Prevent the generation time is smaller than the previous time(due to issues such as NTP callback), and keep the incremental trend.
# File lib/uniqid.rb, line 56 def next_timestamp(last_timestamp) timestamp = (Time.now.to_f * 1000).to_i timestamp = (Time.now.to_f * 1000).to_i while timestamp <= last_timestamp timestamp end
server_value(value)
click to toggle source
# File lib/uniqid.rb, line 70 def server_value(value) left_num = BAK_ID_LEN + LOCAL_ID_LEN value = 0 if value.to_i > MAX_SERVER_NUM || value.to_i.negative? unless value.present? # In development mode, take the random number of the largest supported number if Rails.env == 'development' rand(MAX_SERVER_NUM) << left_num else value = 0 end end value.to_i << left_num end
worker_value(value)
click to toggle source
@return worker_id 64 bits
# File lib/uniqid.rb, line 63 def worker_value(value) # Handling parameter exception value = 0 if value.to_i > MAX_WORKER_NUM || value.to_i.negative? value.to_i << SERVER_ID_LEN + BAK_ID_LEN + LOCAL_ID_LEN # 15 bits left end