You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by vj...@apache.org on 2026/09/17 04:23:52 UTC
(hbase) branch branch-3 updated: HBASE-30334: Reopen parent regions on rollback of MERGE_TABLE_REGIONS_CHECK_CLOSED_REGIONS (#8583)
This is an automated email from the ASF dual-hosted git repository.
virajjasani pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-3 by this push:
new d204d105229 HBASE-30334: Reopen parent regions on rollback of MERGE_TABLE_REGIONS_CHECK_CLOSED_REGIONS (#8583)
d204d105229 is described below
commit d204d105229ca363cad85d658ebcd2d9bb05557a
Author: Nirdosh Yadav <ni...@gmail.com>
AuthorDate: Thu Sep 17 09:51:49 2026 +0530
HBASE-30334: Reopen parent regions on rollback of MERGE_TABLE_REGIONS_CHECK_CLOSED_REGIONS (#8583)
Signed-off-by: Andrew Purtell <ap...@apache.org>
Signed-off-by: Viraj Jasani <vj...@apache.org>
---
.../assignment/MergeTableRegionsProcedure.java | 6 +-
.../assignment/TestMergeTableRegionsProcedure.java | 64 ++++++++++++++++++++++
2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/MergeTableRegionsProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/MergeTableRegionsProcedure.java
index 5fdd2893cca..79d4af0629a 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/MergeTableRegionsProcedure.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/MergeTableRegionsProcedure.java
@@ -284,9 +284,13 @@ public class MergeTableRegionsProcedure
cleanupMergedRegion(env);
break;
case MERGE_TABLE_REGIONS_CHECK_CLOSED_REGIONS:
+ rollbackCloseRegionsForMerge(env);
break;
case MERGE_TABLE_REGIONS_CLOSE_REGIONS:
- rollbackCloseRegionsForMerge(env);
+ // No-op. The reopen TransitRegionStateProcedures for the two parents were already
+ // submitted by the rollback of MERGE_TABLE_REGIONS_CHECK_CLOSED_REGIONS above;
+ // submitting a second batch here would race the first. Mirrors
+ // SplitTableRegionProcedure's rollback of SPLIT_TABLE_REGION_CLOSE_PARENT_REGION.
break;
case MERGE_TABLE_REGIONS_PRE_MERGE_OPERATION:
postRollBackMergeRegions(env);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestMergeTableRegionsProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestMergeTableRegionsProcedure.java
index 1de06e82c02..44bd5208977 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestMergeTableRegionsProcedure.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestMergeTableRegionsProcedure.java
@@ -25,6 +25,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseTestingUtil;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.MetaTableAccessor;
@@ -38,6 +40,7 @@ import org.apache.hadoop.hbase.client.SnapshotType;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.master.procedure.MasterProcedureConstants;
import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
import org.apache.hadoop.hbase.master.procedure.MasterProcedureTestingUtility;
@@ -51,7 +54,10 @@ import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
import org.apache.hadoop.hbase.testclassification.LargeTests;
import org.apache.hadoop.hbase.testclassification.MasterTests;
import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.CommonFSUtils;
+import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.hadoop.hbase.util.Threads;
+import org.apache.hadoop.hbase.wal.WALSplitUtil;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
@@ -327,6 +333,64 @@ public class TestMergeTableRegionsProcedure {
assertEquals(initialRegionCount, regions.size());
}
+ /**
+ * HBASE-30334 repro. Plant a stale recovered.edits file on a parent region so that
+ * MERGE_TABLE_REGIONS_CHECK_CLOSED_REGIONS throws. After rollback the parents MUST be OPEN. If
+ * they stay stuck (e.g. CLOSED / MERGING), the rollback path is broken.
+ */
+ @Test
+ public void testRollbackReopensParentsAfterCheckClosedRegionsFailure() throws Exception {
+ final TableName tableName = TableName.valueOf(testMethodName);
+ UTIL.createTable(tableName, new byte[][] { HConstants.CATALOG_FAMILY },
+ new byte[][] { new byte[] { 'b' } });
+ UTIL.waitUntilAllRegionsAssigned(tableName);
+
+ List<RegionInfo> ris = MetaTableAccessor.getTableRegions(UTIL.getConnection(), tableName);
+ assertEquals(2, ris.size());
+ RegionInfo[] regionsToMerge = new RegionInfo[] { ris.get(0), ris.get(1) };
+
+ Configuration conf = UTIL.getConfiguration();
+ Path regionDir =
+ FSUtils.getRegionDirFromRootDir(CommonFSUtils.getRootDir(conf), regionsToMerge[0]);
+ Path recoveredEditsDir = WALSplitUtil.getRegionDirRecoveredEditsDir(regionDir);
+ FileSystem fs = CommonFSUtils.getRootDirFileSystem(conf);
+ fs.mkdirs(recoveredEditsDir);
+ Path staleFile = new Path(recoveredEditsDir, "0000000000000000001");
+ fs.createNewFile(staleFile);
+ assertTrue(WALSplitUtil.hasRecoveredEdits(conf, regionsToMerge[0]),
+ "stale recovered.edits file must be visible");
+
+ AssignmentManager am = UTIL.getHBaseCluster().getMaster().getAssignmentManager();
+ LOG.info("HBASE-30334-DEBUG pre-merge: {} state={} / {} state={}",
+ regionsToMerge[0].getEncodedName(),
+ am.getRegionStates().getRegionStateNode(regionsToMerge[0]).getState(),
+ regionsToMerge[1].getEncodedName(),
+ am.getRegionStates().getRegionStateNode(regionsToMerge[1]).getState());
+
+ final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
+ MergeTableRegionsProcedure proc =
+ new MergeTableRegionsProcedure(procExec.getEnvironment(), regionsToMerge, true);
+ long procId = procExec.submitProcedure(proc);
+ ProcedureTestingUtility.waitProcedure(procExec, procId);
+
+ RegionState.State s0Post =
+ am.getRegionStates().getRegionStateNode(regionsToMerge[0]).getState();
+ RegionState.State s1Post =
+ am.getRegionStates().getRegionStateNode(regionsToMerge[1]).getState();
+ LOG.info("HBASE-30334-DEBUG post-rollback: {} state={} / {} state={}",
+ regionsToMerge[0].getEncodedName(), s0Post, regionsToMerge[1].getEncodedName(), s1Post);
+
+ ProcedureTestingUtility.assertProcFailed(procExec, procId);
+
+ fs.delete(staleFile, false);
+
+ UTIL.waitFor(30_000, 500, () -> {
+ RegionState.State a = am.getRegionStates().getRegionStateNode(regionsToMerge[0]).getState();
+ RegionState.State b = am.getRegionStates().getRegionStateNode(regionsToMerge[1]).getState();
+ return a == RegionState.State.OPEN && b == RegionState.State.OPEN;
+ });
+ }
+
@Test
public void testMergeWithoutPONR() throws Exception {
final TableName tableName = TableName.valueOf("testMergeWithoutPONR");