UniqueIdUtils.java

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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
//
//   http://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.apache.doris.common.util;

import org.apache.doris.thrift.TUniqueId;

import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class UniqueIdUtils {

    private static class Holder {
        static final SecureRandom numberGenerator = new SecureRandom();
    }

    /**
     * Generates a random RFC‑4122 version 4 UUID using {@link java.util.concurrent.ThreadLocalRandom}.
     *
     * <p>This implementation avoids the shared random source used by
     * {@link java.util.UUID#randomUUID()}, reducing contention in high‑concurrency
     * environments and improving throughput.</p>
     *
     * <p><b>Trade‑off:</b> {@code ThreadLocalRandom} is not cryptographically secure.
     * It should be used for high‑throughput identifiers (e.g. request or trace IDs),
     * not for security‑sensitive tokens.</p>
     */
    public static TUniqueId fastUniqueId() {
        final Random ng = ThreadLocalRandom.current();
        long mostSigBits = ng.nextLong();
        long leastSigBits = ng.nextLong();
        // format to uuid v4
        mostSigBits &= 0xFFFFFFFFFFFF0FFFL;
        mostSigBits |= 0x0000000000004000L;
        leastSigBits &= 0x3FFFFFFFFFFFFFFFL;
        leastSigBits |= 0x8000000000000000L;
        return new TUniqueId(mostSigBits, leastSigBits);
    }

    public static TUniqueId randomUniqueId() {
        // copy from java.util.UUID.randomUUID
        final SecureRandom ng = Holder.numberGenerator;
        byte[] data = new byte[16];
        ng.nextBytes(data);
        data[6] &= 0x0f;  /* clear version        */
        data[6] |= 0x40;  /* set to version 4     */
        data[8] &= 0x3f;  /* clear variant        */
        data[8] |= 0x80;  /* set to IETF variant  */
        long msb = 0;
        long lsb = 0;
        for (int i = 0; i < 8; i++) {
            msb = (msb << 8) | (data[i] & 0xff);
        }
        for (int i = 8; i < 16; i++) {
            lsb = (lsb << 8) | (data[i] & 0xff);
        }
        return new TUniqueId(msb, lsb);
    }

}