-
Notifications
You must be signed in to change notification settings - Fork 54
1.7. UUIDv7
This is an implementation of UUID v7.
This library provides 3 types:
-
Type 1 (default):
- Time: 48 bits.
- Counter: 26 bits (incremented by 1).
- Random: 48 bits (always randomized).
-
Type 2 (plus 1):
- Time: 48 bits.
- Monotonic random: 74 bits (incremented by 1).
-
Type 3 (plus n):
- Time: 48 bits.
- Monotonic random: 74 bits (incremented by a random number).
You probably need Type 1.
If the runtime provides sufficient clock precision, microseconds will also be injected into the UUID, specifically in rand_a field (specified in RFC 9562). In JDK 11, we have enough precision. However, in JDK 8, millisecond precision is the best we can get.
π‘ HINT
UUIDv6, UUIDv7, and UUIDv8; what are they?: https://playfulprogramming.com/posts/uuid-v6-8
Type 1 uses method 1 of the specification to generate UUIDv7. This type is twice as fast as UUID.randomUUID().
UUID uuid = UuidCreator.getTimeOrderedEpoch();
Structure of the UUID v7:
01720b5c-bf10-77cc-b631-4f262f500172
^^^^ ^^^^ <- plus 1
|-------------|---------|------------|
time counter random
Notes:
* The counter component is randomized when the time changes.
* The counter component is incremented by 1 when the time repeats.
* The random component is always randomized.
Sequence of UUID v7:
0181be8a-e592-73d4-84fe-aaca0740fa1d
0181be8a-e592-73d4-84ff-f59a5a4d9115
0181be8a-e592-73d4-8500-d5affa859d31
0181be8a-e592-73d4-8501-afb19130e7c4
0181be8a-e592-73d4-8502-a802d8fa7689
0181be8a-e592-73d4-8503-b712f3ca2caa
0181be8a-e592-73d4-8504-09b220ad9b8c
0181be8a-e592-73d4-8505-28cdc6fd9d64
0181be8a-e593-7693-8890-3fd3dc34aeec < millisecond changed
0181be8a-e593-7693-8891-eab210bf4dba
0181be8a-e593-7693-8892-a2fd10099b16
0181be8a-e593-7693-8893-801739366152
0181be8a-e593-7693-8894-de1f8c2f3f39
0181be8a-e593-7693-8895-817d9bb344ef
0181be8a-e593-7693-8896-b3cd2cffbebe
0181be8a-e593-7693-8897-8dc4c8d2f4bd
^ look ^ look
|-------------|---------|------------|
time counter random
Type 2 uses method 2 from spec to generate UUIDv7. The least significant bits are incremented by 1 when the time has not changed since the last generated UUIDv7. This type can be 20x faster than UUID.randomUUID().
UUID uuid = UuidCreator.getTimeOrderedEpochPlus1();
Structure of the UUID v7 with increments of 1:
01720b5c-bf10-77cc-b631-4f262f500172
^^^^ ^^^^ ^^^^^^^^^^^^ <- plus 1
|-------------|----------------------|
time monotonic random
Notes:
* The monotonic random component is randomized when the time changes.
* The monotonic random component incremented by 1 when the time repeats.
Sequence of UUID v7:
0181be8a-e59a-73c8-b04c-06c9c7ab6d56
0181be8a-e59a-73c8-b04c-06c9c7ab6d57
0181be8a-e59a-73c8-b04c-06c9c7ab6d58
0181be8a-e59a-73c8-b04c-06c9c7ab6d59
0181be8a-e59a-73c8-b04c-06c9c7ab6d5a
0181be8a-e59a-73c8-b04c-06c9c7ab6d5b
0181be8a-e59a-73c8-b04c-06c9c7ab6d5c
0181be8a-e59a-73c8-b04c-06c9c7ab6d5d
0181be8a-e59b-7392-84bc-79c4faadcad8 < millisecond changed
0181be8a-e59b-7392-84bc-79c4faadcad9
0181be8a-e59b-7392-84bc-79c4faadcada
0181be8a-e59b-7392-84bc-79c4faadcadb
0181be8a-e59b-7392-84bc-79c4faadcadc
0181be8a-e59b-7392-84bc-79c4faadcadd
0181be8a-e59b-7392-84bc-79c4faadcade
0181be8a-e59b-7392-84bc-79c4faadcadf
^ look ^ look
|-------------|----------------------|
time monotonic random
Type 3 uses method 2 from spec to generate UUID v7. The least significant bits are incremented by a random number when the time has not changed since the last generated UUIDv7. This type is at least twice as fast as UUID.randomUUID().
The random number has a maximum value of 2^32. However, a different maximum value can be specified for TimeOrderedEpochFactory if necessary.
UUID uuid = UuidCreator.getTimeOrderedEpochPlusN();
Structure of the UUID v7 with random increments:
01720b5c-bf10-77cc-b631-4f262f500172
^^^^ ^^^^ ^^^^^^^^^^^^ <- plus n, where 1 <= n <= 2^32
|-------------|----------------------|
time monotonic random
* The monotonic random component is randomized when the time changes.
* The monotonic random component incremented by a positive integer `n` when the time repeats.
* The positive integer `n` maximum value can be specified via factory builder.
* The positive integer `n` is always randomized.
Sequence of UUID v7:
0181be8a-e5ac-7cc0-a3e5-84ea795e8418
0181be8a-e5ac-7cc0-a3e5-84eaceb743e7
0181be8a-e5ac-7cc0-a3e5-84ebb3b9dbe7
0181be8a-e5ac-7cc0-a3e5-84eca0e14876
0181be8a-e5ac-7cc0-a3e5-84ed1fdc19c6
0181be8a-e5ac-7cc0-a3e5-84ee082176d8
0181be8a-e5ac-7cc0-a3e5-84ee1d1f63ae
0181be8a-e5ac-7cc0-a3e5-84eeafd13b2a
0181be8a-e5ad-790f-91a1-900fe2d661cc < millisecond changed
0181be8a-e5ad-790f-91a1-901051bb5f55
0181be8a-e5ad-790f-91a1-90110ca4ebf6
0181be8a-e5ad-790f-91a1-901119498fd6
0181be8a-e5ad-790f-91a1-9011903ff6aa
0181be8a-e5ad-790f-91a1-901215a742d8
0181be8a-e5ad-790f-91a1-9012407c8742
0181be8a-e5ad-790f-91a1-90127c104374
^ look ^ look
|-------------|----------------------|
time monotonic random
A key generator that makes substitution easy if necessary:
package com.example; import com.github.f4b6a3.uuid.UuidCreator; public class UuidGenerator { public static UUID generate() { return UuidCreator.getTimeOrderedEpoch(); } }
UUID uuid = UuidGenerator.generate();
An UUID v7 factory with Random:
// a UUID v7 factory with `Random` TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory(new Random());
// use the custom factory UUID uuid = factory.create();
A random-based factory with SplittableRandom:
// use a random function that returns a long value SplittableRandom random = new SplittableRandom(); TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory(() -> random.nextLong());
// use the factory UUID uuid = factory.create();
A random-based factory with RandomGenerator (JDK 17+):
// use a random function that returns a long value RandomGenerator random = RandomGenerator.getDefault(); TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory(() -> random.nextLong());
// use the factory UUID uuid = factory.create();
An UUID v7 factory with ThreadLocalRandom:
// a UUID v7 factory with a custom `RandomFunction` TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory((int length) -> { final byte[] bytes = new byte[length]; ThreadLocalRandom.current().nextBytes(bytes); return bytes; });
// use the custom factory UUID uuid = factory.create();
A UUID v7 factory with random increments:
// maximum increment long maximum = 100_000; // a UUID v7 factory with random increments between 1 and 100,000 TimeOrderedEpochFactory factory = TimeOrderedEpochFactory.builder() // .withIncrementPlusN(maximum).build();
// use the custom factory UUID uuid = factory.create();