Dive C4.07.1
The Snowflake
A 64-bit integer that carries its own clock. Read its high bits and you have the time it was made — to the millisecond.
A Snowflake packs three fields into one int64: a millisecond
timestamp in the high bits, a node id in the middle, and a within-millisecond
sequence in the low bits. EchoMQ uses the exact layout in echo_fs/EchoMQ/Snowflake.fs:
(ts - Epoch) << 22 | node << 12 | seq, against the epoch
1704067200000 (2024-01-01). Because the timestamp is the high field, a later mint is always a
larger integer — the property the queue turns into "byte order is mint order". This dive composes one, then reads it
back with shifts and masks; every value was produced by dotnet fsi.
The layout — three fields in one integer
The 64 bits split into one unused sign bit, then a 42-bit timestamp, a 10-bit node id, and a 12-bit sequence.
NodeBits = 10 and SeqBits = 12, so the timestamp is shifted left
by 22 and the node by 12. The constants and the compose function
below are quoted verbatim from echo_fs/EchoMQ/Snowflake.fs.
module Snowflake = [<Literal>] let Epoch = 1704067200000L // 2024-01-01T00:00:00Z [<Literal>] let NodeBits = 10 [<Literal>] let SeqBits = 12 let private nodeMax = (1L <<< NodeBits) - 1L let private seqMax = (1L <<< SeqBits) - 1L /// Compose a snowflake from a wall-clock millisecond, a node id, and a sequence. let compose (tsMs: int64) (node: int64) (seq: int64) : int64 = ((tsMs - Epoch) <<< (NodeBits + SeqBits)) ||| ((node &&& nodeMax) <<< SeqBits) ||| (seq &&& seqMax)
- Epoch
- the custom zero point,
1704067200000Lms (2024-01-01). The stored timestamp istsMs - Epoch, which keeps the value small and within 42 bits for decades. - NodeBits / SeqBits
10and12, sonoderanges 0–1023 andseqranges 0–4095 within one millisecond.- nodeMax / seqMax
- the masks
(1L <<< bits) - 1L— all-ones for that field — used to clamp each input before it is OR-ed in. - <<< · ||| · &&&
- F#'s left-shift, bitwise-OR, and bitwise-AND on
int64. The shift places each field; the OR merges them; the AND keeps each field within its width.
Reading it back — shifts and masks
Each accessor undoes one part of the composition. timestamp shifts the high bits back down
and re-adds the epoch; node shifts past the sequence and masks; seq
masks the low 12 bits. at turns the timestamp into a DateTimeOffset.
All four are quoted verbatim.
/// The wall-clock millisecond the id was minted at. let timestamp (id: int64) : int64 = (id >>> (NodeBits + SeqBits)) + Epoch /// The minting node id. let node (id: int64) : int64 = (id >>> SeqBits) &&& nodeMax /// The within-millisecond sequence. let seq (id: int64) : int64 = id &&& seqMax /// The mint instant as a DateTimeOffset. let at (id: int64) : System.DateTimeOffset = System.DateTimeOffset.FromUnixTimeMilliseconds(timestamp id)
Composed and read back in FSI, for a fixed example — minted at
2024-06-01T12:00:00Z, node 7, sequence 0:
let id = Snowflake.compose 1717243200000L 7L 0L // val id : int64 = 55264149504028672L Snowflake.timestamp id // val it : int64 = 1717243200000L Snowflake.node id // val it : int64 = 7L Snowflake.seq id // val it : int64 = 0L Snowflake.at id // val it : DateTimeOffset = 01/06/2024 12:00:00 +00:00
timestamp (compose tsMs node seq) = tsMs whenever the
inputs fit their fields. The unused sign bit keeps the integer non-negative, so it compares and sorts as an
ordinary positive int64.Decode the bits
Pick a field. The diagram marks it; the readout shows that field's value for a fixed example id, computed by the
same shift-and-mask the F# accessors use. The id is 55264149504028672 —
Snowflake.compose 1717243200000L 7L 0L, verified in FSI. The decode runs in this page's
JavaScript with the identical layout (id >>> 22,
(id >>> 12) & 0x3FF, id & 0xFFF).
A 64-bit Snowflake · select a field
The clock lives inside the number. No created_at column, no central counter — sort
the integers and you have sorted by time.
Why the timestamp is the high field
Field order decides sort order. With the timestamp in the high bits, two ids minted in different milliseconds compare in time order regardless of node or sequence — a later millisecond is a strictly larger integer. Within one millisecond, the sequence breaks ties; across nodes, the node id breaks the remaining ties. The result is a total order that needs no coordination: every node mints on its own and the integers still line up by time.
// three mints; A and B share a millisecond, C is one ms later (FSI) let a = Snowflake.compose 1717243200000L 7L 0L // 55264149504028672L let b = Snowflake.compose 1717243200000L 7L 1L // 55264149504028673L let c = Snowflake.compose 1717243200001L 7L 0L // 55264149508222976L a < b && b < c // val it : bool = true
The layout gives
Timestamp high, node middle, sequence low — a single int64 whose numeric order is mint order.
The next dive asks
How does this integer travel as a string and keep that order? Base62, fixed width, ascending alphabet — C4.07.2.
EchoMQ in F#
EchoMQ gives each job a Snowflake.compose id, so the pending set is held in mint order with
no second index — the bus serves the oldest job first by reading the smallest id. The single-writer broker advances
the sequence within a millisecond and lets the timestamp tick when it exhausts, exactly as the layout intends.
The F# EchoMQ mints these ids today — Snowflake is built and tested
(SnowflakeTests covers the compose/decode round trip). The Valkey transport
EchoMQ.Connector lands next.
The cost model on .NET
An int64 is a value type: 8 bytes, stored inline in a record or on the stack, with no heap
allocation and no boxing in the integer path. compose and every accessor are constant-time
bit operations — a handful of shifts, ORs, and ANDs that the JIT lowers to single machine instructions. The Elixir
course (E4.07) builds the same Snowflake on the BEAM, where an integer is a tagged term; on the CLR it is a machine
word, so F#'s integer path allocates nothing.
Status — echo_fs is an in-memory model. The EchoMQ protocol — the Lua transitions executing on a Valkey wire — is not implemented (there is no Lua and no Valkey client in the code); that is the coming-soon transport (EchoMQ.Connector). This block shows how the model uses the structure, not a running bus.
References
Sources
- Microsoft — F# documentation — integers, literals, and the bitwise operators
<<<,>>>,|||,&&&. - FSharp.Core API reference — the operators module these accessors use.
- Microsoft — .NET documentation —
System.Int64andDateTimeOffset.FromUnixTimeMilliseconds. - The F# Software Foundation — F# on the .NET runtime.
Related in this course
- Elixir — The Snowflake bigint — the same layout on the BEAM.
- C4.07.2 — Base62 — how this integer travels as a string and keeps its order.
- C4.07.3 — Branded ids — the namespace and the validity gate.
- C4.07 — Identifiers — the module hub.