Last active
May 18, 2016 13:43
-
-
Save imposeren/870c65da097d5819b577e807c55b9c62 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
"""Sortable by time "id-generator" with configurable bit-length of time-, node-, random-based parts""" | |
import time | |
import random | |
import uuid | |
_last_delta_time_val = None | |
_default_offset_nanosecs = 1463565297762000000 | |
_bit_masks = {} | |
def get_bit_mask(bits): | |
"""return int with binary represantation of '1' repeated ``bits`` times.""" | |
if bits not in _bit_masks: | |
_bit_masks[bits] = (1 << bits) - 1 | |
return _bit_masks[bits] | |
def shorter_id( | |
node=None, time_bits=47, node_bits=6, random_bits=11, time_detalization=2, | |
offset_nanosecs=_default_offset_nanosecs, | |
): | |
"""Return integer constructed from time, node and random bits. | |
:param int random_bits: last part of id will have this number of random bits | |
:param int node_bits: | |
next part of id will have this number of bits constructed from | |
:py:func:`uuid.getnode` (uses HW-addr or random 48 bit value) | |
:param int time_bits: | |
next part of id will have this number of bits constructed from :py:func:`time.time` | |
:param int time_detalization: | |
``time.time()-X`` is multiplied by 10**time_detalization before it's used | |
:param int offset_nanosecs: | |
number of nanoseconds subsracted from ``time.time()`` | |
Some details on collision probability for calls with same arguments on same node: | |
* collision on single node is only possible when timestamps collide. This is | |
impossible for single process and very unlikely on multiple processes. | |
* collisions on multiple nodes are only possible when `node` part matches. | |
So it's better to ensure that different nodes have different bits in their `uuid.getnode()` | |
* on nodes with same id collision is only possible when timestamp parts match. | |
When such situation happens probability of 2 ids to collide is `1/(2**(random_bits*2))` | |
(around 0.000024% for 11 bits of random part) | |
""" | |
global _last_delta_time_val | |
current_time_nanosecs = int(time.time() * 1e9) | |
delta_time_val = int((current_time_nanosecs - offset_nanosecs) / (10**(9-time_detalization))) | |
if _last_delta_time_val is not None and delta_time_val <= _last_delta_time_val: | |
delta_time_val = _last_delta_time_val + 1 | |
_last_delta_time_val = delta_time_val | |
if node is None: | |
node = uuid.getnode() | |
time_val = delta_time_val & get_bit_mask(time_bits) | |
node_val = uuid.getnode() & get_bit_mask(node_bits) | |
random_val = random.randrange(get_bit_mask(random_bits)) | |
total_val = (time_val << node_bits) | node_val | |
total_val = (total_val << random_bits) | random_val | |
return total_val |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment