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