diff --git a/README.md b/README.md index 907e7ca..0f72c57 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,15 @@ Module and bundle names are the same as the root package name. ### ULID -The ULID is a 128 bit long identifier. The first 48 bits represent the number of milliseconds since Unix Epoch, 1970-01-01. The remaining 80 bits are generated by a secure random number generator. Its canonical string representation is 26 characters long. +ULID is a 128-bit identifier. The first 48 bits represent the number of milliseconds since Unix Epoch, 1970-01-01. The remaining 80 bits are generated by a secure random number generator. Its canonical string representation is 26 characters long. + ```java // Generate a ULID Ulid ulid = UlidCreator.getUlid(); ``` -Sequence of ULIDs: +Structure of a series of ULIDs: ```text 01EX8Y21KBH49ZZCA7KSKH6X1C @@ -91,14 +92,14 @@ Sequence of ULIDs: ### Monotonic ULID -The Monotonic ULID is variant of ULID. The random component is incremented by 1 whenever the current millisecond is equal to the previous one. Its main advantage is *speed*. +Monotonic ULID is a variant of ULID. The random component is incremented by 1 whenever the current millisecond equals the previous millisecond. Its main advantage is *speed*. ```java // Generate a Monotonic ULID Ulid ulid = UlidCreator.getMonotonicUlid(); ``` -Sequence of Monotonic ULIDs: +Structure of a series of Monotonic ULIDs: ```text 01EX8Y7M8MDVX3M3EQG69EEMJW @@ -123,6 +124,34 @@ Sequence of Monotonic ULIDs: time random ``` +### Hash ULID + +Hash ULID is a "non-standard" variant of ULID. It always returns the same ULID for a specific pair of arguments. It has the same basic structure as a ULID, except that the random component is replaced with the first 10 bytes of an SHA-256 hash. + +```java +// Generate a Hash ULID of a string +long time = file.getCreatedAt(); +String name = file.getFileName(); +Ulid ulid = UlidCreator.getHashUlid(time, name); +``` + +```java +// Generate a Hash ULID of a byte array +long time = file.getCreatedAt(); +byte[] bytes = file.getFileBinary(); +Ulid ulid = UlidCreator.getHashUlid(time, bytes); +``` + +Structure of Hash ULIDs: + +```text +01GZ8AR53SE5XCA1MN1PGCSDJ0 + +|---------|--------------| + + time hash +``` + ### More Examples Create a quick ULID: @@ -193,6 +222,7 @@ public class KeyGenerator { } ``` ```java +// use the generator String key = KeyGenerator.next(); ``` @@ -203,20 +233,8 @@ A `UlidFactory` with `java.util.Random`: ```java // use a `java.util.Random` instance for fast generation UlidFactory factory = UlidFactory.newInstance(new Random()); - -// use the factory -Ulid ulid = factory.create(); ``` - ---- - -A `UlidFactory` with `SplittableRandom`: - ```java -// use a random function that returns a long value -SplittableRandom random = new SplittableRandom(); -UlidFactory factory = UlidFactory.newInstance(() -> random.nextLong()); - // use the factory Ulid ulid = factory.create(); ``` @@ -229,23 +247,8 @@ A `UlidFactory` with `RandomGenerator` (JDK 17+): // use a random function that returns a long value RandomGenerator random = RandomGenerator.getDefault(); UlidFactory factory = UlidFactory.newInstance(() -> random.nextLong()); - -// use the factory -Ulid ulid = factory.create(); ``` - ---- - -A `UlidFactory` with `ThreadLocalRandom`: - ```java -// use a random supplier that returns an array of 10 bytes -UlidFactory factory = UlidFactory.newInstance((length) -> { - final byte[] bytes = new byte[length]; - ThreadLocalRandom.current().nextBytes(bytes); - return bytes; -}); - // use the factory Ulid ulid = factory.create(); ``` @@ -261,19 +264,22 @@ This section shows benchmarks comparing `UlidCreator` to `UUID.randomUUID()`. -------------------------------------------------------------------------------- THROUGHPUT (operations/msec) Mode Cnt Score Error Units -------------------------------------------------------------------------------- -UUID_randomUUID thrpt 5 3459,889 ± 98,257 ops/ms (1.00) -UUID_randomUUID_toString thrpt 5 3148,298 ± 159,507 ops/ms +UUID_randomUUID thrpt 5 1787,601 ± 489,482 ops/ms ( 1.0) +UUID_randomUUID_toString thrpt 5 1598,467 ± 93,067 ops/ms - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ulid_fast thrpt 5 34523,147 ± 1022,114 ops/ms (9.98) -Ulid_fast_toString thrpt 5 19161,375 ± 662,563 ops/ms +Ulid_fast thrpt 5 100521,737 ±27132,748 ops/ms (56.2) +Ulid_fast_toString thrpt 5 50529,743 ± 8970,574 ops/ms - - - - - - - - - - - - - - - - - - - - - - - - - - - -UlidCreator_getUlid thrpt 5 4276,614 ± 11,069 ops/ms (1.23) -UlidCreator_getUlid_toString thrpt 5 3645,088 ± 85,478 ops/ms +UlidCreator_getUlid thrpt 5 2443,810 ± 379,149 ops/ms ( 1.3) +UlidCreator_getUlid_toString thrpt 5 2200,047 ± 539,767 ops/ms - - - - - - - - - - - - - - - - - - - - - - - - - - - -UlidCreator_getMonotonicUlid thrpt 5 32921,698 ± 1286,983 ops/ms (9.51) -UlidCreator_getMonotonicUlid_toString thrpt 5 18541,252 ± 710,281 ops/ms +UlidCreator_getMonotonicUlid thrpt 5 9845,810 ± 1239,148 ops/ms ( 5.5) +UlidCreator_getMonotonicUlid_toString thrpt 5 5748,568 ± 549,121 ops/ms +- - - - - - - - - - - - - - - - - - - - - - - - - - - +UlidCreator_getHashUlid thrpt 5 6651,239 ± 2541,774 ops/ms +UlidCreator_getHashUlidString thrpt 5 6043,582 ± 1879,042 ops/ms -------------------------------------------------------------------------------- -Total time: 00:02:41 +Total time: 00:03:22 -------------------------------------------------------------------------------- ``` diff --git a/benchmark/src/main/java/benchmark/Throughput.java b/benchmark/src/main/java/benchmark/Throughput.java index b807cce..5fb83ef 100644 --- a/benchmark/src/main/java/benchmark/Throughput.java +++ b/benchmark/src/main/java/benchmark/Throughput.java @@ -19,7 +19,7 @@ import com.github.f4b6a3.ulid.Ulid; import com.github.f4b6a3.ulid.UlidCreator; @Fork(1) -@Threads(1) +@Threads(4) @State(Scope.Benchmark) @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 5, time = 1) @@ -73,7 +73,7 @@ public class Throughput { } @Benchmark - public Ulid UlidCreator_getHashUlidString() { + public String UlidCreator_getHashUlidString() { return UlidCreator.getHashUlid(0L, "this is a test").toString(); } }