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