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);
+  }
+}

Reply via email to