This is an automated email from the ASF dual-hosted git repository.

tkhurana pushed a commit to branch PHOENIX-7562-feature-new
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/PHOENIX-7562-feature-new by 
this push:
     new 2c9bb7477d PHOENIX-7775 ReplicationLogGroup initialization fixes 
(#2386)
2c9bb7477d is described below

commit 2c9bb7477df365f9071e7323b682fdadb1c7b409
Author: tkhurana <[email protected]>
AuthorDate: Sat Feb 28 10:59:10 2026 -0800

    PHOENIX-7775 ReplicationLogGroup initialization fixes (#2386)
---
 .../phoenix/replication/ReplicationLogGroup.java   | 16 +++++++--
 .../MetricsReplicationLogGroupSourceFactory.java   | 39 ++++++++++++++++++++++
 .../replication/ReplicationLogGroupTest.java       | 29 ++++++++++++++++
 3 files changed, 81 insertions(+), 3 deletions(-)

diff --git 
a/phoenix-core-server/src/main/java/org/apache/phoenix/replication/ReplicationLogGroup.java
 
b/phoenix-core-server/src/main/java/org/apache/phoenix/replication/ReplicationLogGroup.java
index b7a5ca0228..0b31a3e940 100644
--- 
a/phoenix-core-server/src/main/java/org/apache/phoenix/replication/ReplicationLogGroup.java
+++ 
b/phoenix-core-server/src/main/java/org/apache/phoenix/replication/ReplicationLogGroup.java
@@ -41,6 +41,7 @@ import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
@@ -61,7 +62,7 @@ import org.apache.phoenix.jdbc.HAGroupStoreManager;
 import org.apache.phoenix.jdbc.HAGroupStoreRecord;
 import org.apache.phoenix.jdbc.HAGroupStoreRecord.HAGroupState;
 import org.apache.phoenix.replication.metrics.MetricsReplicationLogGroupSource;
-import 
org.apache.phoenix.replication.metrics.MetricsReplicationLogGroupSourceImpl;
+import 
org.apache.phoenix.replication.metrics.MetricsReplicationLogGroupSourceFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -394,7 +395,16 @@ public class ReplicationLogGroup {
    */
   protected ReplicationLogGroup(Configuration conf, ServerName serverName, 
String haGroupName,
     HAGroupStoreManager haGroupStoreManager) {
-    this.conf = conf;
+    // conf object from coprocessor is instance of
+    // org.apache.hadoop.hbase.coprocessor.ReadOnlyConfiguration and we need 
to modify it when
+    // we send rpc to namenode so copying it
+    // Clone configuration by iterating all entries because 
ReadOnlyConfiguration wraps the
+    // original config so you can't use the Configuration(other) constructor 
to create a clone
+    Configuration clonedConf = new Configuration();
+    for (Map.Entry<String, String> entry : conf) {
+      clonedConf.set(entry.getKey(), entry.getValue());
+    }
+    this.conf = clonedConf;
     this.serverName = serverName;
     this.haGroupName = haGroupName;
     this.haGroupStoreManager = haGroupStoreManager;
@@ -717,7 +727,7 @@ public class ReplicationLogGroup {
 
   /** Create a new metrics source for monitoring operations. */
   protected MetricsReplicationLogGroupSource createMetricsSource() {
-    return new MetricsReplicationLogGroupSourceImpl(haGroupName);
+    return 
MetricsReplicationLogGroupSourceFactory.getInstanceForLogGroup(haGroupName);
   }
 
   /**
diff --git 
a/phoenix-core-server/src/main/java/org/apache/phoenix/replication/metrics/MetricsReplicationLogGroupSourceFactory.java
 
b/phoenix-core-server/src/main/java/org/apache/phoenix/replication/metrics/MetricsReplicationLogGroupSourceFactory.java
new file mode 100644
index 0000000000..8c3a083ade
--- /dev/null
+++ 
b/phoenix-core-server/src/main/java/org/apache/phoenix/replication/metrics/MetricsReplicationLogGroupSourceFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.phoenix.replication.metrics;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Factory class for creating log forwarder metrics
+ */
+public class MetricsReplicationLogGroupSourceFactory {
+
+  private MetricsReplicationLogGroupSourceFactory() {
+    // Utility class, no instantiation
+  }
+
+  /** Cache of ReplicationLogTrackerForwarderImpl instances by HA Group ID */
+  private static final ConcurrentHashMap<String,
+    MetricsReplicationLogGroupSource> LOG_GROUP_INSTANCES = new 
ConcurrentHashMap<>();
+
+  public static MetricsReplicationLogGroupSource getInstanceForLogGroup(String 
haGroupName) {
+    return LOG_GROUP_INSTANCES.computeIfAbsent(haGroupName,
+      k -> new MetricsReplicationLogGroupSourceImpl(haGroupName));
+  }
+}
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/replication/ReplicationLogGroupTest.java
 
b/phoenix-core/src/test/java/org/apache/phoenix/replication/ReplicationLogGroupTest.java
index 68fa17196f..39109364c0 100644
--- 
a/phoenix-core/src/test/java/org/apache/phoenix/replication/ReplicationLogGroupTest.java
+++ 
b/phoenix-core/src/test/java/org/apache/phoenix/replication/ReplicationLogGroupTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -1264,6 +1265,34 @@ public class ReplicationLogGroupTest extends 
ReplicationLogBaseTest {
     inOrder.verify(storeAndForwardWriter, times(1)).sync();
   }
 
+  /**
+   * Tests that multiple instances of the same HA group don't attempt to 
register the same jmx
+   * metrics instance which is not allowed.
+   */
+  @Test
+  public void testMetricsCaching() throws Exception {
+    String hagroup1 = "group1";
+    // create a HA group which creates the metrics jmx instance
+    ReplicationLogGroup group1 =
+      spy(new ReplicationLogGroup(conf, serverName, hagroup1, 
haGroupStoreManager));
+    // HA group initialization fails so the HA group is not cached
+    doThrow(new IOException("Simulate HAGroup initialization 
error")).when(group1).init();
+    try {
+      group1.init();
+      fail("HAGroup initialization should have failed");
+    } catch (IOException e) {
+      // expected
+    }
+    // retry creating another instance of the same HA Group
+    ReplicationLogGroup group2 =
+      new ReplicationLogGroup(conf, serverName, hagroup1, haGroupStoreManager);
+    // this time initialization succeeds
+    group2.init();
+    // metrics instance is the same in both the instances
+    assertEquals(group1.metrics, group2.metrics);
+    group2.close();
+  }
+
   // @Test
   public void testAppendTimeoutWhileSyncPending() throws Exception {
     final String tableName = "TESTTBL";

Reply via email to