time-id

Time-ordered, k-sortable, URL-safe ID generator.

License

License

GroupId

GroupId

com.codahale
ArtifactId

ArtifactId

time-id
Last Version

Last Version

0.4.5
Release Date

Release Date

Type

Type

jar
Description

Description

time-id
Time-ordered, k-sortable, URL-safe ID generator.
Project URL

Project URL

https://github.com/codahale/time-id
Source Code Management

Source Code Management

https://github.com/codahale/time-id

Download time-id

How to add to project

<!-- https://jarcasting.com/artifacts/com.codahale/time-id/ -->
<dependency>
    <groupId>com.codahale</groupId>
    <artifactId>time-id</artifactId>
    <version>0.4.5</version>
</dependency>
// https://jarcasting.com/artifacts/com.codahale/time-id/
implementation 'com.codahale:time-id:0.4.5'
// https://jarcasting.com/artifacts/com.codahale/time-id/
implementation ("com.codahale:time-id:0.4.5")
'com.codahale:time-id:jar:0.4.5'
<dependency org="com.codahale" name="time-id" rev="0.4.5">
  <artifact name="time-id" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.codahale', module='time-id', version='0.4.5')
)
libraryDependencies += "com.codahale" % "time-id" % "0.4.5"
[com.codahale/time-id "0.4.5"]

Dependencies

test (6)

Group / Artifact Type Version
org.junit.jupiter : junit-jupiter jar 5.4.0
org.assertj : assertj-core jar 3.12.2
org.quicktheories : quicktheories jar 0.26
org.mockito : mockito-core jar 2.27.0
org.openjdk.jmh : jmh-core jar 1.21
org.openjdk.jmh : jmh-generator-annprocess jar 1.21

Project Modules

There are no modules declared in this project.

time-id

time id

Generates 27-character, time-ordered, k-sortable, URL-safe, globally unique identifiers.

How do I add it to my project?

pom.xml
<dependency>
  <groupId>com.codahale</groupId>
  <artifactId>time-id</artifactId>
  <version>0.4.5</version>
</dependency>
Note
The module name for Java 9+ is com.codahale.timeid.

How do I use it?

Example.java
import com.codahale.timeid.IdGenerator;

class Example {
  public static void main(String[] args) throws InterruptedException {
    final IdGenerator generator = new IdGenerator();
    for (int i = 0; i < 5; i++) {
      System.out.println(generator.generate());
      Thread.sleep(1000);
    }
  }
}
STDOUT
1KoN0_AUFKtrzGS_vay5hlOyCFF
1KoN1$8dtcqssctVzGFD1O900o$
1KoN1Q7uJBNHyQuEo8y$eND_2dk
1KoN1VejHzyMi1MJLNM4sqtmNJ3
1KoN1vqpjk0nUfE25pUjZXCFLjN
Tip
IdGenerator is thread-safe but synchronized. Highly concurrent applications may wish to use thread-local instances.

How does it work?

Each ID consists of a 32-bit, big-endian timestamp (the number of seconds since 1.4e9 seconds after the Unix epoch), plus 128 bits of random data, for a total of 160 bits of information.

The random data is produced using ChaCha20 in a fast-key-erasure construction, with a per-ID iteration of the ChaCha20 block transform. The first 256 bits of the result are used as the key for the next ID; the next 128 bits are used in the ID; the remaining state is discarded. This construction is an order of magnitude faster than the fastest java.util.SecureRandom implementation, is nonblocking, has a very small memory footprint, operates in constant time, offers forward secrecy, requires no hardware support, and has performance characteristics independent of JVM configuration.

The timestamp and the random data are encoded with Radix-64 using an alphabet which is both URL-safe and which preserves lexical ordering. The result is a 27-character, URL-safe string which can be used in systems which are unaware of its internal structure (e.g., databases, file systems) to store time-ordered data with unique IDs.

Is it fast?

benchmarks.txt
Benchmark                                           Mode      Cnt        Score    Error   Units
Benchmarks.generate                               sample  7041460      270.418 ±  2.743   ns/op
Benchmarks.generate:generate·p0.00                sample               211.000            ns/op
Benchmarks.generate:generate·p0.50                sample               246.000            ns/op
Benchmarks.generate:generate·p0.90                sample               259.000            ns/op
Benchmarks.generate:generate·p0.95                sample               264.000            ns/op
Benchmarks.generate:generate·p0.99                sample               405.000            ns/op
Benchmarks.generate:generate·p0.999               sample              3516.000            ns/op
Benchmarks.generate:generate·p0.9999              sample             25472.000            ns/op
Benchmarks.generate:generate·p1.00                sample           2912256.000            ns/op
Benchmarks.generate:·gc.alloc.rate                sample       20      293.922 ±  4.292  MB/sec
Benchmarks.generate:·gc.alloc.rate.norm           sample       20       72.007 ±  0.001    B/op
Benchmarks.generate:·gc.churn.G1_Eden_Space       sample       20      293.985 ±  8.721  MB/sec
Benchmarks.generate:·gc.churn.G1_Eden_Space.norm  sample       20       72.017 ±  1.684    B/op
Benchmarks.generate:·gc.churn.G1_Old_Gen          sample       20        0.001 ±  0.001  MB/sec
Benchmarks.generate:·gc.churn.G1_Old_Gen.norm     sample       20       ≈ 10⁻⁴             B/op
Benchmarks.generate:·gc.count                     sample       20      334.000           counts
Benchmarks.generate:·gc.time                      sample       20      208.000               ms

It’s pretty fast. Has a nicely flat latency profile. Doesn’t generate a lot of garbage, either. Mostly just the String allocation. All the internal state is either reused or stack-allocated.

License

Copyright © 2019 Coda Hale

Distributed under the Apache License 2.0.

Versions

Version
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.1
0.1.0