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 <[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());