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

lupeng pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2 by this push:
     new 758dc33ce9f HBASE-29831 Fix for NPE in region replication (#7629)
758dc33ce9f is described below

commit 758dc33ce9fdc846846627d080fff21a329a9d15
Author: Kodey Converse <[email protected]>
AuthorDate: Wed Jan 28 09:34:31 2026 -0500

    HBASE-29831 Fix for NPE in region replication (#7629)
    
    Signed-off-by: Chandra Kambham <[email protected]>
    Signed-off-by: Peng Lu <[email protected]>
---
 .../RegionReplicaReplicationEndpoint.java          |  5 +-
 .../TestRegionReplicaReplicationEndpoint.java      | 59 ++++++++++++++++++++++
 2 files changed, 61 insertions(+), 3 deletions(-)

diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/RegionReplicaReplicationEndpoint.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/RegionReplicaReplicationEndpoint.java
index 7dbb4f008f8..bf8316626dd 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/RegionReplicaReplicationEndpoint.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/RegionReplicaReplicationEndpoint.java
@@ -427,7 +427,6 @@ public class RegionReplicaReplicationEndpoint extends 
HBaseReplicationEndpoint {
       // invalidate the cache and check from meta
       RegionLocations locations = null;
       boolean useCache = true;
-      int retries = 0;
       while (true) {
         // get the replicas of the primary region
         try {
@@ -441,12 +440,12 @@ public class RegionReplicaReplicationEndpoint extends 
HBaseReplicationEndpoint {
           // keep going to the cache, we will not learn of the replicas and 
their locations after
           // they come online.
           if (useCache && locations.size() == 1) {
-            if (tableDescriptors.get(tableName).getRegionReplication() > 1 && 
retries <= 3) {
+            TableDescriptor td = tableDescriptors.get(tableName);
+            if (td != null && td.getRegionReplication() > 1) {
               // Make an obnoxious log here. See how bad this issue is. Add a 
timer if happening
               // too much.
               LOG.info("Skipping location cache; only one location found for 
{}", tableName);
               useCache = false;
-              retries++;
               continue;
             }
           }
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplicationEndpoint.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplicationEndpoint.java
index ffca0caabef..861414c3709 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplicationEndpoint.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplicationEndpoint.java
@@ -22,6 +22,10 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -42,7 +46,9 @@ import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.RegionLocations;
 import org.apache.hadoop.hbase.ReplicationPeerNotFoundException;
+import org.apache.hadoop.hbase.TableDescriptors;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.Waiter;
 import org.apache.hadoop.hbase.client.Admin;
@@ -557,6 +563,59 @@ public class TestRegionReplicaReplicationEndpoint {
     }
   }
 
+  @Test
+  public void testNullTableDescriptorDoesNotCauseNPE() throws Exception {
+    TableName tableName = TableName.valueOf(name.getMethodName());
+    int regionReplication = 2;
+    HTableDescriptor htd = HTU.createTableDescriptor(tableName);
+    htd.setRegionReplication(regionReplication);
+    createOrEnableTableWithRetries(htd, true);
+
+    Connection connection = 
ConnectionFactory.createConnection(HTU.getConfiguration());
+    Table table = connection.getTable(tableName);
+
+    try {
+      HTU.loadNumericRows(table, HBaseTestingUtility.fam1, 0, 100);
+
+      RegionLocator rl = connection.getRegionLocator(tableName);
+      HRegionLocation hrl = rl.getRegionLocation(HConstants.EMPTY_BYTE_ARRAY);
+      byte[] encodedRegionName = hrl.getRegionInfo().getEncodedNameAsBytes();
+      rl.close();
+
+      AtomicLong skippedEdits = new AtomicLong();
+      RegionReplicaReplicationEndpoint.RegionReplicaOutputSink sink =
+        mock(RegionReplicaReplicationEndpoint.RegionReplicaOutputSink.class);
+      when(sink.getSkippedEditsCounter()).thenReturn(skippedEdits);
+
+      TableDescriptors mockTableDescriptors = mock(TableDescriptors.class);
+      when(mockTableDescriptors.get(tableName)).thenReturn(null);
+
+      RegionLocations singleLocation = new RegionLocations(hrl);
+      ClusterConnection mockConnection = mock(ClusterConnection.class);
+      when(mockConnection.locateRegion(eq(tableName), any(byte[].class), 
anyBoolean(), anyBoolean(),
+        anyInt())).thenReturn(singleLocation);
+      
when(mockConnection.getConfiguration()).thenReturn(HTU.getConfiguration());
+
+      RegionReplicaReplicationEndpoint.RegionReplicaSinkWriter sinkWriter =
+        new RegionReplicaReplicationEndpoint.RegionReplicaSinkWriter(sink, 
mockConnection,
+          Executors.newSingleThreadExecutor(), Integer.MAX_VALUE, 
mockTableDescriptors);
+
+      Cell cell = CellBuilderFactory.create(CellBuilderType.DEEP_COPY)
+        .setRow(Bytes.toBytes("testRow")).setFamily(HBaseTestingUtility.fam1)
+        .setValue(Bytes.toBytes("testValue")).setType(Type.Put).build();
+
+      Entry entry =
+        new Entry(new WALKeyImpl(encodedRegionName, tableName, 1), new 
WALEdit().add(cell));
+
+      sinkWriter.append(tableName, encodedRegionName, Bytes.toBytes("testRow"),
+        Lists.newArrayList(entry));
+
+    } finally {
+      table.close();
+      connection.close();
+    }
+  }
+
   @Test
   public void testMetaCacheSkippedForSingleReplicaTable() throws Exception {
     TableName tableName = TableName.valueOf(name.getMethodName());

Reply via email to