From e120dc260f4c338360944fb7b54fb108c4487366 Mon Sep 17 00:00:00 2001 From: Roman Shkryl Date: Sun, 20 Sep 2026 23:34:24 +0300 Subject: [PATCH 1/7] Added and changed constants. --- src/part1/constants.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/part1/constants.py b/src/part1/constants.py index 9abfbba2..a01b7b98 100644 --- a/src/part1/constants.py +++ b/src/part1/constants.py @@ -15,24 +15,23 @@ from typing import Final -# TODO: замените заглушки (0) на корректные значения, см. TASK.md. -# Все константы, зависящие от ёмкостей *_BITS, должны вычисляться из них. + # Twitter's original Snowflake epoch: 2010-11-04 01:42:54.657 UTC. -EPOCH_MS_DEFAULT: Final[int] = 0 +EPOCH_MS_DEFAULT: Final[int] = 1288834974657 # Node identifier used when the caller does not supply one. -NODE_ID_DEFAULT: Final[int] = 0 +NODE_ID_DEFAULT: Final[int] = 1 # Width of each field, in bits. -TIMESTAMP_BITS: Final[int] = 0 -NODE_ID_BITS: Final[int] = 0 -SEQUENCE_ID_BITS: Final[int] = 0 +TIMESTAMP_BITS: Final[int] = 41 +NODE_ID_BITS: Final[int] = 10 +SEQUENCE_ID_BITS: Final[int] = 12 # Largest value each field can hold. -TIMESTAMP_MS_MAX: Final[int] = 0 -NODE_ID_MAX: Final[int] = 0 -SEQUENCE_ID_MAX: Final[int] = 0 +TIMESTAMP_MS_MAX: Final[int] = 2 ** TIMESTAMP_BITS - 1 +NODE_ID_MAX: Final[int] = 2 ** NODE_ID_BITS - 1 +SEQUENCE_ID_MAX: Final[int] = 2 ** SEQUENCE_ID_BITS - 1 # Здесь можно добавить собственные вспомогательные константы # (например, сдвиги полей при сборке идентификатора). From 0aebe01c8b4a70035f7f2f09135a84fb68718728 Mon Sep 17 00:00:00 2001 From: Roman Shkryl Date: Sun, 20 Sep 2026 23:44:07 +0300 Subject: [PATCH 2/7] Added function 'read_current_millis' --- src/part1/snowflake.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index d3abf050..81bed18d 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -25,17 +25,10 @@ def read_current_millis(epoch_ms: int) -> int: - """Read the number of milliseconds elapsed since the custom epoch. + current_time = int(time.time() * 1000) - Args: - epoch_ms: The custom epoch expressed as Unix milliseconds. - Returns: - The count of whole milliseconds between ``epoch_ms`` and now. May be - negative if ``epoch_ms`` lies in the future. - """ - # TODO: реализуйте функцию - return 0 + return current_time - epoch_ms def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int: From 5ce5d0d5f6c288b905c4afd6f45efffd0c70ceef Mon Sep 17 00:00:00 2001 From: Roman Shkryl Date: Mon, 21 Sep 2026 15:05:42 +0300 Subject: [PATCH 3/7] modifided 'decode_timestamp_ms' --- src/part1/snowflake.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 81bed18d..2b2e3f18 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -32,32 +32,13 @@ def read_current_millis(epoch_ms: int) -> int: def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int: - """Read the timestamp field out of a Snowflake identifier. + default_time = snowflake_id >> 22 - Args: - snowflake_id: An identifier produced against the same epoch. - epoch_ms: The epoch the identifier was generated against. Defaults to - the original Twitter epoch (2010-11-04 01:42:54.657 UTC). - Returns: - The absolute Unix time in milliseconds at which the identifier was - generated. - """ - # TODO: реализуйте функцию - return 0 + return default_time + epoch_ms def decode_node_id(snowflake_id: int) -> int: - """Read the node identifier field out of a Snowflake identifier. - - Args: - snowflake_id: An identifier produced by :func:`generate_snowflake_id`. - - Returns: - The node identifier packed into ``snowflake_id``, in the range - ``[0, NODE_ID_MAX]``. - """ - # TODO: реализуйте функцию return 0 From 2de06967bd4a7fa29568b2d34475569100661f2e Mon Sep 17 00:00:00 2001 From: Roman Shkryl Date: Mon, 21 Sep 2026 15:10:30 +0300 Subject: [PATCH 4/7] modificed 'decode_node_id' --- src/part1/snowflake.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 2b2e3f18..9798a340 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -39,7 +39,9 @@ def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> def decode_node_id(snowflake_id: int) -> int: - return 0 + node_id = (snowflake_id >> 12) & 0b1111111111 + + return node_id def decode_sequence_id(snowflake_id: int) -> int: From b1f51c48c003d628162ba24a1ad2af6706686849 Mon Sep 17 00:00:00 2001 From: Roman Shkryl Date: Mon, 21 Sep 2026 15:12:49 +0300 Subject: [PATCH 5/7] modificed 'decode_sequence_id' --- src/part1/snowflake.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 9798a340..4d6217af 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -45,17 +45,9 @@ def decode_node_id(snowflake_id: int) -> int: def decode_sequence_id(snowflake_id: int) -> int: - """Read the sequence counter field out of a Snowflake identifier. + sequence_id = snowflake_id & 0b111111111111 - Args: - snowflake_id: An identifier produced by :func:`generate_snowflake_id`. - - Returns: - The per-millisecond sequence counter packed into ``snowflake_id``, in - the range ``[0, SEQUENCE_ID_MAX]``. - """ - # TODO: реализуйте функцию - return 0 + return sequence_id def generate_snowflake_id( From 2af0c8083b601df14b0e6db9e064baab9a93d7f9 Mon Sep 17 00:00:00 2001 From: Roman Shkryl Date: Mon, 21 Sep 2026 15:33:24 +0300 Subject: [PATCH 6/7] modificed 'generate_snowflake_id' --- src/part1/snowflake.py | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 4d6217af..2abce632 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -55,28 +55,20 @@ def generate_snowflake_id( node_id: int = NODE_ID_DEFAULT, epoch_ms: int = EPOCH_MS_DEFAULT, ) -> int | None: - """Build and return a Snowflake identifier for the current millisecond. - - The function is stateless: the caller passes the per-millisecond sequence - counter explicitly. It is the caller's responsibility to increment - ``sequence_id`` for identifiers minted within the same millisecond and to - reset it once the clock advances. - - Args: - sequence_id: The per-millisecond sequence counter, in the range - ``[0, SEQUENCE_ID_MAX]``. - node_id: The identifier of this node, in the range ``[0, NODE_ID_MAX]``. - Optional; defaults to ``NODE_ID_DEFAULT``. - epoch_ms: The start of the epoch as Unix milliseconds. Optional; - defaults to the original Twitter epoch (2010-11-04 01:42:54.657 - UTC). - - Returns: - The Snowflake identifier as a positive 63-bit integer, or ``None`` if - ``node_id`` is outside ``[0, NODE_ID_MAX]``, ``sequence_id`` is outside - ``[0, SEQUENCE_ID_MAX]``, or the elapsed time no longer fits in the - timestamp field (roughly 69 years after ``epoch_ms``). In each of those - cases an explanatory message is printed to stdout first. - """ - # TODO: реализуйте функцию - return 0 + + if (node_id < 0 or node_id > NODE_ID_MAX): + print('node_id must be in range[0; 1023]') + return None + + + elif (sequence_id < 0 or sequence_id > SEQUENCE_ID_MAX): + print('sequence_id must be in [0; 4095]') + return None + + + elif (decode_timestamp_ms(epoch_ms) > TIMESTAMP_MS_MAX): + print('overflows') + return None + + + return read_current_millis(epoch_ms) << 22 | node_id << 12 | sequence_id From ca03d8378031869a5d0bb99b9bec304251ed760f Mon Sep 17 00:00:00 2001 From: Roman Shkryl Date: Mon, 21 Sep 2026 15:46:10 +0300 Subject: [PATCH 7/7] fixed shorcoming --- src/part1/constants.py | 28 +++------------------------- src/part1/snowflake.py | 39 ++++++++------------------------------- 2 files changed, 11 insertions(+), 56 deletions(-) diff --git a/src/part1/constants.py b/src/part1/constants.py index a01b7b98..afc19ecf 100644 --- a/src/part1/constants.py +++ b/src/part1/constants.py @@ -1,37 +1,15 @@ -"""Bit layout and default epoch for the Twitter Snowflake ID generator. - -A Snowflake identifier is a 63-bit positive integer packed as follows, from -the most significant bit downwards: - - 1 bit unused sign bit, always zero - 41 bits milliseconds elapsed since a custom epoch - 10 bits node identifier - 12 bits per-millisecond sequence counter - -The shift and mask constants should be derived from the bit widths so that -changing a width keeps everything else consistent. -""" - from typing import Final - - -# Twitter's original Snowflake epoch: 2010-11-04 01:42:54.657 UTC. EPOCH_MS_DEFAULT: Final[int] = 1288834974657 -# Node identifier used when the caller does not supply one. NODE_ID_DEFAULT: Final[int] = 1 -# Width of each field, in bits. TIMESTAMP_BITS: Final[int] = 41 NODE_ID_BITS: Final[int] = 10 SEQUENCE_ID_BITS: Final[int] = 12 -# Largest value each field can hold. -TIMESTAMP_MS_MAX: Final[int] = 2 ** TIMESTAMP_BITS - 1 -NODE_ID_MAX: Final[int] = 2 ** NODE_ID_BITS - 1 -SEQUENCE_ID_MAX: Final[int] = 2 ** SEQUENCE_ID_BITS - 1 -# Здесь можно добавить собственные вспомогательные константы -# (например, сдвиги полей при сборке идентификатора). +TIMESTAMP_MS_MAX: Final[int] = 2**TIMESTAMP_BITS - 1 +NODE_ID_MAX: Final[int] = 2**NODE_ID_BITS - 1 +SEQUENCE_ID_MAX: Final[int] = 2**SEQUENCE_ID_BITS - 1 diff --git a/src/part1/snowflake.py b/src/part1/snowflake.py index 2abce632..7c441711 100644 --- a/src/part1/snowflake.py +++ b/src/part1/snowflake.py @@ -1,21 +1,6 @@ -"""Twitter Snowflake identifier generator. +import time -Snowflake produces roughly time-ordered 64-bit integer identifiers without -coordination between nodes. Each identifier packs the milliseconds elapsed -since a custom epoch, a node identifier and a per-millisecond sequence counter -into a single 63-bit positive integer (see ``constants`` for the layout). - -The public entry point is :func:`generate_snowflake_id`. It is stateless: the -caller passes the sequence counter on every call and is responsible for -advancing it within a millisecond and resetting it when the clock ticks over. - -Each packed field can be read back on its own with :func:`decode_timestamp_ms`, -:func:`decode_node_id` and :func:`decode_sequence_id`. -""" - -import time # noqa: F401 - -from .constants import ( # noqa: F401 +from .constants import ( EPOCH_MS_DEFAULT, NODE_ID_DEFAULT, NODE_ID_MAX, @@ -27,14 +12,12 @@ def read_current_millis(epoch_ms: int) -> int: current_time = int(time.time() * 1000) - return current_time - epoch_ms def decode_timestamp_ms(snowflake_id: int, epoch_ms: int = EPOCH_MS_DEFAULT) -> int: default_time = snowflake_id >> 22 - return default_time + epoch_ms @@ -55,20 +38,14 @@ def generate_snowflake_id( node_id: int = NODE_ID_DEFAULT, epoch_ms: int = EPOCH_MS_DEFAULT, ) -> int | None: - - if (node_id < 0 or node_id > NODE_ID_MAX): - print('node_id must be in range[0; 1023]') + if node_id < 0 or node_id > NODE_ID_MAX: + print("node_id must be in range[0; 1023]") return None - - - elif (sequence_id < 0 or sequence_id > SEQUENCE_ID_MAX): - print('sequence_id must be in [0; 4095]') + elif sequence_id < 0 or sequence_id > SEQUENCE_ID_MAX: + print("sequence_id must be in [0; 4095]") return None - - - elif (decode_timestamp_ms(epoch_ms) > TIMESTAMP_MS_MAX): - print('overflows') + elif decode_timestamp_ms(epoch_ms) > TIMESTAMP_MS_MAX: + print("overflows") return None - return read_current_millis(epoch_ms) << 22 | node_id << 12 | sequence_id