You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by lu...@apache.org on 2026/01/28 14:50:28 UTC
(hbase) branch branch-2.6 updated: HBASE-29831 Fix for NPE in region replication (#7629)
This is an automated email from the ASF dual-hosted git repository.
lupeng pushed a commit to branch branch-2.6
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-2.6 by this push:
new a2335f89877 HBASE-29831 Fix for NPE in region replication (#7629)
a2335f89877 is described below
commit a2335f89877e75523cb88fad1b43da787b51076e
Author: Kodey Converse <ko...@conve.rs>
AuthorDate: Wed Jan 28 09:34:31 2026 -0500
HBASE-29831 Fix for NPE in region replication (#7629)
Signed-off-by: Chandra Kambham <ch...@apache.org>
Signed-off-by: Peng Lu <lu...@apache.org>
---
.../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());