-
Notifications
You must be signed in to change notification settings - Fork 43
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).
See the benchmarks to compare the 3 types.
Clock regressions of up to 10 seconds are handled to keep monotonicity.
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. See the last example in next section.
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();