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

apurtell pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/master by this push:
     new 698937d  HBASE-26864 SplitTableRegionProcedure calls 
openParentRegions() at a … (#4261)
698937d is described below

commit 698937d32bc480f27c8e8ec04c0aba849c975880
Author: huaxiangsun <[email protected]>
AuthorDate: Sat Mar 26 12:02:16 2022 -0700

    HBASE-26864 SplitTableRegionProcedure calls openParentRegions() at a … 
(#4261)
    
    Signed-off-by: Duo Zhang <[email protected]>
    Signed-off-by: Xiaolin Ha <[email protected]>
---
 .../master/assignment/AssignmentManagerUtil.java   |   8 +-
 .../assignment/SplitTableRegionProcedure.java      |  12 ++-
 .../assignment/TestSplitTableRegionProcedure.java  | 101 +++++++++++++++++++++
 3 files changed, 117 insertions(+), 4 deletions(-)

diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManagerUtil.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManagerUtil.java
index 5f8f784..f16b46a 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManagerUtil.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManagerUtil.java
@@ -180,9 +180,15 @@ final class AssignmentManagerUtil {
     for (RegionInfo hri : regions) {
       // start the index from 1
       for (int i = 1; i < regionReplication; i++) {
-        replicaRegionInfos.add(RegionReplicaUtil.getRegionInfoForReplica(hri, 
i));
+        RegionInfo ri = RegionReplicaUtil.getRegionInfoForReplica(hri, i);
+        // apply ignoreRITs to replica regions as well.
+        if (!ignoreIfInTransition || 
!env.getAssignmentManager().getRegionStates().
+          getOrCreateRegionStateNode(ri).isInTransition()) {
+          replicaRegionInfos.add(ri);
+        }
       }
     }
+
     // create round robin procs. Note that we exclude the primary region's 
target server
     TransitRegionStateProcedure[] replicaRegionAssignProcs =
         
env.getAssignmentManager().createRoundRobinAssignProcedures(replicaRegionInfos,
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/SplitTableRegionProcedure.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/SplitTableRegionProcedure.java
index effdba4..825b989 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/SplitTableRegionProcedure.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/SplitTableRegionProcedure.java
@@ -302,6 +302,11 @@ public class SplitTableRegionProcedure
           break;
         case SPLIT_TABLE_REGION_CLOSE_PARENT_REGION:
           addChildProcedure(createUnassignProcedures(env));
+          // createUnassignProcedures() can throw out IOException. If this 
happens,
+          // it wont reach state SPLIT_TABLE_REGIONS_CHECK_CLOSED_REGION and 
no parent regions
+          // is closed as all created UnassignProcedures are rolled back. If 
it rolls back with
+          // state SPLIT_TABLE_REGION_CLOSE_PARENT_REGION, no need to call 
openParentRegion(),
+          // otherwise, it will result in OpenRegionProcedure for an already 
open region.
           
setNextState(SplitTableRegionState.SPLIT_TABLE_REGIONS_CHECK_CLOSED_REGIONS);
           break;
         case SPLIT_TABLE_REGIONS_CHECK_CLOSED_REGIONS:
@@ -379,11 +384,12 @@ public class SplitTableRegionProcedure
           deleteDaughterRegions(env);
           break;
         case SPLIT_TABLE_REGIONS_CHECK_CLOSED_REGIONS:
-          // Doing nothing, in SPLIT_TABLE_REGION_CLOSE_PARENT_REGION,
-          // we will bring parent region online
+          openParentRegion(env);
           break;
         case SPLIT_TABLE_REGION_CLOSE_PARENT_REGION:
-          openParentRegion(env);
+          // If it rolls back with state 
SPLIT_TABLE_REGION_CLOSE_PARENT_REGION, no need to call
+          // openParentRegion(), otherwise, it will result in 
OpenRegionProcedure for an
+          // already open region.
           break;
         case SPLIT_TABLE_REGION_PRE_OPERATION:
           postRollBackSplitRegion(env);
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestSplitTableRegionProcedure.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestSplitTableRegionProcedure.java
index bbcce85..9cb6fd8 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestSplitTableRegionProcedure.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/assignment/TestSplitTableRegionProcedure.java
@@ -20,10 +20,12 @@ package org.apache.hadoop.hbase.master.assignment;
 import static 
org.apache.hadoop.hbase.master.assignment.AssignmentTestingUtil.insertData;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Optional;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellUtil;
@@ -37,9 +39,14 @@ import org.apache.hadoop.hbase.client.CompactionState;
 import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.Get;
 import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.client.RegionReplicaUtil;
 import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.client.Table;
 import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.coprocessor.ObserverContext;
+import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
+import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
+import org.apache.hadoop.hbase.coprocessor.RegionObserver;
 import org.apache.hadoop.hbase.master.procedure.MasterProcedureConstants;
 import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
 import org.apache.hadoop.hbase.master.procedure.MasterProcedureTestingUtility;
@@ -98,6 +105,39 @@ public class TestSplitTableRegionProcedure {
   private static void setupConf(Configuration conf) {
     conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
     conf.setLong(HConstants.MAJOR_COMPACTION_PERIOD, 0);
+    conf.set("hbase.coprocessor.region.classes",
+      RegionServerHostingReplicaSlowOpenCopro.class.getName());
+    conf.setInt("hbase.client.sync.wait.timeout.msec", 1500);
+  }
+
+  /**
+   * This copro is used to slow down opening of the replica regions.
+   */
+  public static class RegionServerHostingReplicaSlowOpenCopro
+    implements RegionCoprocessor, RegionObserver {
+    static int countForReplica = 0;
+    static boolean slowDownReplicaOpen = false;
+
+    @Override
+    public Optional<RegionObserver> getRegionObserver() {
+      return Optional.of(this);
+    }
+
+    @Override
+    public void preOpen(ObserverContext<RegionCoprocessorEnvironment> c) 
throws IOException {
+      int replicaId = 
c.getEnvironment().getRegion().getRegionInfo().getReplicaId();
+      if ((replicaId != RegionInfo.DEFAULT_REPLICA_ID) && (countForReplica == 
0)) {
+        countForReplica ++;
+        while (slowDownReplicaOpen) {
+          LOG.info("Slow down replica region open a bit");
+          try {
+            Thread.sleep(100);
+          } catch (InterruptedException ie) {
+            // Ingore
+          }
+        }
+      }
+    }
   }
 
   @BeforeClass
@@ -137,6 +177,67 @@ public class TestSplitTableRegionProcedure {
     }
   }
 
+
+  @Test
+  public void testRollbackForSplitTableRegionWithReplica() throws Exception {
+    final TableName tableName = TableName.valueOf(name.getMethodName());
+    final ProcedureExecutor<MasterProcedureEnv> procExec = 
getMasterProcedureExecutor();
+
+
+    RegionServerHostingReplicaSlowOpenCopro.slowDownReplicaOpen = true;
+    RegionInfo [] regions = MasterProcedureTestingUtility.createTable(
+      procExec, tableName, null, columnFamilyName1);
+
+    try {
+      HBaseTestingUtil.setReplicas(UTIL.getAdmin(), tableName, 2);
+    } catch (IOException ioe) {
+
+    }
+
+    // wait until the primary region is online.
+    HBaseTestingUtil.await(2000, () -> {
+      try {
+        AssignmentManager am = 
UTIL.getHBaseCluster().getMaster().getAssignmentManager();
+        if (am == null) return false;
+        if (am.getRegionStates().getRegionState(regions[0]).isOpened()) {
+          return true;
+        }
+        return false;
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    });
+
+    // Split region of the table, it will fail and rollback as replica parent 
region
+    // is still at OPENING state.
+    long procId = procExec.submitProcedure(new SplitTableRegionProcedure(
+      procExec.getEnvironment(), regions[0], HConstants.CATALOG_FAMILY));
+    // Wait for the completion.
+    ProcedureTestingUtility.waitProcedure(procExec, procId);
+
+    // Let replica parent region open.
+    RegionServerHostingReplicaSlowOpenCopro.slowDownReplicaOpen = false;
+
+    // wait until the replica region is online.
+    HBaseTestingUtil.await(2000, () -> {
+      try {
+        AssignmentManager am = 
UTIL.getHBaseCluster().getMaster().getAssignmentManager();
+        if (am == null) return false;
+        RegionInfo replicaRegion = 
RegionReplicaUtil.getRegionInfoForReplica(regions[0], 1);
+        if (am.getRegionStates().getRegionState(replicaRegion).isOpened()) {
+          return true;
+        }
+        return false;
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    });
+
+    ProcedureTestingUtility.assertProcFailed(procExec, procId);
+    // There should not be any active OpenRegionProcedure
+    procExec.getActiveProceduresNoCopy().forEach(p -> assertFalse(p instanceof 
OpenRegionProcedure));
+  }
+
   @Test
   public void testSplitTableRegion() throws Exception {
     final TableName tableName = TableName.valueOf(name.getMethodName());

Reply via email to