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; 030 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 boolean[] results = admin.setSplitOrMergeEnabled(false, false, MasterSwitchType.SPLIT); 097 assertEquals(1, results.length); 098 assertTrue(results[0]); 099 admin.split(t.getName()); 100 int count = admin.getTableRegions(tableName).size(); 101 assertTrue(originalCount == count); 102 results = admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.SPLIT); 103 assertEquals(1, results.length); 104 assertFalse(results[0]); 105 admin.split(t.getName()); 106 while ((count = admin.getTableRegions(tableName).size()) == originalCount) { 107 Threads.sleep(1);; 108 } 109 count = admin.getTableRegions(tableName).size(); 110 assertTrue(originalCount < count); 111 admin.close(); 112 } 113 114 115 @Ignore @Test 116 public void testMergeSwitch() throws Exception { 117 final TableName tableName = TableName.valueOf(name.getMethodName()); 118 Table t = TEST_UTIL.createTable(tableName, FAMILY); 119 TEST_UTIL.loadTable(t, FAMILY, false); 120 121 Admin admin = TEST_UTIL.getAdmin(); 122 int originalCount = admin.getTableRegions(tableName).size(); 123 initSwitchStatus(admin); 124 admin.split(t.getName()); 125 int postSplitCount = -1; 126 while ((postSplitCount = admin.getTableRegions(tableName).size()) == originalCount) { 127 Threads.sleep(1);; 128 } 129 assertTrue("originalCount=" + originalCount + ", newCount=" + postSplitCount, 130 originalCount != postSplitCount); 131 132 // Merge switch is off so merge should NOT succeed. 133 boolean[] results = admin.setSplitOrMergeEnabled(false, false, MasterSwitchType.MERGE); 134 assertEquals(1, results.length); 135 assertTrue(results[0]); 136 List<HRegionInfo> regions = admin.getTableRegions(t.getName()); 137 assertTrue(regions.size() > 1); 138 Future<?> f = admin.mergeRegionsAsync(regions.get(0).getEncodedNameAsBytes(), 139 regions.get(1).getEncodedNameAsBytes(), true); 140 try { 141 f.get(10, TimeUnit.SECONDS); 142 fail("Should not get here."); 143 } catch (ExecutionException ee) { 144 // Expected. 145 } 146 int count = admin.getTableRegions(tableName).size(); 147 assertTrue("newCount=" + postSplitCount + ", count=" + count, postSplitCount == count); 148 149 results = admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.MERGE); 150 regions = admin.getTableRegions(t.getName()); 151 assertEquals(1, results.length); 152 assertFalse(results[0]); 153 f = admin.mergeRegionsAsync(regions.get(0).getEncodedNameAsBytes(), 154 regions.get(1).getEncodedNameAsBytes(), true); 155 f.get(10, TimeUnit.SECONDS); 156 count = admin.getTableRegions(tableName).size(); 157 assertTrue((postSplitCount / 2 /*Merge*/) == count); 158 admin.close(); 159 } 160 161 @Test 162 public void testMultiSwitches() throws IOException { 163 Admin admin = TEST_UTIL.getAdmin(); 164 boolean[] switches = admin.setSplitOrMergeEnabled(false, false, 165 MasterSwitchType.SPLIT, MasterSwitchType.MERGE); 166 for (boolean s : switches){ 167 assertTrue(s); 168 } 169 assertFalse(admin.isSplitOrMergeEnabled(MasterSwitchType.SPLIT)); 170 assertFalse(admin.isSplitOrMergeEnabled(MasterSwitchType.MERGE)); 171 admin.close(); 172 } 173 174 @Test 175 public void testSplitRegionReplicaRitRecovery() throws Exception { 176 int startRowNum = 11; 177 int rowCount = 60; 178 final TableName tableName = TableName.valueOf(name.getMethodName()); 179 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 180 TEST_UTIL.getAdmin().createTable(TableDescriptorBuilder.newBuilder(tableName) 181 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).setRegionReplication(2).build()); 182 TEST_UTIL.waitUntilAllRegionsAssigned(tableName); 183 ServerName serverName = 184 RegionReplicaTestHelper.getRSCarryingReplica(TEST_UTIL, tableName, 1).get(); 185 List<RegionInfo> regions = TEST_UTIL.getAdmin().getRegions(tableName); 186 insertData(tableName, startRowNum, rowCount); 187 int splitRowNum = startRowNum + rowCount / 2; 188 byte[] splitKey = Bytes.toBytes("" + splitRowNum); 189 // Split region of the table 190 long procId = procExec.submitProcedure( 191 new SplitTableRegionProcedure(procExec.getEnvironment(), regions.get(0), splitKey)); 192 // Wait the completion 193 ProcedureTestingUtility.waitProcedure(procExec, procId); 194 // Disable the table 195 long procId1 = procExec 196 .submitProcedure(new DisableTableProcedure(procExec.getEnvironment(), tableName, false)); 197 // Wait the completion 198 ProcedureTestingUtility.waitProcedure(procExec, procId1); 199 // Delete Table 200 long procId2 = 201 procExec.submitProcedure(new DeleteTableProcedure(procExec.getEnvironment(), tableName)); 202 // Wait the completion 203 ProcedureTestingUtility.waitProcedure(procExec, procId2); 204 AssignmentTestingUtil.killRs(TEST_UTIL, serverName); 205 Threads.sleepWithoutInterrupt(5000); 206 boolean hasRegionsInTransition = TEST_UTIL.getMiniHBaseCluster().getMaster() 207 .getAssignmentManager().getRegionStates().hasRegionsInTransition(); 208 assertEquals(false, hasRegionsInTransition); 209 } 210 211 private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() { 212 return TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); 213 } 214 215 private void insertData(final TableName tableName, int startRow, int rowCount) 216 throws IOException { 217 Table t = TEST_UTIL.getConnection().getTable(tableName); 218 Put p; 219 for (int i = 0; i < rowCount; i++) { 220 p = new Put(Bytes.toBytes("" + (startRow + i))); 221 p.addColumn(FAMILY, Bytes.toBytes("q1"), Bytes.toBytes(i)); 222 t.put(p); 223 } 224 } 225 226 private void initSwitchStatus(Admin admin) throws IOException { 227 if (!admin.isSplitOrMergeEnabled(MasterSwitchType.SPLIT)) { 228 admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.SPLIT); 229 } 230 if (!admin.isSplitOrMergeEnabled(MasterSwitchType.MERGE)) { 231 admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.MERGE); 232 } 233 assertTrue(admin.isSplitOrMergeEnabled(MasterSwitchType.SPLIT)); 234 assertTrue(admin.isSplitOrMergeEnabled(MasterSwitchType.MERGE)); 235 } 236}