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.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertNotNull; 023import static org.junit.jupiter.api.Assertions.assertThrows; 024import static org.junit.jupiter.api.Assertions.assertTrue; 025import static org.junit.jupiter.api.Assertions.fail; 026 027import java.io.IOException; 028import java.util.ArrayList; 029import java.util.List; 030import java.util.concurrent.ExecutionException; 031import java.util.concurrent.TimeUnit; 032import java.util.concurrent.atomic.AtomicInteger; 033import org.apache.hadoop.hbase.HConstants; 034import org.apache.hadoop.hbase.HRegionLocation; 035import org.apache.hadoop.hbase.MetaTableAccessor; 036import org.apache.hadoop.hbase.ServerName; 037import org.apache.hadoop.hbase.TableName; 038import org.apache.hadoop.hbase.TableNotFoundException; 039import org.apache.hadoop.hbase.exceptions.MergeRegionException; 040import org.apache.hadoop.hbase.master.HMaster; 041import org.apache.hadoop.hbase.master.janitor.CatalogJanitor; 042import org.apache.hadoop.hbase.regionserver.DisabledRegionSplitPolicy; 043import org.apache.hadoop.hbase.regionserver.HRegion; 044import org.apache.hadoop.hbase.regionserver.HStore; 045import org.apache.hadoop.hbase.regionserver.HStoreFile; 046import org.apache.hadoop.hbase.testclassification.ClientTests; 047import org.apache.hadoop.hbase.testclassification.LargeTests; 048import org.apache.hadoop.hbase.util.Bytes; 049import org.apache.hadoop.hbase.util.CommonFSUtils; 050import org.apache.hadoop.hbase.util.FutureUtils; 051import org.apache.hadoop.hbase.util.Pair; 052import org.apache.hadoop.hbase.util.Threads; 053import org.junit.jupiter.api.Tag; 054import org.junit.jupiter.api.Test; 055import org.slf4j.Logger; 056import org.slf4j.LoggerFactory; 057 058import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter; 059import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MergeTableRegionsRequest; 060 061/** 062 * Class to test HBaseAdmin. Spins up the minicluster once at test start and then takes it down 063 * afterward. Add any testing of HBaseAdmin functionality here. 064 */ 065@Tag(LargeTests.TAG) 066@Tag(ClientTests.TAG) 067public class TestAdmin1 extends TestAdminBase { 068 069 private static final Logger LOG = LoggerFactory.getLogger(TestAdmin1.class); 070 071 @Test 072 public void testSplitFlushCompactUnknownTable() throws InterruptedException { 073 final TableName unknowntable = TableName.valueOf(methodName); 074 Exception exception = null; 075 try { 076 ADMIN.compact(unknowntable); 077 } catch (IOException e) { 078 exception = e; 079 } 080 assertTrue(exception instanceof TableNotFoundException); 081 082 exception = null; 083 try { 084 ADMIN.flush(unknowntable); 085 } catch (IOException e) { 086 exception = e; 087 } 088 assertTrue(exception instanceof TableNotFoundException); 089 090 exception = null; 091 try { 092 ADMIN.split(unknowntable); 093 } catch (IOException e) { 094 exception = e; 095 } 096 assertTrue(exception instanceof TableNotFoundException); 097 } 098 099 @Test 100 public void testCompactATableWithSuperLongTableName() throws Exception { 101 TableName tableName = TableName.valueOf(methodName); 102 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 103 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("fam1")).build(); 104 try { 105 ADMIN.createTable(htd); 106 assertThrows(IllegalArgumentException.class, 107 () -> ADMIN.majorCompactRegion(tableName.getName())); 108 109 assertThrows(IllegalArgumentException.class, 110 () -> ADMIN.majorCompactRegion(Bytes.toBytes("abcd"))); 111 } finally { 112 ADMIN.disableTable(tableName); 113 ADMIN.deleteTable(tableName); 114 } 115 } 116 117 @Test 118 public void testCompactionTimestamps() throws Exception { 119 TableName tableName = TableName.valueOf(methodName); 120 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 121 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("fam1")).build(); 122 ADMIN.createTable(htd); 123 Table table = TEST_UTIL.getConnection().getTable(htd.getTableName()); 124 long ts = ADMIN.getLastMajorCompactionTimestamp(tableName); 125 assertEquals(0, ts); 126 Put p = new Put(Bytes.toBytes("row1")); 127 p.addColumn(Bytes.toBytes("fam1"), Bytes.toBytes("fam1"), Bytes.toBytes("fam1")); 128 table.put(p); 129 ts = ADMIN.getLastMajorCompactionTimestamp(tableName); 130 // no files written -> no data 131 assertEquals(0, ts); 132 133 ADMIN.flush(tableName); 134 ts = ADMIN.getLastMajorCompactionTimestamp(tableName); 135 // still 0, we flushed a file, but no major compaction happened 136 assertEquals(0, ts); 137 138 byte[] regionName; 139 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 140 regionName = l.getAllRegionLocations().get(0).getRegion().getRegionName(); 141 } 142 long ts1 = ADMIN.getLastMajorCompactionTimestampForRegion(regionName); 143 assertEquals(ts, ts1); 144 p = new Put(Bytes.toBytes("row2")); 145 p.addColumn(Bytes.toBytes("fam1"), Bytes.toBytes("fam1"), Bytes.toBytes("fam1")); 146 table.put(p); 147 ADMIN.flush(tableName); 148 ts = ADMIN.getLastMajorCompactionTimestamp(tableName); 149 // make sure the region API returns the same value, as the old file is still around 150 assertEquals(ts1, ts); 151 152 TEST_UTIL.compact(tableName, true); 153 table.put(p); 154 // forces a wait for the compaction 155 ADMIN.flush(tableName); 156 ts = ADMIN.getLastMajorCompactionTimestamp(tableName); 157 // after a compaction our earliest timestamp will have progressed forward 158 assertTrue(ts > ts1); 159 160 // region api still the same 161 ts1 = ADMIN.getLastMajorCompactionTimestampForRegion(regionName); 162 assertEquals(ts, ts1); 163 table.put(p); 164 ADMIN.flush(tableName); 165 ts = ADMIN.getLastMajorCompactionTimestamp(tableName); 166 assertEquals(ts, ts1); 167 table.close(); 168 } 169 170 @Test 171 public void testColumnValidName() { 172 assertThrows(IllegalArgumentException.class, 173 () -> ColumnFamilyDescriptorBuilder.of("\\test\\abc")); 174 } 175 176 @Test 177 public void testTableExist() throws IOException { 178 final TableName table = TableName.valueOf(methodName); 179 boolean exist; 180 exist = ADMIN.tableExists(table); 181 assertEquals(false, exist); 182 TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY); 183 exist = ADMIN.tableExists(table); 184 assertEquals(true, exist); 185 } 186 187 /** 188 * Tests forcing split from client and having scanners successfully ride over split. 189 */ 190 @Test 191 public void testForceSplit() throws Exception { 192 byte[][] familyNames = new byte[][] { Bytes.toBytes("cf") }; 193 int[] rowCounts = new int[] { 6000 }; 194 int numVersions = ColumnFamilyDescriptorBuilder.DEFAULT_MAX_VERSIONS; 195 int blockSize = 256; 196 splitTest(null, familyNames, rowCounts, numVersions, blockSize, true); 197 198 byte[] splitKey = Bytes.toBytes(3500); 199 splitTest(splitKey, familyNames, rowCounts, numVersions, blockSize, true); 200 // test regionSplitSync 201 splitTest(splitKey, familyNames, rowCounts, numVersions, blockSize, false); 202 } 203 204 /** 205 * Multi-family scenario. Tests forcing split from client and having scanners successfully ride 206 * over split. 207 */ 208 @Test 209 public void testForceSplitMultiFamily() throws Exception { 210 int numVersions = ColumnFamilyDescriptorBuilder.DEFAULT_MAX_VERSIONS; 211 212 // use small HFile block size so that we can have lots of blocks in HFile 213 // Otherwise, if there is only one block, 214 // HFileBlockIndex.midKey()'s value == startKey 215 int blockSize = 256; 216 byte[][] familyNames = new byte[][] { Bytes.toBytes("cf1"), Bytes.toBytes("cf2") }; 217 218 // one of the column families isn't splittable 219 int[] rowCounts = new int[] { 6000, 1 }; 220 splitTest(null, familyNames, rowCounts, numVersions, blockSize, true); 221 222 rowCounts = new int[] { 1, 6000 }; 223 splitTest(null, familyNames, rowCounts, numVersions, blockSize, true); 224 225 // one column family has much smaller data than the other 226 // the split key should be based on the largest column family 227 rowCounts = new int[] { 6000, 300 }; 228 splitTest(null, familyNames, rowCounts, numVersions, blockSize, true); 229 230 rowCounts = new int[] { 300, 6000 }; 231 splitTest(null, familyNames, rowCounts, numVersions, blockSize, true); 232 } 233 234 private int count(ResultScanner scanner) throws IOException { 235 int rows = 0; 236 while (scanner.next() != null) { 237 rows++; 238 } 239 return rows; 240 } 241 242 private void splitTest(byte[] splitPoint, byte[][] familyNames, int[] rowCounts, int numVersions, 243 int blockSize, boolean async) throws Exception { 244 TableName tableName = TableName.valueOf("testForceSplit"); 245 StringBuilder sb = new StringBuilder(); 246 // Add tail to String so can see better in logs where a test is running. 247 for (int i = 0; i < rowCounts.length; i++) { 248 sb.append("_").append(Integer.toString(rowCounts[i])); 249 } 250 assertFalse(ADMIN.tableExists(tableName)); 251 try (final Table table = TEST_UTIL.createTable(tableName, familyNames, numVersions, blockSize); 252 final RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 253 254 int rowCount = 0; 255 byte[] q = new byte[0]; 256 257 // insert rows into column families. The number of rows that have values 258 // in a specific column family is decided by rowCounts[familyIndex] 259 for (int index = 0; index < familyNames.length; index++) { 260 ArrayList<Put> puts = new ArrayList<>(rowCounts[index]); 261 for (int i = 0; i < rowCounts[index]; i++) { 262 byte[] k = Bytes.toBytes(i); 263 Put put = new Put(k); 264 put.addColumn(familyNames[index], q, k); 265 puts.add(put); 266 } 267 table.put(puts); 268 269 if (rowCount < rowCounts[index]) { 270 rowCount = rowCounts[index]; 271 } 272 } 273 274 // get the initial layout (should just be one region) 275 List<HRegionLocation> m = locator.getAllRegionLocations(); 276 LOG.info("Initial regions (" + m.size() + "): " + m); 277 assertTrue(m.size() == 1); 278 279 // Verify row count 280 Scan scan = new Scan(); 281 int rows; 282 try (ResultScanner scanner = table.getScanner(scan)) { 283 rows = count(scanner); 284 } 285 assertEquals(rowCount, rows); 286 287 // Have an outstanding scan going on to make sure we can scan over splits. 288 scan = new Scan(); 289 try (ResultScanner scanner = table.getScanner(scan)) { 290 // Scan first row so we are into first region before split happens. 291 scanner.next(); 292 293 // Split the table 294 if (async) { 295 if (splitPoint != null) { 296 ADMIN.split(tableName, splitPoint); 297 } else { 298 ADMIN.split(tableName); 299 } 300 final AtomicInteger count = new AtomicInteger(0); 301 Thread t = new Thread("CheckForSplit") { 302 @Override 303 public void run() { 304 for (int i = 0; i < 45; i++) { 305 try { 306 sleep(1000); 307 } catch (InterruptedException e) { 308 continue; 309 } 310 // check again 311 List<HRegionLocation> regions = null; 312 try { 313 regions = locator.getAllRegionLocations(); 314 } catch (IOException e) { 315 LOG.warn("get location failed", e); 316 } 317 if (regions == null) { 318 continue; 319 } 320 count.set(regions.size()); 321 if (count.get() >= 2) { 322 LOG.info("Found: " + regions); 323 break; 324 } 325 LOG.debug("Cycle waiting on split"); 326 } 327 LOG.debug("CheckForSplit thread exited, current region count: " + count.get()); 328 } 329 }; 330 t.setPriority(Thread.NORM_PRIORITY - 2); 331 t.start(); 332 t.join(); 333 } else { 334 // Sync split region, no need to create a thread to check 335 ADMIN.splitRegionAsync(m.get(0).getRegion().getRegionName(), splitPoint).get(); 336 } 337 // Verify row count 338 rows = 1 + count(scanner); // We counted one row above. 339 } 340 assertEquals(rowCount, rows); 341 342 List<HRegionLocation> regions = null; 343 try { 344 regions = locator.getAllRegionLocations(); 345 } catch (IOException e) { 346 e.printStackTrace(); 347 } 348 assertEquals(2, regions.size()); 349 if (splitPoint != null) { 350 // make sure the split point matches our explicit configuration 351 assertEquals(Bytes.toString(splitPoint), 352 Bytes.toString(regions.get(0).getRegion().getEndKey())); 353 assertEquals(Bytes.toString(splitPoint), 354 Bytes.toString(regions.get(1).getRegion().getStartKey())); 355 LOG.debug("Properly split on " + Bytes.toString(splitPoint)); 356 } else { 357 if (familyNames.length > 1) { 358 int splitKey = Bytes.toInt(regions.get(0).getRegion().getEndKey()); 359 // check if splitKey is based on the largest column family 360 // in terms of it store size 361 int deltaForLargestFamily = Math.abs(rowCount / 2 - splitKey); 362 LOG.debug("SplitKey=" + splitKey + "&deltaForLargestFamily=" + deltaForLargestFamily 363 + ", r=" + regions.get(0).getRegion()); 364 for (int index = 0; index < familyNames.length; index++) { 365 int delta = Math.abs(rowCounts[index] / 2 - splitKey); 366 if (delta < deltaForLargestFamily) { 367 assertTrue(false, "Delta " + delta + " for family " + index + " should be at least " 368 + "deltaForLargestFamily " + deltaForLargestFamily); 369 } 370 } 371 } 372 } 373 TEST_UTIL.deleteTable(tableName); 374 } 375 } 376 377 @Test 378 public void testSplitAndMergeWithReplicaTable() throws Exception { 379 // The test tries to directly split replica regions and directly merge replica regions. These 380 // are not allowed. The test validates that. Then the test does a valid split/merge of allowed 381 // regions. 382 // Set up a table with 3 regions and replication set to 3 383 TableName tableName = TableName.valueOf(methodName); 384 byte[] cf = Bytes.toBytes("f"); 385 TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName).setRegionReplication(3) 386 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf)).build(); 387 byte[][] splitRows = new byte[2][]; 388 splitRows[0] = new byte[] { (byte) '4' }; 389 splitRows[1] = new byte[] { (byte) '7' }; 390 TEST_UTIL.getAdmin().createTable(desc, splitRows); 391 List<HRegion> oldRegions; 392 do { 393 oldRegions = TEST_UTIL.getHBaseCluster().getRegions(tableName); 394 Thread.sleep(10); 395 } while (oldRegions.size() != 9); // 3 regions * 3 replicas 396 // write some data to the table 397 Table ht = TEST_UTIL.getConnection().getTable(tableName); 398 List<Put> puts = new ArrayList<>(); 399 byte[] qualifier = Bytes.toBytes("c"); 400 Put put = new Put(new byte[] { (byte) '1' }); 401 put.addColumn(cf, qualifier, Bytes.toBytes("100")); 402 puts.add(put); 403 put = new Put(new byte[] { (byte) '6' }); 404 put.addColumn(cf, qualifier, Bytes.toBytes("100")); 405 puts.add(put); 406 put = new Put(new byte[] { (byte) '8' }); 407 put.addColumn(cf, qualifier, Bytes.toBytes("100")); 408 puts.add(put); 409 ht.put(puts); 410 ht.close(); 411 List<Pair<RegionInfo, ServerName>> regions = 412 MetaTableAccessor.getTableRegionsAndLocations(TEST_UTIL.getConnection(), tableName); 413 boolean gotException = false; 414 // the element at index 1 would be a replica (since the metareader gives us ordered 415 // regions). Try splitting that region via the split API . Should fail 416 try { 417 FutureUtils 418 .get(TEST_UTIL.getAdmin().splitRegionAsync(regions.get(1).getFirst().getRegionName())); 419 } catch (IllegalArgumentException ex) { 420 gotException = true; 421 } 422 assertTrue(gotException); 423 gotException = false; 424 // the element at index 1 would be a replica (since the metareader gives us ordered 425 // regions). Try splitting that region via a different split API (the difference is 426 // this API goes direct to the regionserver skipping any checks in the admin). Should fail 427 try { 428 FutureUtils.get(TEST_UTIL.getAdmin().splitRegionAsync( 429 regions.get(1).getFirst().getEncodedNameAsBytes(), new byte[] { (byte) '1' })); 430 } catch (IllegalArgumentException ex) { 431 gotException = true; 432 } 433 assertTrue(gotException); 434 435 gotException = false; 436 // testing Sync split operation 437 try { 438 FutureUtils.get(TEST_UTIL.getAdmin() 439 .splitRegionAsync(regions.get(1).getFirst().getRegionName(), new byte[] { (byte) '1' })); 440 } catch (IllegalArgumentException ex) { 441 gotException = true; 442 } 443 assertTrue(gotException); 444 445 gotException = false; 446 // Try merging a replica with another. Should fail. 447 try { 448 FutureUtils.get( 449 TEST_UTIL.getAdmin().mergeRegionsAsync(regions.get(1).getFirst().getEncodedNameAsBytes(), 450 regions.get(2).getFirst().getEncodedNameAsBytes(), true)); 451 } catch (IllegalArgumentException m) { 452 gotException = true; 453 } 454 assertTrue(gotException); 455 // Try going to the master directly (that will skip the check in admin) 456 try { 457 byte[][] nameofRegionsToMerge = new byte[2][]; 458 nameofRegionsToMerge[0] = regions.get(1).getFirst().getEncodedNameAsBytes(); 459 nameofRegionsToMerge[1] = regions.get(2).getFirst().getEncodedNameAsBytes(); 460 MergeTableRegionsRequest request = RequestConverter.buildMergeTableRegionsRequest( 461 nameofRegionsToMerge, true, HConstants.NO_NONCE, HConstants.NO_NONCE); 462 TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterRpcServices().mergeTableRegions(null, 463 request); 464 } catch (org.apache.hbase.thirdparty.com.google.protobuf.ServiceException m) { 465 Throwable t = m.getCause(); 466 do { 467 if (t instanceof MergeRegionException) { 468 gotException = true; 469 break; 470 } 471 t = t.getCause(); 472 } while (t != null); 473 } 474 assertTrue(gotException); 475 } 476 477 @Test 478 public void testInvalidColumnDescriptor() { 479 assertThrows(IllegalArgumentException.class, 480 () -> ColumnFamilyDescriptorBuilder.of("/cfamily/name")); 481 } 482 483 /** 484 * Test DFS replication for column families, where one CF has default replication(3) and the other 485 * is set to 1. 486 */ 487 @Test 488 public void testHFileReplication() throws Exception { 489 final TableName tableName = TableName.valueOf(methodName); 490 String fn1 = "rep1"; 491 String fn = "defaultRep"; 492 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 493 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(fn)) 494 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(fn1)) 495 .setDFSReplication((short) 1).build()) 496 .build(); 497 Table table = TEST_UTIL.createTable(htd, null); 498 TEST_UTIL.waitTableAvailable(tableName); 499 Put p = new Put(Bytes.toBytes("defaultRep_rk")); 500 byte[] q1 = Bytes.toBytes("q1"); 501 byte[] v1 = Bytes.toBytes("v1"); 502 p.addColumn(Bytes.toBytes(fn), q1, v1); 503 List<Put> puts = new ArrayList<>(2); 504 puts.add(p); 505 p = new Put(Bytes.toBytes("rep1_rk")); 506 p.addColumn(Bytes.toBytes(fn1), q1, v1); 507 puts.add(p); 508 try { 509 table.put(puts); 510 ADMIN.flush(tableName); 511 512 List<HRegion> regions = TEST_UTIL.getMiniHBaseCluster().getRegions(tableName); 513 for (HRegion r : regions) { 514 HStore store = r.getStore(Bytes.toBytes(fn)); 515 for (HStoreFile sf : store.getStorefiles()) { 516 assertTrue(sf.toString().contains(fn)); 517 assertTrue( 518 CommonFSUtils.getDefaultReplication(TEST_UTIL.getTestFileSystem(), sf.getPath()) 519 == (sf.getFileInfo().getFileStatus().getReplication()), 520 "Column family " + fn + " should have 3 copies"); 521 } 522 523 store = r.getStore(Bytes.toBytes(fn1)); 524 for (HStoreFile sf : store.getStorefiles()) { 525 assertTrue(sf.toString().contains(fn1)); 526 assertTrue(1 == sf.getFileInfo().getFileStatus().getReplication(), 527 "Column family " + fn1 + " should have only 1 copy"); 528 } 529 } 530 } finally { 531 if (ADMIN.isTableEnabled(tableName)) { 532 ADMIN.disableTable(tableName); 533 ADMIN.deleteTable(tableName); 534 } 535 } 536 } 537 538 @Test 539 public void testMergeRegions() throws Exception { 540 final TableName tableName = TableName.valueOf(methodName); 541 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName) 542 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("d")).build(); 543 byte[][] splitRows = new byte[2][]; 544 splitRows[0] = new byte[] { (byte) '3' }; 545 splitRows[1] = new byte[] { (byte) '6' }; 546 try { 547 TEST_UTIL.createTable(td, splitRows); 548 TEST_UTIL.waitTableAvailable(tableName); 549 550 List<RegionInfo> tableRegions; 551 RegionInfo regionA; 552 RegionInfo regionB; 553 RegionInfo regionC; 554 RegionInfo mergedChildRegion = null; 555 556 // merge with full name 557 tableRegions = ADMIN.getRegions(tableName); 558 assertEquals(3, ADMIN.getRegions(tableName).size()); 559 regionA = tableRegions.get(0); 560 regionB = tableRegions.get(1); 561 regionC = tableRegions.get(2); 562 // TODO convert this to version that is synchronous (See HBASE-16668) 563 ADMIN.mergeRegionsAsync(regionA.getRegionName(), regionB.getRegionName(), false).get(60, 564 TimeUnit.SECONDS); 565 566 tableRegions = ADMIN.getRegions(tableName); 567 568 assertEquals(2, tableRegions.size()); 569 for (RegionInfo ri : tableRegions) { 570 if (regionC.compareTo(ri) != 0) { 571 mergedChildRegion = ri; 572 break; 573 } 574 } 575 576 assertNotNull(mergedChildRegion); 577 // Need to wait GC for merged child region is done. 578 HMaster services = TEST_UTIL.getHBaseCluster().getMaster(); 579 CatalogJanitor cj = services.getCatalogJanitor(); 580 assertTrue(cj.scan() > 0); 581 // Wait until all procedures settled down 582 while (!services.getMasterProcedureExecutor().getActiveProcIds().isEmpty()) { 583 Thread.sleep(200); 584 } 585 586 // TODO convert this to version that is synchronous (See HBASE-16668) 587 ADMIN.mergeRegionsAsync(regionC.getEncodedNameAsBytes(), 588 mergedChildRegion.getEncodedNameAsBytes(), false).get(60, TimeUnit.SECONDS); 589 590 assertEquals(1, ADMIN.getRegions(tableName).size()); 591 } finally { 592 ADMIN.disableTable(tableName); 593 ADMIN.deleteTable(tableName); 594 } 595 } 596 597 @Test 598 public void testMergeRegionsInvalidRegionCount() 599 throws IOException, InterruptedException, ExecutionException { 600 TableName tableName = TableName.valueOf(methodName); 601 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName) 602 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("d")).build(); 603 byte[][] splitRows = new byte[2][]; 604 splitRows[0] = new byte[] { (byte) '3' }; 605 splitRows[1] = new byte[] { (byte) '6' }; 606 try { 607 TEST_UTIL.createTable(td, splitRows); 608 TEST_UTIL.waitTableAvailable(tableName); 609 610 List<RegionInfo> tableRegions = ADMIN.getRegions(tableName); 611 // 0 612 try { 613 FutureUtils.get(ADMIN.mergeRegionsAsync(new byte[0][0], false)); 614 fail(); 615 } catch (IllegalArgumentException e) { 616 // expected 617 } 618 // 1 619 try { 620 FutureUtils.get(ADMIN 621 .mergeRegionsAsync(new byte[][] { tableRegions.get(0).getEncodedNameAsBytes() }, false)); 622 fail(); 623 } catch (IllegalArgumentException e) { 624 // expected 625 } 626 } finally { 627 ADMIN.disableTable(tableName); 628 ADMIN.deleteTable(tableName); 629 } 630 } 631 632 @Test 633 public void testSplitShouldNotHappenIfSplitIsDisabledForTable() throws Exception { 634 final TableName tableName = TableName.valueOf(methodName); 635 TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) 636 .setRegionSplitPolicyClassName(DisabledRegionSplitPolicy.class.getName()) 637 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f")).build(); 638 Table table = TEST_UTIL.createTable(htd, null); 639 for (int i = 0; i < 10; i++) { 640 Put p = new Put(Bytes.toBytes("row" + i)); 641 byte[] q1 = Bytes.toBytes("q1"); 642 byte[] v1 = Bytes.toBytes("v1"); 643 p.addColumn(Bytes.toBytes("f"), q1, v1); 644 table.put(p); 645 } 646 ADMIN.flush(tableName); 647 try { 648 ADMIN.split(tableName, Bytes.toBytes("row5")); 649 Threads.sleep(10000); 650 } catch (Exception e) { 651 // Nothing to do. 652 } 653 // Split should not happen. 654 List<RegionInfo> allRegions = 655 MetaTableAccessor.getTableRegions(ADMIN.getConnection(), tableName, true); 656 assertEquals(1, allRegions.size()); 657 } 658}