Created
August 11, 2019 17:23
-
-
Save KamilLelonek/56baff6f36c6c7fe0eded29a4dc8ffff to your computer and use it in GitHub Desktop.
This file contains hidden or 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
defmodule GlobalId do | |
@moduledoc """ | |
GlobalId module contains an implementation of a guaranteed globally unique id system. | |
It can be used for generating 64-bit unique IDs at high scale. | |
The IDs generated by this service are roughly time sortable. | |
""" | |
# NOTE: On production don't change it once set | |
epoch = {{1970, 1, 1}, {0, 0, 0}} | |
@epoch :calendar.datetime_to_gregorian_seconds(epoch) | |
@doc """ | |
Please implement the following function. | |
Since the IDs use timestamp as the first component, they are time sortable. | |
64 bit non negative integer output | |
""" | |
# NOTE: On production track increasing sequence | |
@spec get_id(sequence :: non_neg_integer) :: non_neg_integer | |
def get_id(sequence) do | |
<<new_id::unsigned-integer-64>> = | |
<<timestamp()::unsigned-integer-42, node_id()::unsigned-integer-10, | |
sequence::unsigned-integer-12>> | |
new_id | |
end | |
@doc """ | |
Returns your node id as an integer. | |
It will be greater than or equal to 0 and less than 1024. | |
It is guaranteed to be globally unique. | |
SIZE: 1024 = 2^10 - 10 bits | |
""" | |
@spec node_id() :: non_neg_integer | |
def node_id, | |
# NOTE: On production rely on node discovery | |
do: Enum.random(0..1024) | |
@doc """ | |
Returns timestamp since the epoch in milliseconds. | |
The maximum timestamp that can be represented using 42 bits is 2^42 - 1, | |
or 4398046511103, which comes out to be Wednesday, May 15, 2109 7:35:11.103 AM. | |
That gives us 139 years with respect to a custom epoch. | |
defp epoch do | |
2 | |
|> :math.pow(42) | |
|> Kernel.-(1) | |
|> round() | |
|> DateTime.from_unix!(:millisecond) | |
end | |
""" | |
@spec timestamp() :: non_neg_integer | |
def timestamp, | |
do: System.os_time(:millisecond) - @epoch | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment