diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/UniqueIdUtils.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/UniqueIdUtils.java new file mode 100644 index 00000000000000..7160dcb6db2f7e --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/UniqueIdUtils.java @@ -0,0 +1,75 @@ +// 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}. + * + *
This implementation avoids the shared random source used by + * {@link java.util.UUID#randomUUID()}, reducing contention in high‑concurrency + * environments and improving throughput.
+ * + *Trade‑off: {@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.
+ */ + 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); + } + +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index c5dc61d15f5b5a..11d633a56445ac 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -62,6 +62,7 @@ import org.apache.doris.common.util.DebugUtil; import org.apache.doris.common.util.NetUtils; import org.apache.doris.common.util.TimeUtils; +import org.apache.doris.common.util.UniqueIdUtils; import org.apache.doris.common.util.Util; import org.apache.doris.datasource.FileScanNode; import org.apache.doris.datasource.tvf.source.TVFScanNode; @@ -166,7 +167,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.UUID; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Matcher; @@ -561,8 +561,7 @@ public boolean isCached() { // query with a random sql public void execute() throws Exception { - UUID uuid = UUID.randomUUID(); - TUniqueId queryId = new TUniqueId(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); + TUniqueId queryId = UniqueIdUtils.fastUniqueId(); if (Config.enable_print_request_before_execution) { LOG.info("begin to execute query {} {}", DebugUtil.printId(queryId), originStmt == null ? "null" : originStmt.originStmt); @@ -572,7 +571,6 @@ public void execute() throws Exception { public void queryRetry(TUniqueId queryId) throws Exception { TUniqueId firstQueryId = queryId; - UUID uuid; int retryTime = Config.max_query_retry_time; retryTime = retryTime <= 0 ? 1 : retryTime + 1; // If the query is an `outfile` statement, @@ -595,8 +593,7 @@ public void queryRetry(TUniqueId queryId) throws Exception { throw e; } TUniqueId lastQueryId = queryId; - uuid = UUID.randomUUID(); - queryId = new TUniqueId(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); + queryId = UniqueIdUtils.fastUniqueId(); int randomMillis = 10 + (int) (Math.random() * 10); if (i > retryTime / 2) { randomMillis = 20 + (int) (Math.random() * 10); @@ -971,9 +968,7 @@ private void handleQueryWithRetry(TUniqueId queryId) throws Exception { try { // reset query id for each retry if (i > 0) { - UUID uuid = UUID.randomUUID(); - TUniqueId newQueryId = new TUniqueId(uuid.getMostSignificantBits(), - uuid.getLeastSignificantBits()); + TUniqueId newQueryId = UniqueIdUtils.fastUniqueId(); AuditLog.getQueryAudit().log("Query {} {} times with new query id: {}", DebugUtil.printId(queryId), i, DebugUtil.printId(newQueryId)); context.setQueryId(newQueryId); @@ -2022,8 +2017,7 @@ public ListThis implementation avoids the shared random source used by + * {@link java.util.UUID#randomUUID()}, reducing contention in high‑concurrency + * environments and improving throughput.
+ * + *Trade‑off: {@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.
+ */ + public static UUID fastUUID() { + 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 UUID(mostSigBits, leastSigBits); + } + + public static UUID randomUUID() { + return UUID.randomUUID(); + } +}