Skip to content

Instantly share code, notes, and snippets.

@imposeren
Last active May 18, 2016 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imposeren/870c65da097d5819b577e807c55b9c62 to your computer and use it in GitHub Desktop.
Save imposeren/870c65da097d5819b577e807c55b9c62 to your computer and use it in GitHub Desktop.
"""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