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.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.io.IOException; 026import java.util.List; 027import java.util.concurrent.ExecutionException; 028import java.util.concurrent.Future; 029import java.util.concurrent.TimeUnit; 030import org.apache.hadoop.hbase.DoNotRetryIOException; 031import org.apache.hadoop.hbase.HBaseClassTestRule; 032import org.apache.hadoop.hbase.HBaseTestingUtility; 033import org.apache.hadoop.hbase.HRegionInfo; 034import org.apache.hadoop.hbase.ServerName; 035import org.apache.hadoop.hbase.TableName; 036import org.apache.hadoop.hbase.master.assignment.AssignmentTestingUtil; 037import org.apache.hadoop.hbase.master.assignment.SplitTableRegionProcedure; 038import org.apache.hadoop.hbase.master.procedure.DeleteTableProcedure; 039import org.apache.hadoop.hbase.master.procedure.DisableTableProcedure; 040import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; 041import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 042import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 043import org.apache.hadoop.hbase.testclassification.ClientTests; 044import org.apache.hadoop.hbase.testclassification.MediumTests; 045import org.apache.hadoop.hbase.util.Bytes; 046import org.apache.hadoop.hbase.util.Threads; 047import org.junit.After; 048import org.junit.Before; 049import org.junit.ClassRule; 050import org.junit.Ignore; 051import org.junit.Rule; 052import org.junit.Test; 053import org.junit.experimental.categories.Category; 054import org.junit.rules.TestName; 055 056@Category({ MediumTests.class, ClientTests.class }) 057public class TestSplitOrMergeStatus { 058 059 @ClassRule 060 public static final HBaseClassTestRule CLASS_RULE = 061 HBaseClassTestRule.forClass(TestSplitOrMergeStatus.class); 062 063 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 064 private static byte[] FAMILY = Bytes.toBytes("testFamily"); 065 066 @Rule 067 public TestName name = new TestName(); 068 069 /** 070 * @throws java.lang.Exception 071 */ 072 @Before 073 public void setUp() throws Exception { 074 TEST_UTIL.startMiniCluster(2); 075 } 076 077 /** 078 * @throws java.lang.Exception 079 */ 080 @After 081 public void tearDown() throws Exception { 082 TEST_UTIL.shutdownMiniCluster(); 083 } 084 085 @Test 086 public void testSplitSwitch() throws Exception { 087 final TableName tableName = TableName.valueOf(name.getMethodName()); 088 Table t = TEST_UTIL.createTable(tableName, FAMILY); 089 TEST_UTIL.loadTable(t, FAMILY, false); 090 091 RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(t.getName()); 092 int originalCount = locator.getAllRegionLocations().size(); 093 094 Admin admin = TEST_UTIL.getAdmin(); 095 initSwitchStatus(admin); 096 assertTrue(admin.splitSwitch(false, false)); 097 try { 098 admin.split(t.getName()); 099 fail("Shouldn't get here"); 100 } catch (DoNotRetryIOException dnioe) { 101 // Expected 102 } 103 int count = admin.getTableRegions(tableName).size(); 104 assertTrue(originalCount == count); 105 assertFalse(admin.splitSwitch(true, false)); 106 admin.split(t.getName()); 107 while ((count = admin.getTableRegions(tableName).size()) == originalCount) { 108 Threads.sleep(1); 109 ; 110 } 111 count = admin.getTableRegions(tableName).size(); 112 assertTrue(originalCount < count); 113 admin.close(); 114 } 115 116 @Ignore 117 @Test 118 public void testMergeSwitch() throws Exception { 119 final TableName tableName = TableName.valueOf(name.getMethodName()); 120 Table t = TEST_UTIL.createTable(tableName, FAMILY); 121 TEST_UTIL.loadTable(t, FAMILY, false); 122 123 Admin admin = TEST_UTIL.getAdmin(); 124 int originalCount = admin.getTableRegions(tableName).size(); 125 initSwitchStatus(admin); 126 admin.split(t.getName()); 127 int postSplitCount = -1; 128 while ((postSplitCount = admin.getTableRegions(tableName).size()) == originalCount) { 129 Threads.sleep(1); 130 ; 131 } 132 assertTrue("originalCount=" + originalCount + ", newCount=" + postSplitCount, 133 originalCount != postSplitCount); 134 135 // Merge switch is off so merge should NOT succeed. 136 boolean[] results = admin.setSplitOrMergeEnabled(false, false, MasterSwitchType.MERGE); 137 assertEquals(1, results.length); 138 assertTrue(results[0]); 139 List<HRegionInfo> regions = admin.getTableRegions(t.getName()); 140 assertTrue(regions.size() > 1); 141 Future<?> f = admin.mergeRegionsAsync(regions.get(0).getEncodedNameAsBytes(), 142 regions.get(1).getEncodedNameAsBytes(), true); 143 try { 144 f.get(10, TimeUnit.SECONDS); 145 fail("Should not get here."); 146 } catch (ExecutionException ee) { 147 // Expected. 148 } 149 int count = admin.getTableRegions(tableName).size(); 150 assertTrue("newCount=" + postSplitCount + ", count=" + count, postSplitCount == count); 151 152 results = admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.MERGE); 153 regions = admin.getTableRegions(t.getName()); 154 assertEquals(1, results.length); 155 assertFalse(results[0]); 156 f = admin.mergeRegionsAsync(regions.get(0).getEncodedNameAsBytes(), 157 regions.get(1).getEncodedNameAsBytes(), true); 158 f.get(10, TimeUnit.SECONDS); 159 count = admin.getTableRegions(tableName).size(); 160 assertTrue((postSplitCount / 2 /* Merge */) == count); 161 admin.close(); 162 } 163 164 @Test 165 public void testMultiSwitches() throws IOException { 166 Admin admin = TEST_UTIL.getAdmin(); 167 boolean[] switches = 168 admin.setSplitOrMergeEnabled(false, false, MasterSwitchType.SPLIT, MasterSwitchType.MERGE); 169 for (boolean s : switches) { 170 assertTrue(s); 171 } 172 assertFalse(admin.isSplitOrMergeEnabled(MasterSwitchType.SPLIT)); 173 assertFalse(admin.isSplitOrMergeEnabled(MasterSwitchType.MERGE)); 174 admin.close(); 175 } 176 177 @Test 178 public void testSplitRegionReplicaRitRecovery() throws Exception { 179 int startRowNum = 11; 180 int rowCount = 60; 181 final TableName tableName = TableName.valueOf(name.getMethodName()); 182 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 183 TEST_UTIL.getAdmin().createTable(TableDescriptorBuilder.newBuilder(tableName) 184 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).setRegionReplication(2).build()); 185 TEST_UTIL.waitUntilAllRegionsAssigned(tableName); 186 ServerName serverName = 187 RegionReplicaTestHelper.getRSCarryingReplica(TEST_UTIL, tableName, 1).get(); 188 List<RegionInfo> regions = TEST_UTIL.getAdmin().getRegions(tableName); 189 insertData(tableName, startRowNum, rowCount); 190 int splitRowNum = startRowNum + rowCount / 2; 191 byte[] splitKey = Bytes.toBytes("" + splitRowNum); 192 // Split region of the table 193 long procId = procExec.submitProcedure( 194 new SplitTableRegionProcedure(procExec.getEnvironment(), regions.get(0), splitKey)); 195 // Wait the completion 196 ProcedureTestingUtility.waitProcedure(procExec, procId); 197 // Disable the table 198 long procId1 = procExec 199 .submitProcedure(new DisableTableProcedure(procExec.getEnvironment(), tableName, false)); 200 // Wait the completion 201 ProcedureTestingUtility.waitProcedure(procExec, procId1); 202 // Delete Table 203 long procId2 = 204 procExec.submitProcedure(new DeleteTableProcedure(procExec.getEnvironment(), tableName)); 205 // Wait the completion 206 ProcedureTestingUtility.waitProcedure(procExec, procId2); 207 AssignmentTestingUtil.killRs(TEST_UTIL, serverName); 208 Threads.sleepWithoutInterrupt(5000); 209 boolean hasRegionsInTransition = TEST_UTIL.getMiniHBaseCluster().getMaster() 210 .getAssignmentManager().getRegionStates().hasRegionsInTransition(); 211 assertEquals(false, hasRegionsInTransition); 212 } 213 214 private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() { 215 return TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); 216 } 217 218 private void insertData(final TableName tableName, int startRow, int rowCount) 219 throws IOException { 220 Table t = TEST_UTIL.getConnection().getTable(tableName); 221 Put p; 222 for (int i = 0; i < rowCount; i++) { 223 p = new Put(Bytes.toBytes("" + (startRow + i))); 224 p.addColumn(FAMILY, Bytes.toBytes("q1"), Bytes.toBytes(i)); 225 t.put(p); 226 } 227 } 228 229 private void initSwitchStatus(Admin admin) throws IOException { 230 if (!admin.isSplitEnabled()) { 231 admin.splitSwitch(true, false); 232 } 233 if (!admin.isMergeEnabled()) { 234 admin.mergeSwitch(true, false); 235 } 236 assertTrue(admin.isSplitEnabled()); 237 assertTrue(admin.isMergeEnabled()); 238 } 239}