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