1+ import time
2+ import threading
3+ class SnowflakeGenerator :
4+ def __init__ (self , worker_id = 0 , datacenter_id = 0 ):
5+ self .worker_id = worker_id
6+ self .datacenter_id = datacenter_id
7+ self .sequence = 0
8+ self .last_timestamp = - 1
9+ self .lock = threading .Lock ()
10+
11+ self .worker_id_bits = 5
12+ self .datacenter_id_bits = 5
13+ self .max_worker_id = - 1 ^ (- 1 << self .worker_id_bits )
14+ self .max_datacenter_id = - 1 ^ (- 1 << self .datacenter_id_bits )
15+ self .sequence_bits = 12
16+
17+ self .worker_id_shift = self .sequence_bits
18+ self .datacenter_id_shift = self .sequence_bits + self .worker_id_bits
19+ self .timestamp_left_shift = self .sequence_bits + self .worker_id_bits + self .datacenter_id_bits
20+ self .sequence_mask = - 1 ^ (- 1 << self .sequence_bits )
21+
22+ if self .worker_id > self .max_worker_id or self .worker_id < 0 :
23+ raise ValueError (f"worker ID can't be greater than { self .max_worker_id } or less than 0" )
24+ if self .datacenter_id > self .max_datacenter_id or self .datacenter_id < 0 :
25+ raise ValueError (f"datacenter ID can't be greater than { self .max_datacenter_id } or less than 0" )
26+
27+ def _current_time (self ):
28+ return int (time .time () * 1000 )
29+
30+ def _wait_next_millis (self , last_timestamp ):
31+ timestamp = self ._current_time ()
32+ while timestamp <= last_timestamp :
33+ timestamp = self ._current_time ()
34+ return timestamp
35+
36+ def generate_id (self ):
37+ with self .lock :
38+ timestamp = self ._current_time ()
39+
40+ if timestamp < self .last_timestamp :
41+ raise ValueError ("Clock moved backwards. Refusing to generate ID" )
42+
43+ if timestamp == self .last_timestamp :
44+ self .sequence = (self .sequence + 1 ) & self .sequence_mask
45+ if self .sequence == 0 :
46+ timestamp = self ._wait_next_millis (self .last_timestamp )
47+ else :
48+ self .sequence = 0
49+
50+ self .last_timestamp = timestamp
51+
52+ return ((timestamp << self .timestamp_left_shift ) |
53+ (self .datacenter_id << self .datacenter_id_shift ) |
54+ (self .worker_id << self .worker_id_shift ) |
55+ self .sequence )
56+
57+ snowflake = SnowflakeGenerator (worker_id = 1 )
0 commit comments