snowflake_id_generator 1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/snowflake_id_generator.rb +127 -0
- metadata +45 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 564f24abd439144a45be9dd151cdedb2d3e35562a7808fa6544bd164b9561367
|
4
|
+
data.tar.gz: e1f3f6aa33fa2027b3c22d31f1b373f0b999c7a6e2710b20e39d22757e50dfa9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1cdb79ad56bba69f83372453b9b1b4e2efcb68e81fbe49598bf3b2536ffbe8930e449338c05c47bebf30f93a8001395c2a05dea48a2b6b09b34b84d19b0a6dfa
|
7
|
+
data.tar.gz: fa467ee85a046b61c03a9a7db1d7020c4318f60c50c5b616b6c1b60dcc739164cbbc2a9ba61eaf1e57c6f29a63cc3f4f5f3e4b97e0c5678cfcc8e74179343b6b
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Snowflake
|
2
|
+
EPOCH = 1288834974657 # Custom epoch (January 1, 2024)
|
3
|
+
WORKER_ID_BITS = 5
|
4
|
+
DATACENTER_ID_BITS = 5
|
5
|
+
SEQUENCE_BITS = 12
|
6
|
+
|
7
|
+
MAX_WORKER_ID = -1 ^ (-1 << WORKER_ID_BITS)
|
8
|
+
MAX_DATACENTER_ID = -1 ^ (-1 << DATACENTER_ID_BITS)
|
9
|
+
MAX_SEQUENCE = -1 ^ (-1 << SEQUENCE_BITS)
|
10
|
+
|
11
|
+
WORKER_ID_SHIFT = SEQUENCE_BITS
|
12
|
+
DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS
|
13
|
+
TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS
|
14
|
+
|
15
|
+
class IdGenerator
|
16
|
+
|
17
|
+
attr_reader :datacenter_id, :worker_id, :sequence, :last_timestamp
|
18
|
+
|
19
|
+
def initialize(datacenter_id, worker_id)
|
20
|
+
if datacenter_id > Snowflake::MAX_DATACENTER_ID || datacenter_id < 0
|
21
|
+
raise ArgumentError, "datacenter_id must be between 0 and #{Snowflake::MAX_DATACENTER_ID}"
|
22
|
+
end
|
23
|
+
|
24
|
+
if worker_id > Snowflake::MAX_WORKER_ID || worker_id < 0
|
25
|
+
raise ArgumentError, "worker_id must be between 0 and #{Snowflake::MAX_WORKER_ID}"
|
26
|
+
end
|
27
|
+
|
28
|
+
@datacenter_id = datacenter_id
|
29
|
+
@worker_id = worker_id
|
30
|
+
@sequence = 0
|
31
|
+
@last_timestamp = -1
|
32
|
+
end
|
33
|
+
|
34
|
+
def next_id
|
35
|
+
timestamp = current_time_millis
|
36
|
+
|
37
|
+
if timestamp < @last_timestamp
|
38
|
+
raise "Clock moved backwards. Refusing to generate id for #{@last_timestamp - timestamp} milliseconds"
|
39
|
+
end
|
40
|
+
|
41
|
+
if @last_timestamp == timestamp
|
42
|
+
@sequence = (@sequence + 1) & Snowflake::MAX_SEQUENCE
|
43
|
+
if @sequence == 0
|
44
|
+
timestamp = wait_for_next_millis(@last_timestamp)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
@sequence = 0
|
48
|
+
end
|
49
|
+
|
50
|
+
@last_timestamp = timestamp
|
51
|
+
|
52
|
+
p "timestamp - EPOCH: #{timestamp - Snowflake::EPOCH}"
|
53
|
+
|
54
|
+
((timestamp - Snowflake::EPOCH) << Snowflake::TIMESTAMP_SHIFT) |
|
55
|
+
(@datacenter_id << Snowflake::DATACENTER_ID_SHIFT) |
|
56
|
+
(@worker_id << Snowflake::WORKER_ID_SHIFT) |
|
57
|
+
@sequence
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def current_time_millis
|
63
|
+
(Time.now.to_f * 1000).to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def wait_for_next_millis(last_timestamp)
|
67
|
+
timestamp = current_time_millis
|
68
|
+
while timestamp <= last_timestamp
|
69
|
+
timestamp = current_time_millis
|
70
|
+
end
|
71
|
+
timestamp
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class IdAnalyzer
|
76
|
+
def initialize(id)
|
77
|
+
@id = id.to_i
|
78
|
+
@binary_id = @id.to_s(2).rjust(64, '0')
|
79
|
+
end
|
80
|
+
|
81
|
+
def analyze
|
82
|
+
{
|
83
|
+
timestamp: extract_timestamp,
|
84
|
+
datacenter_id: extract_datacenter_id,
|
85
|
+
worker_id: extract_worker_id,
|
86
|
+
sequence: extract_sequence,
|
87
|
+
timestamp_utc: timestamp_to_utc(extract_timestamp)
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def extract_timestamp
|
94
|
+
# Extract timestamp bits from the binary ID
|
95
|
+
timestamp_bits = @binary_id[0..41]
|
96
|
+
# Convert timestamp bits to integer
|
97
|
+
timestamp = timestamp_bits.to_i(2)
|
98
|
+
# Add the dynamic epoch (based on the first 41 bits of the ID)
|
99
|
+
timestamp += Snowflake::EPOCH
|
100
|
+
timestamp
|
101
|
+
end
|
102
|
+
|
103
|
+
def extract_datacenter_id
|
104
|
+
@binary_id[42..46].to_i(2)
|
105
|
+
end
|
106
|
+
|
107
|
+
def extract_worker_id
|
108
|
+
@binary_id[47..51].to_i(2)
|
109
|
+
end
|
110
|
+
|
111
|
+
def extract_sequence
|
112
|
+
@binary_id[52..63].to_i(2)
|
113
|
+
end
|
114
|
+
|
115
|
+
def timestamp_to_utc(timestamp)
|
116
|
+
Time.at(timestamp / 1000.0).utc
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# datacenter_id = ENV['DATACENTER_ID'].to_i
|
123
|
+
# worker_id = ENV['WORKER_ID'].to_i
|
124
|
+
# @generator = Snowflake::IdGenerator.new(datacenter_id, worker_id)
|
125
|
+
# p id = @generator.next_id
|
126
|
+
|
127
|
+
# p analyzer = Snowflake::IdAnalyzer.new(id).analyze
|
metadata
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snowflake_id_generator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.3'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kokorolx
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-24 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Generate unique Snowflake IDs across multiple data centers and workers
|
14
|
+
simultaneously using a distributed system.
|
15
|
+
email:
|
16
|
+
- kokoro.lehoang@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/snowflake_id_generator.rb
|
22
|
+
homepage: https://github.com/kokorolx/snowflake_id_generator
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubygems_version: 3.4.10
|
42
|
+
signing_key:
|
43
|
+
specification_version: 4
|
44
|
+
summary: Snowflake ID generator and analyzer service.
|
45
|
+
test_files: []
|