Last active
September 5, 2017 23:09
-
-
Save gigamonkey/50bf1d44020d167df77a4c209f14892b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from time import sleep | |
from datetime import datetime, timezone | |
# Snowflake like ID generator that generates a 53-bit id suitable for sending as a number in JSON. | |
TIME_BITS = 40 | |
COUNTER_BITS = 10 | |
MACHINE_BITS = 3 | |
assert TIME_BITS + COUNTER_BITS + MACHINE_BITS <= 53 | |
TIME_MASK = (2 ** TIME_BITS) - 1 | |
COUNTER_MASK = (2 ** COUNTER_BITS) - 1 | |
MACHINE_MASK = (2 ** MACHINE_BITS) - 1 | |
EPOCH = int(datetime(2016, 11, 8, tzinfo=timezone.utc).timestamp() * 1000) | |
def since_epoch(): | |
dt = datetime.utcnow() | |
return int(dt.replace(tzinfo=timezone.utc).timestamp() * 1000) - EPOCH | |
def make_id(time, counter, machine_id): | |
assert 0 <= machine_id <= 7, "Invalid machine id: {}".format(machine_id) | |
t = (time & TIME_MASK) << (COUNTER_BITS + MACHINE_BITS) | |
c = (counter & COUNTER_MASK) << MACHINE_BITS | |
return t + c + machine_id | |
def ids(machine_id): | |
counter = 0 | |
last_ts = 0 | |
while True: | |
ts = since_epoch() | |
# Whenever the counter rolls over wait a bit to make sure the | |
# timestamp has advanced at least a millisecond. | |
if counter == 0: | |
while ts == last_ts: | |
sleep(0.0001) | |
ts = since_epoch() | |
last_ts = ts | |
yield make_id(ts, counter, machine_id) | |
counter += 1 | |
counter %= (2 ** COUNTER_BITS) | |
def age(id): | |
return id >> (COUNTER_BITS + MACHINE_BITS) | |
def counter(id): | |
return (id >> MACHINE_BITS) & COUNTER_MASK | |
def machine(id): | |
return id & MACHINE_MASK | |
if __name__ == '__main__': | |
g1 = ids(0) | |
for _ in range(1030): | |
id = next(g1) | |
print("{}: age: {}; counter: {}; machine: {}".format(id, age(id), counter(id), machine(id))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment