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.junit.Assert.assertEquals; 023import static org.junit.Assert.assertFalse; 024import static org.junit.Assert.assertNotNull; 025import static org.junit.Assert.assertThat; 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.CatalogJanitor; 040import org.apache.hadoop.hbase.master.HMaster; 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 055 * ten 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 = AsyncMetaTableAccessor 164 .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 178 .getTableHRegionLocations(metaTable, tableName).get(); 179 180 assertEquals(2, regionLocations.size()); 181 for (HRegionLocation rl : regionLocations) { 182 if (regionC.compareTo(rl.getRegion()) != 0) { 183 mergedChildRegion = rl.getRegion(); 184 break; 185 } 186 } 187 188 assertNotNull(mergedChildRegion); 189 // Need to wait GC for merged child region is done. 190 HMaster services = TEST_UTIL.getHBaseCluster().getMaster(); 191 CatalogJanitor cj = services.getCatalogJanitor(); 192 cj.cleanMergeQualifier(mergedChildRegion); 193 // Wait until all procedures settled down 194 while (!services.getMasterProcedureExecutor().getActiveProcIds().isEmpty()) { 195 Thread.sleep(200); 196 } 197 // merge with encoded name 198 admin.mergeRegions(regionC.getRegionName(), mergedChildRegion.getRegionName(), 199 false).get(); 200 201 regionLocations = AsyncMetaTableAccessor 202 .getTableHRegionLocations(metaTable, tableName).get(); 203 assertEquals(1, regionLocations.size()); 204 } 205 206 @Test 207 public void testMergeRegionsInvalidRegionCount() throws Exception { 208 byte[][] splitRows = new byte[][] { Bytes.toBytes("3"), Bytes.toBytes("6") }; 209 createTableWithDefaultConf(tableName, splitRows); 210 List<RegionInfo> regions = admin.getRegions(tableName).join(); 211 // 0 212 try { 213 admin.mergeRegions(Collections.emptyList(), false).get(); 214 fail(); 215 } catch (ExecutionException e) { 216 // expected 217 assertThat(e.getCause(), instanceOf(IllegalArgumentException.class)); 218 } 219 // 1 220 try { 221 admin.mergeRegions(regions.stream().limit(1).map(RegionInfo::getEncodedNameAsBytes) 222 .collect(Collectors.toList()), false).get(); 223 fail(); 224 } catch (ExecutionException e) { 225 // expected 226 assertThat(e.getCause(), instanceOf(IllegalArgumentException.class)); 227 } 228 } 229 230 @Test 231 public void testSplitTable() throws Exception { 232 initSplitMergeSwitch(); 233 splitTest(TableName.valueOf("testSplitTable"), 3000, false, null); 234 splitTest(TableName.valueOf("testSplitTableWithSplitPoint"), 3000, false, Bytes.toBytes("3")); 235 splitTest(TableName.valueOf("testSplitTableRegion"), 3000, true, null); 236 splitTest(TableName.valueOf("testSplitTableRegionWithSplitPoint2"), 3000, true, Bytes.toBytes("3")); 237 } 238 239 private void 240 splitTest(TableName tableName, int rowCount, boolean isSplitRegion, byte[] splitPoint) 241 throws Exception { 242 // create table 243 createTableWithDefaultConf(tableName); 244 245 AsyncTable<AdvancedScanResultConsumer> metaTable = ASYNC_CONN.getTable(META_TABLE_NAME); 246 List<HRegionLocation> regionLocations = AsyncMetaTableAccessor 247 .getTableHRegionLocations(metaTable, tableName).get(); 248 assertEquals(1, regionLocations.size()); 249 250 AsyncTable<?> table = ASYNC_CONN.getTable(tableName); 251 List<Put> puts = new ArrayList<>(); 252 for (int i = 0; i < rowCount; i++) { 253 Put put = new Put(Bytes.toBytes(i)); 254 put.addColumn(FAMILY, null, Bytes.toBytes("value" + i)); 255 puts.add(put); 256 } 257 table.putAll(puts).join(); 258 259 if (isSplitRegion) { 260 if (splitPoint == null) { 261 admin.splitRegion(regionLocations.get(0).getRegion().getRegionName()).get(); 262 } else { 263 admin.splitRegion(regionLocations.get(0).getRegion().getRegionName(), splitPoint).get(); 264 } 265 } else { 266 if (splitPoint == null) { 267 admin.split(tableName).get(); 268 } else { 269 admin.split(tableName, splitPoint).get(); 270 } 271 } 272 273 int count = 0; 274 for (int i = 0; i < 45; i++) { 275 try { 276 regionLocations = AsyncMetaTableAccessor 277 .getTableHRegionLocations(metaTable, tableName).get(); 278 count = regionLocations.size(); 279 if (count >= 2) { 280 break; 281 } 282 Thread.sleep(1000L); 283 } catch (Exception e) { 284 LOG.error(e.toString(), e); 285 } 286 } 287 assertEquals(2, count); 288 } 289}