Skip to content

Repository files navigation

snowflake-ada

A Twitter Snowflake distributed ID generator library for Ada.

Status

Early development — Core ID generation complete with comprehensive test suite.

Features

  • ✅ 64-bit distributed IDs (Twitter Snowflake format)
  • ✅ Thread-safe generation via protected objects
  • ✅ Configurable custom epoch (default: Twitter's Nov 4, 2010)
  • ✅ Monotonic IDs within a node (newer = numerically greater)
  • ✅ ID decomposition (timestamp, node, sequence)
  • ✅ Clock-backwards detection (raises exception)
  • ✅ Sequence rollover handling (bounded 1ms wait)
  • ✅ Comprehensive test suite (14 tests covering edge cases)
  • ✅ Benchmarked: ~2.5M IDs/sec on Apple M1

ID Format

64-bit IDs with the following layout:

[63]      = unused (always 0)
[62..22]  = timestamp delta (41 bits, milliseconds since epoch)
[21..12]  = node ID (10 bits, 0..1023 — supports up to 1024 nodes)
[11..0]   = sequence (12 bits, 0..4095 — up to 4096 IDs/ms/node)
  • Time horizon: 41 bits represents ~69.7 years from epoch (Twitter epoch + 41 bits lasts until mid-2080)
  • Capacity: 4,096 unique IDs per millisecond per node

Build

Requires GNAT 16.1+ and gprbuild 26.0+ (via Alire).

# Build library
gprbuild -p -P snowflake_ada.gpr

# Build and run tests
gprbuild -p -P snowflake_ada_tests.gpr
./bin/snowflake-generator-tests

Usage

with Snowflake.Generator; use Snowflake.Generator;

--  Create a node (ID must be unique across your distributed system)
declare
   N : Node (Node_Num => 42, Epoch_MS => Default_Epoch);
   My_ID : ID;
begin
   --  Generate IDs
   N.Generate (My_ID);
   
   --  Decompose an ID
   declare
      TS : constant Unsigned_64 := To_Timestamp (My_ID);  -- Unix timestamp (ms)
      Node_Num : constant Node_ID := Node_Of (My_ID);     -- Node ID (0..1023)
      Step : constant Sequence := Step_Of (My_ID);        -- Sequence (0..4095)
   begin
      Put_Line ("Timestamp:" & Unsigned_64'Image (TS));
      Put_Line ("Node:" & Node_ID'Image (Node_Num));
      Put_Line ("Step:" & Sequence'Image (Step));
   end;
end;

Custom Epoch

--  Use a custom epoch (milliseconds since Unix epoch)
declare
   Custom_Epoch : constant Unsigned_64 := 1_600_000_000_000; -- Sept 2020
   N : Node (100, Custom_Epoch);
begin
   --  IDs encode timestamps relative to Custom_Epoch
end;

Design Choices

  • ID type: Unsigned_64 for natural bit operations and guaranteed monotonic ordering
  • Thread safety: Protected object ensures safe concurrent generation
  • Sequence overflow: Spins (delays) until next millisecond when 4096 IDs/ms exhausted (rare in practice)
  • Clock regression: Raises Clock_Backwards exception if system time moves backwards

Performance

Benchmark (Apple M1, macOS 15.7.3):

  • ~2.5M IDs/sec single-threaded generation (100k sample)

Roadmap

  • Core ID generation with tests
  • Alire publication
  • Multi-node coordination helpers
  • Custom epoch validation (warn on overflow approaching)

Reference

Based on bwmarrin/snowflake (Go, 3.7k★) and the Twitter Snowflake design.

License

MIT License — see LICENSE

Copyright © 2026 Konstantin Khlopkov

About

Twitter Snowflake distributed ID generator for Ada (64-bit: 41-bit timestamp + 10-bit node + 12-bit sequence)

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages