001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.master.assignment; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.io.IOException; 025import org.apache.hadoop.hbase.HBaseClassTestRule; 026import org.apache.hadoop.hbase.HBaseTestingUtil; 027import org.apache.hadoop.hbase.TableName; 028import org.apache.hadoop.hbase.client.RegionInfo; 029import org.apache.hadoop.hbase.master.HMaster; 030import org.apache.hadoop.hbase.master.procedure.MasterProcedureConstants; 031import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; 032import org.apache.hadoop.hbase.master.procedure.MasterProcedureTestingUtility; 033import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 034import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 035import org.apache.hadoop.hbase.regionserver.HRegion; 036import org.apache.hadoop.hbase.regionserver.HRegionServer; 037import org.apache.hadoop.hbase.testclassification.MasterTests; 038import org.apache.hadoop.hbase.testclassification.MediumTests; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.junit.After; 041import org.junit.AfterClass; 042import org.junit.Before; 043import org.junit.BeforeClass; 044import org.junit.ClassRule; 045import org.junit.Rule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048import org.junit.rules.TestName; 049 050@Category({ MasterTests.class, MediumTests.class }) 051public class TestTransitRegionStateProcedure { 052 053 @ClassRule 054 public static final HBaseClassTestRule CLASS_RULE = 055 HBaseClassTestRule.forClass(TestTransitRegionStateProcedure.class); 056 057 private static HBaseTestingUtil UTIL = new HBaseTestingUtil(); 058 059 private static byte[] CF = Bytes.toBytes("cf"); 060 061 @Rule 062 public TestName name = new TestName(); 063 064 private TableName tableName; 065 066 @BeforeClass 067 public static void setUpBeforeClass() throws Exception { 068 UTIL.getConfiguration().setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); 069 UTIL.startMiniCluster(3); 070 UTIL.getAdmin().balancerSwitch(false, true); 071 } 072 073 @AfterClass 074 public static void tearDownAfterClass() throws Exception { 075 UTIL.shutdownMiniCluster(); 076 } 077 078 @Before 079 public void setUp() throws IOException, InterruptedException { 080 tableName = TableName.valueOf(name.getMethodName()); 081 UTIL.createTable(tableName, CF); 082 UTIL.waitTableAvailable(tableName); 083 } 084 085 private void resetProcExecutorTestingKillFlag() { 086 ProcedureExecutor<MasterProcedureEnv> procExec = 087 UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); 088 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false); 089 assertTrue("expected executor to be running", procExec.isRunning()); 090 } 091 092 @After 093 public void tearDown() throws IOException { 094 resetProcExecutorTestingKillFlag(); 095 UTIL.deleteTable(tableName); 096 } 097 098 private void testRecoveryAndDoubleExcution(TransitRegionStateProcedure proc) throws Exception { 099 HMaster master = UTIL.getHBaseCluster().getMaster(); 100 AssignmentManager am = master.getAssignmentManager(); 101 RegionStateNode regionNode = am.getRegionStates().getRegionStateNode(proc.getRegion()); 102 assertFalse(regionNode.isInTransition()); 103 regionNode.setProcedure(proc); 104 assertTrue(regionNode.isInTransition()); 105 ProcedureExecutor<MasterProcedureEnv> procExec = master.getMasterProcedureExecutor(); 106 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 107 long procId = procExec.submitProcedure(proc); 108 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId); 109 regionNode = am.getRegionStates().getRegionStateNode(proc.getRegion()); 110 assertFalse(regionNode.isInTransition()); 111 } 112 113 @Test 114 public void testRecoveryAndDoubleExecutionMove() throws Exception { 115 MasterProcedureEnv env = 116 UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor().getEnvironment(); 117 HRegion region = UTIL.getMiniHBaseCluster().getRegions(tableName).get(0); 118 long openSeqNum = region.getOpenSeqNum(); 119 TransitRegionStateProcedure proc = 120 TransitRegionStateProcedure.move(env, region.getRegionInfo(), null); 121 testRecoveryAndDoubleExcution(proc); 122 HRegion region2 = UTIL.getMiniHBaseCluster().getRegions(tableName).get(0); 123 long openSeqNum2 = region2.getOpenSeqNum(); 124 // confirm that the region is successfully opened 125 assertTrue(openSeqNum2 > openSeqNum); 126 } 127 128 @Test 129 public void testRecoveryAndDoubleExecutionReopen() throws Exception { 130 MasterProcedureEnv env = 131 UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor().getEnvironment(); 132 HRegionServer rs = UTIL.getRSForFirstRegionInTable(tableName); 133 HRegion region = rs.getRegions(tableName).get(0); 134 region.addReadRequestsCount(1); 135 region.addWriteRequestsCount(2); 136 long openSeqNum = region.getOpenSeqNum(); 137 TransitRegionStateProcedure proc = 138 TransitRegionStateProcedure.reopen(env, region.getRegionInfo()); 139 testRecoveryAndDoubleExcution(proc); 140 // should still be on the same RS 141 HRegion region2 = rs.getRegions(tableName).get(0); 142 long openSeqNum2 = region2.getOpenSeqNum(); 143 // confirm that the region is successfully opened 144 assertTrue(openSeqNum2 > openSeqNum); 145 // we check the available by scan after table created, 146 // so the readRequestsCount should be 2 here 147 assertEquals(2, region2.getReadRequestsCount()); 148 assertEquals(2, region2.getWriteRequestsCount()); 149 } 150 151 @Test 152 public void testRecoveryAndDoubleExecutionUnassignAndAssign() throws Exception { 153 HMaster master = UTIL.getMiniHBaseCluster().getMaster(); 154 MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment(); 155 HRegion region = UTIL.getMiniHBaseCluster().getRegions(tableName).get(0); 156 RegionInfo regionInfo = region.getRegionInfo(); 157 long openSeqNum = region.getOpenSeqNum(); 158 TransitRegionStateProcedure unassign = TransitRegionStateProcedure.unassign(env, regionInfo); 159 testRecoveryAndDoubleExcution(unassign); 160 AssignmentManager am = master.getAssignmentManager(); 161 assertTrue(am.getRegionStates().getRegionState(regionInfo).isClosed()); 162 163 TransitRegionStateProcedure assign = TransitRegionStateProcedure.assign(env, regionInfo, null); 164 testRecoveryAndDoubleExcution(assign); 165 166 HRegion region2 = UTIL.getMiniHBaseCluster().getRegions(tableName).get(0); 167 long openSeqNum2 = region2.getOpenSeqNum(); 168 // confirm that the region is successfully opened 169 assertTrue(openSeqNum2 > openSeqNum); 170 } 171}