This is an automated email from the ASF dual-hosted git repository.
abstractdog pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new c4150d55938 HIVE-29566: Tez client creation fails with docker LLAP
mode on client reconnect - LlapTaskSchedulerMetrics init is not idempotent
(#6436)
c4150d55938 is described below
commit c4150d55938f9219b067679b350fc991c63a2771
Author: Bodor Laszlo <[email protected]>
AuthorDate: Sat Apr 18 07:12:45 2026 +0200
HIVE-29566: Tez client creation fails with docker LLAP mode on client
reconnect - LlapTaskSchedulerMetrics init is not idempotent (#6436)
---
.../org/apache/hadoop/hive/common/JvmMetrics.java | 10 +++-
.../llap/metrics/LlapDaemonExecutorMetrics.java | 2 +-
.../llap/tezplugins/LlapTaskSchedulerService.java | 2 +-
.../metrics/LlapTaskSchedulerMetrics.java | 15 +++--
.../metrics/TestLlapTaskSchedulerMetrics.java | 65 ++++++++++++++++++++++
5 files changed, 87 insertions(+), 7 deletions(-)
diff --git a/common/src/java/org/apache/hadoop/hive/common/JvmMetrics.java
b/common/src/java/org/apache/hadoop/hive/common/JvmMetrics.java
index fa0d285faf4..822b979b846 100644
--- a/common/src/java/org/apache/hadoop/hive/common/JvmMetrics.java
+++ b/common/src/java/org/apache/hadoop/hive/common/JvmMetrics.java
@@ -51,8 +51,12 @@ enum Singleton {
JvmMetrics impl;
synchronized JvmMetrics init(String processName, String sessionId) {
+ return init(processName, sessionId, DefaultMetricsSystem.instance());
+ }
+
+ synchronized JvmMetrics init(String processName, String sessionId,
MetricsSystem ms) {
if (impl == null) {
- impl = create(processName, sessionId, DefaultMetricsSystem.instance());
+ impl = create(processName, sessionId, ms);
}
return impl;
}
@@ -87,6 +91,10 @@ public static JvmMetrics initSingleton(String processName,
String sessionId) {
return Singleton.INSTANCE.init(processName, sessionId);
}
+ public static JvmMetrics initSingleton(String processName, String sessionId,
MetricsSystem ms) {
+ return Singleton.INSTANCE.init(processName, sessionId, ms);
+ }
+
@Override
public void getMetrics(MetricsCollector collector, boolean all) {
MetricsRecordBuilder rb = collector.addRecord(JvmMetrics)
diff --git
a/llap-server/src/java/org/apache/hadoop/hive/llap/metrics/LlapDaemonExecutorMetrics.java
b/llap-server/src/java/org/apache/hadoop/hive/llap/metrics/LlapDaemonExecutorMetrics.java
index c1f91e12fa5..17d992b0b22 100644
---
a/llap-server/src/java/org/apache/hadoop/hive/llap/metrics/LlapDaemonExecutorMetrics.java
+++
b/llap-server/src/java/org/apache/hadoop/hive/llap/metrics/LlapDaemonExecutorMetrics.java
@@ -236,7 +236,7 @@ public static LlapDaemonExecutorMetrics create(String
displayName, String sessio
int numExecutorsConfigured, int waitQueueSizeConfigured, final int[]
intervals, int timedWindowAverageDataPoints,
long timedWindowAverageWindowLength, int simpleAverageWindowDataSize) {
MetricsSystem ms = LlapMetricsSystem.instance();
- JvmMetrics jm = JvmMetrics.create(MetricsUtils.METRICS_PROCESS_NAME,
sessionId, ms);
+ JvmMetrics jm =
JvmMetrics.initSingleton(MetricsUtils.METRICS_PROCESS_NAME, sessionId, ms);
return ms.register(displayName, "LlapDaemon Executor Metrics",
new LlapDaemonExecutorMetrics(displayName, jm, sessionId,
numExecutorsConfigured, waitQueueSizeConfigured,
intervals, timedWindowAverageDataPoints,
timedWindowAverageWindowLength, simpleAverageWindowDataSize));
diff --git
a/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/LlapTaskSchedulerService.java
b/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/LlapTaskSchedulerService.java
index 1806825747b..9ac108728fb 100644
---
a/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/LlapTaskSchedulerService.java
+++
b/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/LlapTaskSchedulerService.java
@@ -455,7 +455,7 @@ public LlapTaskSchedulerService(TaskSchedulerContext
taskSchedulerContext, Clock
pauseMonitor.start();
String displayName = "LlapTaskSchedulerMetrics-" +
MetricsUtils.getHostName();
String sessionId = conf.get("llap.daemon.metrics.sessionid");
- // TODO: Not sure about the use of this. Should we instead use
workerIdentity as sessionId?
+ // TODO: HIVE-29569: Not sure about the use of this. Should we instead
use workerIdentity as sessionId?
this.metrics = LlapTaskSchedulerMetrics.create(displayName, sessionId);
} else {
this.metrics = null;
diff --git
a/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/metrics/LlapTaskSchedulerMetrics.java
b/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/metrics/LlapTaskSchedulerMetrics.java
index c6b5cc17701..0dd645da82c 100644
---
a/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/metrics/LlapTaskSchedulerMetrics.java
+++
b/llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/metrics/LlapTaskSchedulerMetrics.java
@@ -31,6 +31,8 @@
import static org.apache.hadoop.metrics2.impl.MsInfo.ProcessName;
import static org.apache.hadoop.metrics2.impl.MsInfo.SessionId;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.hadoop.hive.common.JvmMetrics;
import org.apache.hadoop.hive.llap.metrics.LlapMetricsSystem;
import org.apache.hadoop.hive.llap.metrics.MetricsUtils;
@@ -51,6 +53,9 @@
*/
@Metrics(about = "Llap Task Scheduler Metrics", context = "scheduler")
public class LlapTaskSchedulerMetrics implements MetricsSource {
+ private static final ConcurrentHashMap<String, LlapTaskSchedulerMetrics>
METRICS =
+ new ConcurrentHashMap<>();
+
private final String name;
private final JvmMetrics jvmMetrics;
private final String sessionId;
@@ -102,10 +107,12 @@ private LlapTaskSchedulerMetrics(String displayName,
JvmMetrics jm, String sessi
}
public static LlapTaskSchedulerMetrics create(String displayName, String
sessionId) {
- MetricsSystem ms = LlapMetricsSystem.instance();
- JvmMetrics jm = JvmMetrics.create(MetricsUtils.METRICS_PROCESS_NAME,
sessionId, ms);
- return ms.register(displayName, "Llap Task Scheduler Metrics",
- new LlapTaskSchedulerMetrics(displayName, jm, sessionId));
+ return METRICS.computeIfAbsent(displayName, name -> {
+ MetricsSystem ms = LlapMetricsSystem.instance();
+ JvmMetrics jm =
JvmMetrics.initSingleton(MetricsUtils.METRICS_PROCESS_NAME, sessionId, ms);
+ return ms.register(name, "Llap Task Scheduler Metrics",
+ new LlapTaskSchedulerMetrics(name, jm, sessionId));
+ });
}
@Override
diff --git
a/llap-tez/src/test/org/apache/hadoop/hive/llap/tezplugins/metrics/TestLlapTaskSchedulerMetrics.java
b/llap-tez/src/test/org/apache/hadoop/hive/llap/tezplugins/metrics/TestLlapTaskSchedulerMetrics.java
new file mode 100644
index 00000000000..45e909cedcd
--- /dev/null
+++
b/llap-tez/src/test/org/apache/hadoop/hive/llap/tezplugins/metrics/TestLlapTaskSchedulerMetrics.java
@@ -0,0 +1,65 @@
+/*
+ * 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.hadoop.hive.llap.tezplugins.metrics;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link LlapTaskSchedulerMetrics}.
+ */
+public class TestLlapTaskSchedulerMetrics {
+
+ /**
+ * Verifies that creating metrics for multiple Tez sessions within the same
JVM does not fail.
+ * Each call to {@code LlapTaskSchedulerMetrics.create()} with the same
display name must return
+ * the existing instance without re-registering, otherwise the metrics
system (a static singleton)
+ * would throw {@code MetricsException: Metrics source X already exists!} on
the second call.
+ */
+ @Test
+ public void testCreateIsIdempotentAcrossSessions() {
+ LlapTaskSchedulerMetrics first =
LlapTaskSchedulerMetrics.create("LlapTaskSchedulerMetrics-hiveserver2",
+ "session-1");
+ assertNotNull(first);
+
+ // Must not throw MetricsException: Metrics source LlapTaskScheduler
already exists!
+ LlapTaskSchedulerMetrics second =
LlapTaskSchedulerMetrics.create("LlapTaskSchedulerMetrics-hiveserver2",
+ "session-2");
+ assertNotNull(second);
+ }
+
+ /**
+ * Verifies that creating metrics with different display names does not fail.
+ * Each unique display name triggers a new source registration, but
JvmMetrics must only be
+ * registered once regardless of display name — otherwise the second call
would throw
+ * {@code MetricsException: Metrics source JvmMetrics already exists!}.
+ */
+ @Test
+ public void testCreateWithDifferentDisplayNamesIsIdempotent() {
+ LlapTaskSchedulerMetrics first =
LlapTaskSchedulerMetrics.create("LlapTaskSchedulerMetrics-host1",
+ "session-1");
+ assertNotNull(first);
+
+ // Must not throw MetricsException: Metrics source JvmMetrics already
exists!
+ LlapTaskSchedulerMetrics second =
LlapTaskSchedulerMetrics.create("LlapTaskSchedulerMetrics-host2",
+ "session-2");
+ assertNotNull(second);
+ }
+}