All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.descoped.dc.api.ulid.ULIDGenerator Maven / Gradle / Ivy

There is a newer version: 2.0.4
Show newest version
package io.descoped.dc.api.ulid;

import de.huxhorn.sulky.ulid.ULID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;

public class ULIDGenerator {

    private static final Logger LOG = LoggerFactory.getLogger(ULIDGenerator.class);
    static final AtomicReference ulid = new AtomicReference<>(new ULID());
    static final AtomicReference prevUlid = new AtomicReference<>(ulid.get().nextValue());

    static ULID.Value nextMonotonicUlid() {
        /*
         * Will spin until time ticks if next value overflows.
         * Although theoretically possible, it is extremely unlikely that the loop will ever spin
         */
        ULID.Value value;
        ULID.Value previousUlid = prevUlid.get();
        do {
            long timestamp = System.currentTimeMillis();
            long diff = timestamp - previousUlid.timestamp();
            if (diff < 0) {
                if (diff < -(30 * 1000)) {
                    throw new IllegalStateException(String.format("Previous timestamp is in the future. Diff %d ms", -diff));
                }
                LOG.debug("Previous timestamp is in the future, waiting for time to catch up. Diff {} ms", -diff);
                try {
                    Thread.sleep(-diff);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            } else if (diff > 0) {
                // start at lsb 1, to avoid inclusive/exclusive semantics when searching
                value = new ULID.Value((timestamp << 16) & 0xFFFFFFFFFFFF0000L, 1L);
                prevUlid.set(value);
                return value;
            }
            // diff == 0
            value = ulid.get().nextStrictlyMonotonicValue(previousUlid, timestamp).orElse(null);
            prevUlid.set(value);
        } while (value == null);
        prevUlid.set(value);
        return value;
    }

    public static ULID.Value generate() {
        return nextMonotonicUlid();
    }

    public static UUID toUUID(ULID.Value ulid) {
        return new UUID(ulid.getMostSignificantBits(), ulid.getLeastSignificantBits());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy