Git Product home page Git Product logo

java-uuid-generator's Introduction

Java Uuid Generator (JUG)

JUG is a set of Java classes for working with UUIDs: generating UUIDs using any of standard methods, outputting efficiently, sorting and so on. It generates UUIDs according to the UUID specification (RFC-4122) (see Wikipedia UUID page for more explanation)

JUG was written by Tatu Saloranta ([email protected]) originally in 2002 and has been updated over the years. In addition, many other individuals have helped fix bugs and implement new features: please see release-notes/CREDITS for the complete list.

JUG is licensed under Apache License 2.0.

Supported UUID versions (1, 3, 4, 5, 6, 7)

JUG supports both "classic" versions defined in RFC 4122]:

  • 1: time/location - based
  • 3 and 5: name hash - based
  • 4: random number - based

and newly (in 2022-2024) proposed (see uuid6 and RFC-4122 bis) variants:

  • 6: reordered variant of version 1 (with lexicographic ordering)
  • 7: Unix-timestamp + random based variant (also with lexicographic ordering)

Status

Type Status
Build (CI) Build (github)
Artifact Maven Central
OSS Sponsorship Tidelift
Javadocs Javadoc
Code coverage (5.x) codecov.io
OpenSSF Score OpenSSF  Scorecard

Usage

JUG can be used as a command-line tool (via class com.fasterxml.uuid.Jug), or as a pluggable component.

Maven Dependency

Maven coordinates are:

<dependency>
  <groupId>com.fasterxml.uuid</groupId>
  <artifactId>java-uuid-generator</artifactId>
  <version>5.1.0</version>
</dependency>

Gradle:

implementation 'com.fasterxml.uuid:java-uuid-generator:5.1.0'

Third-party Dependencies by JUG

The only dependency for JUG is the logging library:

  • For versions up to 3.x, log4j is used, optionally (runtime dependency)
  • For versions 4.x and up, slf4j API is used: logging implementation to be provided by calling application

JDK9+ module info

Since version 3.2.0, JUG defines JDK9+ compatible module-info.class, with module name of com.fasterxml.uuid.

Downloads

For direct downloads, check out Project Wiki.

Using JUG as Library

Generating UUIDs

The original use case for JUG was generation of UUID values. This is done by first selecting a kind of generator to use, and then calling its generate() method. For example:

UUID uuid = Generators.timeBasedGenerator().generate(); // Version 1
UUID uuid = Generators.randomBasedGenerator().generate(); // Version 4
UUID uuid = Generators.nameBasedgenerator().generate("string to hash"); // Version 5
// With JUG 4.1+: support for https://github.com/uuid6/uuid6-ietf-draft versions 6 and 7:
UUID uuid = Generators.timeBasedReorderedGenerator().generate(); // Version 6
UUID uuid = Generators.timeBasedEpochGenerator().generate(); // Version 7
// With JUG 5.0 added variation:
UUID uuid = Generators.timeBasedEpochRandomGenerator().generate(); // Version 7 with per-call random values

If you want customize generators, you may also just want to hold on to generator instance:

TimeBasedGenerator gen = Generators.timeBasedGenerator(EthernetAddress.fromInterface());
UUID uuid = gen.generate();
UUID anotherUuid = gen.generate();

If your machine has a standard IP networking setup, the Generators.defaultTimeBasedGenerator (added in JUG 4.2) factory method will try to determine which network interface corresponds to the default route for all outgoing network traffic, and use that for creating a time based generator. This is likely a good choice for common usage scenarios if you want a version 1 UUID generator.

TimeBasedGenerator gen = Generators.defaultTimeBasedGenerator();
UUID uuid = gen.generate();
UUID anotherUuid = gen.generate();

Generators are fully thread-safe, so a single instance may be shared among multiple threads.

Javadocs for further information can be found from Project Wiki.

Converting java.util.UUID values into byte[]

Sometimes you may want to convert from java.util.UUID into external serialization: for example, as Strings or byte arrays (byte[]). Conversion to String is easy with UUID.toString() (provided by JDK), but there is no similar functionality for converting into byte[].

But UUIDUtil class provides methods for efficient conversions:

byte[] asBytes = UUIDUtil.asByteArray(uuid);
// or if you have longer buffer already
byte[] outputBuffer = new byte[1000];
// append at position #100
UUIDUtil.toByteArray(uuid, outputBuffer, 100);

Constructing java.util.UUID values from String, byte[]

UUID values are often passed as java Strings or byte[]s (byte arrays), and conversion is needed to get to actual java.util.UUID instances. JUG has optimized conversion functionality available via class UUIDUtil (package com.fasterxml.uuid.impl), used as follows:

UUID uuidFromStr = UUIDUtil.uuid("ebb8e8fe-b1b1-11d7-8adb-00b0d078fa18");
byte[] rawUuidBytes = ...; // byte array with 16 bytes
UUID uuidFromBytes = UUIDUtil.uuid(rawUuidBytes)

Note that while JDK has functionality for constructing UUID from String, like so:

UUID uuidFromStr = UUID.fromString("ebb8e8fe-b1b1-11d7-8adb-00b0d078fa18");

it is rather slower than JUG version: for more information, read Measuring performance of Java UUID.fromString().

Using JUG as CLI

JUG jar built under target/:

target/java-uuid-generator-5.1.0-SNAPSHOT.jar

can also be used as a simple Command-line UUID generation tool.

To see usage you can do something like:

java -jar target/java-uuid-generator-5.1.0-SNAPSHOT.jar

and get full instructions, but to generate 5 Random-based UUIDs, you would use:

java -jar target/java-uuid-generator-5.1.0-SNAPSHOT.jar -c 5 r

(where -c (or --count) means number of UUIDs to generate, and r means Random-based version)

NOTE: this functionality is included as of JUG 4.1 -- with earlier versions you would need a bit longer invocation as Jar metadata did not specify "Main-Class". If so, you would need to use

java -cp target/java-uuid-generator-5.1.0-SNAPSHOT.jar com.fasterxml.uuid.Jug -c 5 r

Compatibility

JUG versions 3.1 and later require JDK 1.6 to work, mostly to be able to access local Ethernet MAC address. Earlier versions (3.0 and before) worked on 1.4 (which introduced java.util.UUID).

JUG versions 5.0 and later require JDK 8 to work.

Known Issues

JDK's java.util.UUID has flawed implementation of compareTo(), which uses naive comparison of 64-bit values. This does NOT work as expected, given that underlying content is for all purposes unsigned. For example two UUIDs:

7f905a0b-bb6e-11e3-9e8f-000000000000
8028f08c-bb6e-11e3-9e8f-000000000000

would be ordered with second one first, due to sign extension (second value is considered to be negative, and hence "smaller").

Because of this, you should always use external comparator, such as com.fasterxml.uuid.UUIDComparator, which implements expected sorting order that is simple unsigned sorting, which is also same as lexicographic (alphabetic) sorting of UUIDs (when assuming uniform capitalization).

Enterprise support

Available as part of the Tidelift Subscription.

The maintainers of java-uuid-generator and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.

Contributing

For simple bug reports and fixes, and feature requests, please simply use projects Issue Tracker, with exception of security-related issues for which we recommend filing Tidelift security contact (NOTE: you do NOT have to be a subscriber to do this).

Alternative JVM UUID generators

There are many other publicly available UUID generators. For example:

Note that although some packages claim to be faster than others, it is not clear:

  1. whether claims have been properly verified (or, if they have, can be independently verified), OR
  2. whether performance differences truly matter: JUG, for example, can generate millions of UUID per second per core (sometimes hitting the theoretical limit of 10 million per second) -- and it seems unlikely that generation will be bottleneck for any actual use case

so it is often best to choose based on stability of packages and API.

java-uuid-generator's People

Contributors

alexey-anufriev avatar branchpredictor avatar chadwilson avatar chenzhang22 avatar codylerum avatar cowtowncoder avatar dependabot[bot] avatar divinenickname avatar fwdekker avatar hboutemy avatar hellblazer avatar k163377 avatar magdel avatar maia-everett avatar mazurkin avatar mukham12 avatar pgalbraith avatar phated avatar squireofsoftware avatar sullis avatar worldtiki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

java-uuid-generator's Issues

Generators class not found

I used the following dependency in my project

<dependency>
            <groupId>com.fasterxml.uuid</groupId>
            <artifactId>java-uuid-generator</artifactId>
            <version>3.1.3</version>
</dependency>

After compiling the project , I could find the jar also in following location

.m2\repository\com\fasterxml\uuid\java-uuid-generator\3.1.3

But, When I try to use the command, I get "Generators cannot be resolved"

UUID uuiD= Generators.timeBasedGenerator().generate();
Am I missing Something?

Ensure OSGi exports packages with versions

Currently (released version 3.1.1) the OSGi exports doesn't come with any version information. Therefore the framework falls back to the default export version, which is "0.0.0".

This could introduce problems in several cases and is not recommended.

Output from a Felix Shell:

java-uuid-generator [372] exports packages:
-------------------------------------------
com.fasterxml.uuid; version=0.0.0 UNUSED
com.fasterxml.uuid.ext; version=0.0.0 UNUSED
com.fasterxml.uuid.impl; version=0.0.0 UNUSED

Use SLF4J instead of Log4J directly

Having this depend specifically on Log4J can produce a weird situation when used in projects that use other logging frameworks (which is the problem SLF4J, or depending only on API jars, tackle).

As far as I could see, there isn't a lot of complex things going on here that would require direct access to some Log4J-specific features, so I would like to know if you'd be willing to migrate this to SLF4J (or Log4J2-API).

I can port it myself, but I wanted to know your positioning on the matter before forking and creating a PR

UUID version 7 implementation sorting incorrect?

I tried running the following code to ensure that the ordering of the UUID v7 is correct:

val test = (0..20).map { Generators.timeBasedEpochGenerator().generate() }
    val sorted = test.sorted()

    test.forEachIndexed { index, uuid ->
        println( uuid == sorted[index])
    }

expect the equality check returns false for almost all entries. I have tried to run the same test with the library com.github.f4b6a3:uuid-creator:5.2.0 and there the checks always return true using the following code:

val test = (0..20).map { UuidCreator.getTimeOrderedEpoch() }
    val sorted = test.sorted()

    test.forEachIndexed { index, uuid ->
        println( uuid == sorted[index])
    }

Is this a mistake in the implementation?

Pedigree?

This is a suggestion to add some documentation around the history of this library. I'm currently working on a project that uses v 2.0.0 of org.safehaus.jug. Is that an earlier version of this same library? Is this an improved version of that or is this a fork with some different motivation? There is a credits page mentioning some contributors but no mention of safehaus.

Also, the http://wiki.fasterxml.com/JugHome link doesn't work...

Increase JDK baseline to JDK 8 for `java-uuid-generator` 5.0

It has been a while since I increased the JDK baseline and I think it would be reasonable to finally move to Java 8.
This would make it a little bit easier to maintain things (for example, able to build on JDK 17 which does not support Java 6 target).

This would be doable for version 4.1: I don't think a major version upgrade is warranted, although I am open to being convinced otherwise.

Feel free to add comments, especially if you have anything AGAINST proposal.

Add constants for "Nil UUID", "Max UUID" (from draft "new UUID" spec) in `UUIDUtil`

(note: related to Draft-04 spec at: https://uuid6.github.io/uuid6-ietf-draft/ section 5.4)

So, looks like there will be the counterpart for "null UUID" (all zeroes) wherein all 128 bits are 1s, so-called "Max UUID".
This is specific in section 5.4 of the "new UUID" draft spec (draft-04):

https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html

It should probably be defined similar to the existing null UUID (details to be filled)

Microsecond / nanosecond part of time based uuid set even if UUIDClock is millisecond precision

Hi

For some legacy stuff that I'm working on, I needed to be able to create UUID's for a given timestamp, so I created the following utility class create time based UUID's and convert them back to Instant:

public class UUIDUtil {
    /**
     * Converts a time based (type 1) uuid into a epoch nanos.
     * Inspiration stolen from https://stackoverflow.com/questions/15179428/how-do-i-extract-a-date-from-a-uuid-using-java
     */
    public static long toEpocNano(UUID uuid) {
        long ts = uuid.timestamp();
        return ((ts / 10l) - 12_219_292_800_000_000l) * 1000;
    }

    /**
     * Converts a time based (type 1) uuid into an Instant.
     */
    public static Instant toInstant(UUID uuid) {
        return Instant.ofEpochSecond(0, toEpocNano(uuid));
    }

    /**
     * Generate a time based UUID that matches the given instant time wise.
     */
    public static UUID timeBased(Instant forInstant) {
        try {
            UUIDTimer timer = new UUIDTimer(new Random(), null, new FixedUUIDClock(forInstant));
            return new TimeBasedGenerator(null, timer).generate();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @RequiredArgsConstructor
    private static class FixedUUIDClock extends UUIDClock {
        final Instant i;

        @Override
        public long currentTimeMillis() {
            return i.toEpochMilli();
        }
    }
}

But while doing some testing of it I discovered that the generated UUID (when converved back to an Instant) has micro/nano-second precision.

Following unit test fails because of the 22 micros:

@Test
public void testNanos() {
    Instant i = Instant.parse("2022-12-21T12:11:16.979Z");
    UUID uuid = UUIDUtil.timeBased(i);
    // 2022-12-21T12:11:16.979Z -> 2022-12-21T12:11:16.979022Z
    assertThat(UUIDUtil.toInstant(uuid)).isEqualTo(i);
}

Am I doing something wrong here or should the generated UUID not have the same precision as the UUIDClock?

Missing documentation

Couldn't find any JavaDoc or examples. Can they be found somewhere? Or are they missing?

Time based UUID not using current time stamp

@cowtowncoder , I used the following code Generators.timeBasedGenerator().generate() to generate time based UUID. On the generated UUID, I found the timestamp using Java's UUID.timestamp() , I see the timestamp is not current time . Is there a way to generate UUID with current time stamp?

Add `UUIDUtil.extractTimestamp()` for extracting 64-bit timestamp for all timestamp-based versions

java.util.UUID#timestamp() only works for version 1 UUIDs.

It would be nice to have similar functionality for version 6 UUIDs.
E.g. a static method in TimeBasedReorderedGenerator, something along the lines of

public static long timestamp(UUID uuid)
{
    assert(uuid.version()==6);
    return ((uuid.getMostSignificantBits()>>>4) & ~0xFFF) | (uuid.getMostSignificantBits()&0xFFF);
}

Better yet, a static method in UUIDUtil that returns the number of millis since unix epoch for versions 1, 6 and 7 UUIDs.

thank you very much
Gabriel

LICENSE file refers to the Java Classmate library instead of Java UUID Generator (JUG)

The LICENSE file says:

This copy of Java ClassMate library is licensed under Apache (Software) License,

while I believe that it should read:

This copy of Java UUID Generator (JUG) library is licensed under Apache (Software) License,

I assume that this is a mistake and the license has been copied and pasted from the Java ClassMate library. I appreciate that the README, POM and release notes all say that JUG is licensed under Apache License, Version 2.0, but for the avoidance of doubt, can you confirm this is the case?

Ensure correct distinction between variant and version in documentation

The documentation in the README and the code is using the word "variant" where "version" should be used. For example, the README has the following:

UUID uuid = Generators.timeBasedGenerator().generate(); // Variant 1
UUID uuid = Generators.randomBasedGenerator().generate(); // Variant 4
UUID uuid = Generators.nameBasedgenerator().generate("string to hash"); // Variant 5
// With JUG 4.1+: support for https://github.com/uuid6/uuid6-ietf-draft variants 6 and 7:
UUID uuid = Generators.timeBasedReorderedGenerator().generate(); // Variant 6
UUID uuid = Generators.timeBasedEpochGenerator().generate(); // Variant 7

These are referring to the UUID Versions (See: https://www.rfc-editor.org/rfc/rfc4122#section-4.1.3). The Variant of a UUID is distinct from the Version, and is tracked separately (See: https://www.rfc-editor.org/rfc/rfc4122#section-4.1.1). Also see https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-variant-and-version-fields.

EthernetAddress.fromInterface() returning a WAN miniport address on Win7 64

On a Win7 64bit system, EthernetAddress.fromInterface() is returning the address of a WAN Miniport instead of the NIC address.

This particular system has 20 entries returned by the NetworkInterface.getNetworkInterfaces() method. Entry 6 is "name:eth0 (WAN Miniport (IPv6))" and has an address of [-22, 50, 32, 82, 65, 83] in the byte array (ea:32:20:52:41:53). Having a length of 6, this is returning from the fromInterface() method as the MAC address of the machine. Entry 10 in the network interface enumeration is for the actual NIC, which never gets evaluated.

Running the msinfo32 utility on this machine and navigating to System Summary > Components > Network > Adapter shows the list of most of the network interface entries returned by the getNetworkInterfaces() method, with the Wan Miniport IPv6 entry above the actual NIC, though the MAC address for the WAN Miniport entry in that utility shows up as "Not Available".

As a current work-around I'm using the following code to get the correct MAC address before handing it to EthernetAddress:

InetAddress address = InetAddress.getLocalHost();
NetworkInterface nwi = NetworkInterface.getByInetAddress(address);
byte mac[] = nwi.getHardwareAddress();

Problematic OSGI version range for slf4j dependency

Thank you very much for providing java-uuid-generator!

I tried to update to version 4.0, but it seems like there is a problem with this version range:

org.slf4j;version="[1.7.29,)"

in MANIFEST.MF.

When using org.apache.felix.framework version 5.6.10 this version can not be parsed:

java.util.NoSuchElementException
at java.base/java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
at org.osgi.framework.Version.(Version.java:126)
at org.apache.felix.framework.util.VersionRange.parse(VersionRange.java:93)
at org.apache.felix.framework.util.manifestparser.ManifestParser.normalizeImportClauses(ManifestParser.java:329)
at org.apache.felix.framework.util.manifestparser.ManifestParser.(ManifestParser.java:181)
at org.apache.felix.framework.BundleRevisionImpl.(BundleRevisionImpl.java:117)
at org.apache.felix.framework.BundleImpl.createRevision(BundleImpl.java:1282)
at org.apache.felix.framework.BundleImpl.(BundleImpl.java:113)
at org.apache.felix.framework.Felix.installBundle(Felix.java:3042)
at org.apache.felix.framework.BundleContextImpl.installBundle(BundleContextImpl.java:167)
at org.apache.felix.framework.BundleContextImpl.installBundle(BundleContextImpl.java:140)

I may be wrong, but I think the OSGI spec does not allow a such a version range (see: https://osgi.org/download/r5/osgi.core-5.0.0.pdf, page 27).

When I modify the java-uuid-generator jar and change the version range to org.slf4j;version="[1.7.29,2)" everything works fine.

Need more testing to increase code coverage (at least to 50%)

After enabling JaCoCo based code coverage, CC badge is finally working. Displayed level, 46%, is on low side of usual things so would be good to spend some time increasing code coverage -- I think addition of new UUID versions may have caused coverage to have decreased. Either way, getting to above 50% seems like a useful short-term thing to achieve.

EDIT:

  • As of February 19, 2024, we are at 45.28%.
  • As of February 22, 2024, inching up to 47.71%
  • As of June 7, 2024, up to 54.61%! (thanks to PR #110)
  • ... actually, seems to now exceed 60%, due to #112.

Build generating unsatisfiable module-info.java

It appears your build generates something like the following...

  // IntelliJ API Decompiler stub source generated from a class file
  // Implementation of methods is not available

module com.fasterxml.uuid {
  requires java.logging;
  requires log4j;

  exports com.fasterxml.uuid;
  exports com.fasterxml.uuid.impl;
}

However, there's no log4j release that exports "log4j" (that I can find)

Clock sequence hi and lo bytes appear reversed

I may be wrong, but according to my reading of RFC4122, the following lines of code in TimeBasedGenerator.java appear to be storing the clock id in a reversed format. The following code in the TimeBasedGenerator constructor:

uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_SEQUENCE] = (byte) clockSeq;
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_SEQUENCE+1] = (byte) (clockSeq >> 8);

should probably look like this:

uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_SEQUENCE + 1] = (byte) clockSeq;
uuidBytes[UUIDUtil.BYTE_OFFSET_CLOCK_SEQUENCE] = (byte) (clockSeq >> 8);

UUIDTimer is doing the same thing. Also, in UUIDTimer, the clock sequence should only be 14 bits, so it should look like this:

public int getClockSequence() {
    return (_clockSequence & 0x3FFF);
}

Edit: I know the clock sequence is currently randomly generated. I was experimenting with it not being a random value.

Add copyright notices, license info

It's necessary to add LICENSE information (separate file?), and also copyright notices, to make it easier for corporate entities to (re)use JUG.

Type 1 UUID getTimestamp() synchronization leads to performance bottleneck

We are using type 1 UUID timestamp based generator - TimeBasedGenerator - which has getTimestamp() method which is synchronized. This is causing some performance bottleneck in our code.

public synchronized long getTimestamp()

My question is, can we instead use TimeBasedEpochGenerator and still get the same functionality (uniqueness) of TimeBasedGenerator UUID?

Time based generator with Randomized Node

Would you take a pull request for an additional generator implementation that generates v1 UUIDs but with the node portion replaced with random bits as per section 4.5 of the RFC?

UUIDTimer is not extendable which is not consistent with it's Javadoc

UUIDTimer has synchronized on getTimestamp(), which we want to eliminate.
On the same time, getTimestamp() has a comment:

/**
     * Method that constructs unique timestamp suitable for use for
     * constructing UUIDs. Default implementation is fully synchronized;
     * sub-classes may choose to implemented alternate strategies
     *
     * @return 64-bit timestamp to use for constructing UUID
     */

So, the comment tells something about possible subclasses with relaxed strategy.
On the same time, the whole UUIDTimer class is final and all main methods are final.

Add support for Proposed type v8 (fully custom)

So as per:

there are 3 types; this is for implementing variant 8, DIY variant where actual definition of structure is not specified by spec; this can be used for fully custom uuids where semantics are specific to use case / context.

It may be that this just means ability to accept such uuids, or something more, depending on what makes most sense.

Guidance on how to handle IllegalStateException from TimeBasedEpochGenerator

I noticed that TimeBasedEpochGenerator may throw

throw new IllegalStateException("overflow on same millisecond");

I'm not clear on how applications should brace for this situation.
(This is more of a theoretical question, I haven't been able to actually trigger it in practice).

I looked at https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-uuid-version-7 a bit, and it sure looks like -in general- some corner cases should be handled by the application.

I believe that some comments would be helpful here.

  • what kind of situation would trigger this IllegalStateException? (Is it heavy load? Is is an extremely unlikely unlucky randomness? Is it a combination?)
  • some suggestions on how to application may want to handle this. (Is is simply "retry", or "sleep 1ms and then retry"? Should one try to be clever and try to avoid starvation?)

thank you very much
Gabriel Balan

Confusing comment wrt synchronization

The readme is very clear:

Generators are fully thread-safe, so a single instance may be shared among multiple threads.

That being said, I find this comment rather confusing:

    /* As timer is not synchronized (nor _uuidBytes), need to sync; but most
     * importantly, synchronize on timer which may also be shared between
     * multiple instances

since there's no obvious synchronization in that method, it made me think the comment was meant for the caller.
I know this is not a javadoc comment, but still ...

race condition in RandomBasedGenerator?

The below comment is not strictly true, is it? Because of the wonders of hotspot reordering etc, there is the possibility that a thread will see a non-null _sharedRandom that won't be fully constructed. Would it not be better to use volatile (if you want to maintain the side effects), or an AtomicReference (my preference). Both of these will only work in a 1.5+ JVM, 1.4 and below sync is your only choice.

        /* Could be synchronized, but since side effects are trivial
         * (ie. possibility of generating more than one SecureRandom,
         * of which all but one are dumped) let's not add synchronization
         * overhead.
         */
        rnd = _sharedRandom;
        if (rnd == null) {
            _sharedRandom = rnd = new SecureRandom();
        }

Suggestion to add a static method to generate a random based UUID using ThreadLocalRandom (requires JDK 7)

I suggest to add a static method like the following to UUIDUtil (or any other appropriate class):

public static UUID generateThreadLocalRandomUUID() {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
return UUIDUtil.constructUUID(UUIDType.RANDOM_BASED, rnd.nextLong(), rnd.nextLong());
}

Using a generator created by Generators.randomBasedGenerator(ThreadLocalRandom.current()) is probably not a good idea when working in an environment with thread pools (like Java/Jakarta EE), so i came to this solution.

Best regards, Robert

performace issue

in my test. Performace of this generator and JDK UUID is almost the same. So, do bother to use this for performace consideration.

`public class UtilsTest {

@Test
public void uuidPerformanceCompare() throws Exception {
    uuidGeneratorPerformanceTest();
    javaUuidGeneratorPerformanceTest();
}

public void uuidGeneratorPerformanceTest() throws Exception {
    final int THREAD_COUNT = 100;
    final CountDownLatch startLatch = new CountDownLatch(THREAD_COUNT + 1);
    final AtomicBoolean stop = new AtomicBoolean(false);

    final AtomicInteger generatedCount = new AtomicInteger(0);

    for (int i = 0; i < THREAD_COUNT; ++i) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                startLatch.countDown();
                try {
                    startLatch.await();
                    while (!stop.get()) {
                        Utils.generateId();
                        generatedCount.incrementAndGet();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    Thread.sleep(100);
    startLatch.countDown();
    long startMs = System.currentTimeMillis();
    System.out.println("starting generating");
    TimeUnit.SECONDS.sleep(5);
    stop.compareAndSet(false, true);
    System.out.println(String.format("java-uuid-generator generate %s in %sms",
            generatedCount.get(), System.currentTimeMillis() - startMs));
}

public void javaUuidGeneratorPerformanceTest() throws Exception {
    final int THREAD_COUNT = 100;
    final CountDownLatch startLatch = new CountDownLatch(THREAD_COUNT + 1);
    final AtomicBoolean stop = new AtomicBoolean(false);

    final AtomicInteger generatedCount = new AtomicInteger(0);

    for (int i = 0; i < THREAD_COUNT; ++i) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                startLatch.countDown();
                try {
                    startLatch.await();
                    while (!stop.get()) {
                        Utils.sanitizeId(UUID.randomUUID().toString());
                        generatedCount.incrementAndGet();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    Thread.sleep(100);
    startLatch.countDown();
    long startMs = System.currentTimeMillis();
    System.out.println("starting generating");
    TimeUnit.SECONDS.sleep(5);
    stop.compareAndSet(false, true);
    System.out.println(String.format("java-sdk-UUID generate %s in %sms",
            generatedCount.get(), System.currentTimeMillis() - startMs));
}

}`

test result:
starting generating java-uuid-generator generate 1010994 in 5004ms starting generating java-sdk-UUID generate 1097096 in 5004ms

Enable "Reproducible Build"

(see https://reproducible-builds.org/docs/jvm/ for details)

Similar to latest (2.14) Jackson builds, it seems reasonable to enable reproducible builds for JUG.
This should be as simple as adding

    <project.build.outputTimestamp>

in pom.xml (and ensuring reasonable recent oss-parent parent pom).
Packaging type should also be changed back to jar to get good timestamps in jar classes.

TimeBasedGenerator does not produce increasing UUIDs

In some rare situations TimeBasedGenerator may produce UUIDs that are not increasing.
Consider following sample program:

TimeBasedGenerator generator = new TimeBasedGenerator(new EthernetAddress(0L), new UUIDTimer(new Random(), null));
UUID previous = generator.generate();
while (true) {
    Thread.sleep(1000);
    UUID current = generator.generate();
    System.out.println(current + ", compareTo=" + current.compareTo(previous));
    previous = current;
}

And sample output that shows the problem:

7ef7c38a-bb6e-11e3-9e8f-000000000000, compareTo=1
7f905a0b-bb6e-11e3-9e8f-000000000000, compareTo=1
8028f08c-bb6e-11e3-9e8f-000000000000, compareTo=-1     <------- problem is here
80c1870d-bb6e-11e3-9e8f-000000000000, compareTo=1
815a1d8e-bb6e-11e3-9e8f-000000000000, compareTo=1

As you can see when we hit 63bit boundary for mostSigBits in UUID we get instance that is actually smaller than previous instance.

FileBasedTimestampSynchronizer makes uuid generation a lot slower

It seems that adding the FileBasedTimestampSynchronizer makes generating UUIDs a lot slower...I know intuitively this is kinda expected, but it's over an order of magnitude slower.

I copied the source and slapped some debugging around, it seems that it's not actually running the file sync very much at all, instead it seems to run slowDown() a lot because actDiff is always > 20000 everytime it hits that if block.

I don't really understand the system well enough to understand why adding the time sync would cause this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.