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

org.ehrbase.util.UuidGenerator Maven / Gradle / Ivy

There is a newer version: 2.12.0
Show newest version
/*
 * Copyright (c) 2024 vitasystems GmbH.
 *
 * This file is part of project EHRbase
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ehrbase.util;

import java.security.SecureRandom;
import java.util.UUID;

/**
 * Non-blocking generation of random V4 UUIDs.
 *
 * UUIDs are prepared in batches, which increases throughput (while introducing a bit of jitter).
 *
 * Usually UUID::randomUUID synchronizes on the shared SecureRandom instance,
 * which can lead to blocked threads.
 *
 */
public class UuidGenerator {

    private static final int UUID_BYTECOUNT = 16;
    private static final ThreadLocal GENERATORS = ThreadLocal.withInitial(UuidGenerator::new);

    private final SecureRandom numberGenerator = new SecureRandom();

    /**
     * Prepare 32 UUIDs in one call
     */
    private final byte[] data = new byte[UUID_BYTECOUNT * 32];

    private int nextUuid = data.length;

    private UuidGenerator() {}

    /**
     *
     * UUID.randomUUID() with
     *
     * @return a random UUID
     */
    public static UUID randomUUID() {
        return GENERATORS.get().randomUUIDInternal();
    }

    private UUID randomUUIDInternal() {
        ensureBatchAvailable();
        int pos = nextUuid;
        nextUuid += UUID_BYTECOUNT;
        return createUuid(data, pos);
    }

    private void ensureBatchAvailable() {
        if (nextUuid >= data.length) {
            // prepare new batch
            numberGenerator.nextBytes(data);
            nextUuid = 0;
        }
    }

    private static UUID createUuid(byte[] data, int pos) {
        engraveV4Bytes(data, pos);
        long msb = 0;
        long lsb = 0;
        int i = pos;
        for (int m = i + 8; i < m; i++) msb = (msb << 8) | (data[i] & 0xff);
        for (int m = i + 8; i < m; i++) lsb = (lsb << 8) | (data[i] & 0xff);

        return new UUID(msb, lsb);
    }

    private static void engraveV4Bytes(byte[] data, int offset) {
        int p6 = offset + 6;
        data[p6] &= 0x0f; /* clear version        */
        data[p6] |= 0x40; /* set to version 4     */
        int p8 = offset + 8;
        data[p8] &= 0x3f; /* clear variant        */
        data[p8] |= 0x80; /* set to IETF variant  */
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy