101 lines
3.5 KiB
Text
101 lines
3.5 KiB
Text
{0 Uuidm {%html: <span class="version">v0.9.10+dune</span>%}}
|
|
|
|
{!Uuidm} implements 128 bits universally unique identifiers version 3,
|
|
5 (named based with MD5, SHA-1 hashing), 4 (random based), 7 (time and
|
|
random based) and 8 (custom) according according to
|
|
{{:https://www.rfc-editor.org/rfc/rfc9562} RFC 9562}.
|
|
|
|
See the {{!quick}quick start}.
|
|
|
|
{1:uuidm_lib Library [uuidm]}
|
|
|
|
{!modules: Uuidm}
|
|
|
|
{1:quick Quick start}
|
|
|
|
{2:random_based Random V4 UUIDs}
|
|
|
|
The following [uuid] function generates V4 random UUIDs.
|
|
|
|
{[
|
|
let uuid = Uuidm.v4_gen (Random.State.make_self_init ())
|
|
let () = print_endline (Uuidm.to_string (uuid ()))
|
|
let () = print_endline (Uuidm.to_string (uuid ()))
|
|
]}
|
|
|
|
Make sure to read the {{!Uuidm.gen}warnings} about random generators.
|
|
|
|
{2:name_based Name based V5 UUIDs}
|
|
|
|
Name based V5 UUIDs can be used to generate [urn:uuid] URIs for atom
|
|
feed {{:https://www.rfc-editor.org/rfc/rfc4287#section-4.2.6}entry
|
|
IDs} to minimize the chances of feed replays.
|
|
|
|
First generate a random V4 UUID for the feed. For example with
|
|
the code of the previous section or with:
|
|
{@shell[
|
|
> uuidtrip
|
|
6228c5f9-7069-4519-9bf4-0b6e865f4c42
|
|
]}
|
|
|
|
Store this UUID preciously and use it as your feed ID:
|
|
|
|
{[
|
|
let feed_id ~feed_id = "urn:uuid:" ^ (Uuid.to_string feed_id)
|
|
]}
|
|
|
|
For feed entry IDs, use the feed UUID as a V5 namespace and the immutable
|
|
{{:https://www.rfc-editor.org/rfc/rfc4287#section-4.2.9}[atom:published]}
|
|
value of the entry as the data to hash:
|
|
|
|
{[
|
|
let entry_id ~feed_id ~rfc3339_stamp =
|
|
"urn:uuid:" ^ (Uuidm.to_string @@ Uuidm.v5 feed_id rfc3339_stamp)
|
|
]}
|
|
|
|
This assumes that
|
|
|
|
{ol
|
|
{- You do not publish two entries at exactly the same time.
|
|
{{:https://www.rfc-editor.org/rfc/rfc3339}RFC 3339} has
|
|
enough time granularity to ensure that.}
|
|
{- You do not change your publication dates. In atom they must in fact
|
|
not change, updates to entries must be specified
|
|
in {{:https://www.rfc-editor.org/rfc/rfc4287#section-4.2.15}[atom:updated]}.}
|
|
{- If you store publication dates as a raw POSIX timestamp be careful
|
|
to render them to RFC 3339 with a fixed time zone. Alternatively
|
|
you can directly use the decimal representation of the timestamp
|
|
as the data to hash.}}
|
|
|
|
{2:time_based Monotonic time based V7 UUIDs}
|
|
|
|
In order to generate monotonic time based V7 UUIDs we need to:
|
|
|
|
{ul
|
|
{- Provide a millisecond precision monotonic POSIX clock. {!Unix.gettimeofday}
|
|
can provide a reasonable one but if your monotonicity requirements are
|
|
paramount, remember that it can go back in time.}
|
|
{- Do something if the clock doesn't move between two UUID
|
|
generations. The {!Uuidm.v7_monotonic_gen} generator uses a counter which
|
|
allows to generate up to 4096 UUID per millisecond and returns [None] in case
|
|
of rollover during the millisecond. In the code below we {!Unix.sleepf}
|
|
for a millisecond if we reach the limit.}}
|
|
|
|
{[
|
|
let uuid_monotonic =
|
|
let now_ms () = Int64.of_float (Unix.gettimeofday () *. 1000.) in
|
|
Uuidm.v7_monotonic_gen ~now_ms (Random.State.make_self_init ())
|
|
|
|
let rec uuid () = match uuid_monotonic () with
|
|
| None -> (* Too many UUIDs generated in a ms *) Unix.sleepf 1e-3; uuid ()
|
|
| Some uuid -> uuid
|
|
|
|
let () = print_endline (Uuidm.to_string (uuid ()))
|
|
let () = print_endline (Uuidm.to_string (uuid ()))
|
|
]}
|
|
|
|
Depending on your application {!Uuidm.v7_monotonic_gen} may be a bit
|
|
too simplistic, you can easily implement all sorts of other
|
|
{{:https://www.rfc-editor.org/rfc/rfc9562#name-monotonicity-and-counters}
|
|
generation schemes} by using {!Uuidm.v7} or {!Uuidm.v7_ns} directly. Also, make
|
|
sure to read the {{!Uuidm.gen}warnings} about generators.
|