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.apache.hadoop.hbase.TableName.META_TABLE_NAME; 021import static org.hamcrest.CoreMatchers.instanceOf; 022import static org.hamcrest.MatcherAssert.assertThat; 023import static org.junit.Assert.assertEquals; 024import static org.junit.Assert.assertFalse; 025import static org.junit.Assert.assertNotNull; 026import static org.junit.Assert.assertTrue; 027import static org.junit.Assert.fail; 028 029import java.util.ArrayList; 030import java.util.Collections; 031import java.util.List; 032import java.util.concurrent.ExecutionException; 033import java.util.stream.Collectors; 034import org.apache.hadoop.hbase.AsyncMetaTableAccessor; 035import org.apache.hadoop.hbase.HBaseClassTestRule; 036import org.apache.hadoop.hbase.HConstants; 037import org.apache.hadoop.hbase.HRegionLocation; 038import org.apache.hadoop.hbase.TableName; 039import org.apache.hadoop.hbase.master.HMaster; 040import org.apache.hadoop.hbase.master.janitor.CatalogJanitor; 041import org.apache.hadoop.hbase.testclassification.ClientTests; 042import org.apache.hadoop.hbase.testclassification.LargeTests; 043import org.apache.hadoop.hbase.util.Bytes; 044import org.apache.hadoop.hbase.util.Threads; 045import org.junit.ClassRule; 046import org.junit.Ignore; 047import org.junit.Test; 048import org.junit.experimental.categories.Category; 049import org.junit.runner.RunWith; 050import org.junit.runners.Parameterized; 051 052/** 053 * Class to test asynchronous region admin operations. 054 * @see TestAsyncRegionAdminApi This test and it used to be joined it was taking longer than our ten 055 * minute timeout so they were split. 056 */ 057@RunWith(Parameterized.class) 058@Category({ LargeTests.class, ClientTests.class }) 059public class TestAsyncRegionAdminApi2 extends TestAsyncAdminBase { 060 061 @ClassRule 062 public static final HBaseClassTestRule CLASS_RULE = 063 HBaseClassTestRule.forClass(TestAsyncRegionAdminApi2.class); 064 065 @Test 066 public void testGetRegionLocation() throws Exception { 067 RawAsyncHBaseAdmin rawAdmin = (RawAsyncHBaseAdmin) ASYNC_CONN.getAdmin(); 068 TEST_UTIL.createMultiRegionTable(tableName, HConstants.CATALOG_FAMILY); 069 AsyncTableRegionLocator locator = ASYNC_CONN.getRegionLocator(tableName); 070 HRegionLocation regionLocation = locator.getRegionLocation(Bytes.toBytes("mmm")).get(); 071 RegionInfo region = regionLocation.getRegion(); 072 byte[] regionName = regionLocation.getRegion().getRegionName(); 073 HRegionLocation location = rawAdmin.getRegionLocation(regionName).get(); 074 assertTrue(Bytes.equals(regionName, location.getRegion().getRegionName())); 075 location = rawAdmin.getRegionLocation(region.getEncodedNameAsBytes()).get(); 076 assertTrue(Bytes.equals(regionName, location.getRegion().getRegionName())); 077 } 078 079 @Test 080 public void testSplitSwitch() throws Exception { 081 createTableWithDefaultConf(tableName); 082 byte[][] families = { FAMILY }; 083 final int rows = 10000; 084 TestAsyncRegionAdminApi.loadData(tableName, families, rows); 085 086 AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME); 087 List<HRegionLocation> regionLocations = 088 AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get(); 089 int originalCount = regionLocations.size(); 090 091 initSplitMergeSwitch(); 092 assertTrue(admin.splitSwitch(false).get()); 093 try { 094 admin.split(tableName, Bytes.toBytes(rows / 2)).join(); 095 } catch (Exception e) { 096 // Expected 097 } 098 int count = admin.getRegions(tableName).get().size(); 099 assertTrue(originalCount == count); 100 101 assertFalse(admin.splitSwitch(true).get()); 102 admin.split(tableName).join(); 103 while ((count = admin.getRegions(tableName).get().size()) == originalCount) { 104 Threads.sleep(100); 105 } 106 assertTrue(originalCount < count); 107 } 108 109 @Test 110 @Ignore 111 // It was ignored in TestSplitOrMergeStatus, too 112 public void testMergeSwitch() throws Exception { 113 createTableWithDefaultConf(tableName); 114 byte[][] families = { FAMILY }; 115 TestAsyncRegionAdminApi.loadData(tableName, families, 1000); 116 117 AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME); 118 List<HRegionLocation> regionLocations = 119 AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get(); 120 int originalCount = regionLocations.size(); 121 122 initSplitMergeSwitch(); 123 admin.split(tableName).join(); 124 int postSplitCount = originalCount; 125 while ((postSplitCount = admin.getRegions(tableName).get().size()) == originalCount) { 126 Threads.sleep(100); 127 } 128 assertTrue("originalCount=" + originalCount + ", postSplitCount=" + postSplitCount, 129 originalCount != postSplitCount); 130 131 // Merge switch is off so merge should NOT succeed. 132 assertTrue(admin.mergeSwitch(false).get()); 133 List<RegionInfo> regions = admin.getRegions(tableName).get(); 134 assertTrue(regions.size() > 1); 135 admin.mergeRegions(regions.get(0).getRegionName(), regions.get(1).getRegionName(), true).join(); 136 int count = admin.getRegions(tableName).get().size(); 137 assertTrue("postSplitCount=" + postSplitCount + ", count=" + count, postSplitCount == count); 138 139 // Merge switch is on so merge should succeed. 140 assertFalse(admin.mergeSwitch(true).get()); 141 admin.mergeRegions(regions.get(0).getRegionName(), regions.get(1).getRegionName(), true).join(); 142 count = admin.getRegions(tableName).get().size(); 143 assertTrue((postSplitCount / 2) == count); 144 } 145 146 private void initSplitMergeSwitch() throws Exception { 147 if (!admin.isSplitEnabled().get()) { 148 admin.splitSwitch(true).get(); 149 } 150 if (!admin.isMergeEnabled().get()) { 151 admin.mergeSwitch(true).get(); 152 } 153 assertTrue(admin.isSplitEnabled().get()); 154 assertTrue(admin.isMergeEnabled().get()); 155 } 156 157 @Test 158 public void testMergeRegions() throws Exception { 159 byte[][] splitRows = new byte[][] { Bytes.toBytes("3"), Bytes.toBytes("6") }; 160 createTableWithDefaultConf(tableName, splitRows); 161 162 AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME); 163 List<HRegionLocation> regionLocations = 164 AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get(); 165 RegionInfo regionA; 166 RegionInfo regionB; 167 RegionInfo regionC; 168 RegionInfo mergedChildRegion = null; 169 170 // merge with full name 171 assertEquals(3, regionLocations.size()); 172 regionA = regionLocations.get(0).getRegion(); 173 regionB = regionLocations.get(1).getRegion(); 174 regionC = regionLocations.get(2).getRegion(); 175 admin.mergeRegions(regionA.getRegionName(), regionB.getRegionName(), false).get(); 176 177 regionLocations = AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get(); 178 179 assertEquals(2, regionLocations.size()); 180 for (HRegionLocation rl : regionLocations) { 181 if (regionC.compareTo(rl.getRegion()) != 0) { 182 mergedChildRegion = rl.getRegion(); 183 break; 184 } 185 } 186 187 assertNotNull(mergedChildRegion); 188 // Need to wait GC for merged child region is done. 189 HMaster services = TEST_UTIL.getHBaseCluster().getMaster(); 190 CatalogJanitor cj = services.getCatalogJanitor(); 191 assertTrue(cj.scan() > 0); 192 // Wait until all procedures settled down 193 while (!services.getMasterProcedureExecutor().getActiveProcIds().isEmpty()) { 194 Thread.sleep(200); 195 } 196 // merge with encoded name 197 admin.mergeRegions(regionC.getRegionName(), mergedChildRegion.getRegionName(), false).get(); 198 199 regionLocations = AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get(); 200 assertEquals(1, regionLocations.size()); 201 } 202 203 @Test 204 public void testMergeRegionsInvalidRegionCount() throws Exception { 205 byte[][] splitRows = new byte[][] { Bytes.toBytes("3"), Bytes.toBytes("6") }; 206 createTableWithDefaultConf(tableName, splitRows); 207 List<RegionInfo> regions = admin.getRegions(tableName).join(); 208 // 0 209 try { 210 admin.mergeRegions(Collections.emptyList(), false).get(); 211 fail(); 212 } catch (ExecutionException e) { 213 // expected 214 assertThat(e.getCause(), instanceOf(IllegalArgumentException.class)); 215 } 216 // 1 217 try { 218 admin.mergeRegions(regions.stream().limit(1).map(RegionInfo::getEncodedNameAsBytes) 219 .collect(Collectors.toList()), false).get(); 220 fail(); 221 } catch (ExecutionException e) { 222 // expected 223 assertThat(e.getCause(), instanceOf(IllegalArgumentException.class)); 224 } 225 } 226 227 @Test 228 public void testSplitTable() throws Exception { 229 initSplitMergeSwitch(); 230 splitTest(TableName.valueOf("testSplitTable"), 3000, false, null); 231 splitTest(TableName.valueOf("testSplitTableWithSplitPoint"), 3000, false, Bytes.toBytes("3")); 232 splitTest(TableName.valueOf("testSplitTableRegion"), 3000, true, null); 233 splitTest(TableName.valueOf("testSplitTableRegionWithSplitPoint2"), 3000, true, 234 Bytes.toBytes("3")); 235 } 236 237 private void splitTest(TableName tableName, int rowCount, boolean isSplitRegion, 238 byte[] splitPoint) throws Exception { 239 // create table 240 createTableWithDefaultConf(tableName); 241 242 AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME); 243 List<HRegionLocation> regionLocations = 244 AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get(); 245 assertEquals(1, regionLocations.size()); 246 247 AsyncTable<?> table = ASYNC_CONN.getTable(tableName); 248 List<Put> puts = new ArrayList<>(); 249 for (int i = 0; i < rowCount; i++) { 250 Put put = new Put(Bytes.toBytes(i)); 251 put.addColumn(FAMILY, null, Bytes.toBytes("value" + i)); 252 puts.add(put); 253 } 254 table.putAll(puts).join(); 255 256 if (isSplitRegion) { 257 if (splitPoint == null) { 258 admin.splitRegion(regionLocations.get(0).getRegion().getRegionName()).get(); 259 } else { 260 admin.splitRegion(regionLocations.get(0).getRegion().getRegionName(), splitPoint).get(); 261 } 262 } else { 263 if (splitPoint == null) { 264 admin.split(tableName).get(); 265 } else { 266 admin.split(tableName, splitPoint).get(); 267 } 268 } 269 270 int count = 0; 271 for (int i = 0; i < 45; i++) { 272 try { 273 regionLocations = 274 AsyncMetaTableAccessor.getTableHRegionLocations(metaTable, tableName).get(); 275 count = regionLocations.size(); 276 if (count >= 2) { 277 break; 278 } 279 Thread.sleep(1000L); 280 } catch (Exception e) { 281 LOG.error(e.toString(), e); 282 } 283 } 284 assertEquals(2, count); 285 } 286}