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.ArrayList; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.EnumSet; 030import java.util.HashMap; 031import java.util.HashSet; 032import java.util.List; 033import java.util.Random; 034import java.util.concurrent.atomic.AtomicInteger; 035import java.util.stream.Collectors; 036import org.apache.hadoop.conf.Configuration; 037import org.apache.hadoop.hbase.ClusterMetrics.Option; 038import org.apache.hadoop.hbase.HBaseClassTestRule; 039import org.apache.hadoop.hbase.HColumnDescriptor; 040import org.apache.hadoop.hbase.HConstants; 041import org.apache.hadoop.hbase.HRegionLocation; 042import org.apache.hadoop.hbase.HTableDescriptor; 043import org.apache.hadoop.hbase.MiniHBaseCluster; 044import org.apache.hadoop.hbase.ServerName; 045import org.apache.hadoop.hbase.TableExistsException; 046import org.apache.hadoop.hbase.TableName; 047import org.apache.hadoop.hbase.TableNotDisabledException; 048import org.apache.hadoop.hbase.TableNotEnabledException; 049import org.apache.hadoop.hbase.TableNotFoundException; 050import org.apache.hadoop.hbase.UnknownRegionException; 051import org.apache.hadoop.hbase.Waiter.Predicate; 052import org.apache.hadoop.hbase.ZooKeeperConnectionException; 053import org.apache.hadoop.hbase.constraint.ConstraintException; 054import org.apache.hadoop.hbase.ipc.HBaseRpcController; 055import org.apache.hadoop.hbase.master.HMaster; 056import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 057import org.apache.hadoop.hbase.regionserver.HRegion; 058import org.apache.hadoop.hbase.regionserver.HRegionServer; 059import org.apache.hadoop.hbase.regionserver.HStore; 060import org.apache.hadoop.hbase.testclassification.ClientTests; 061import org.apache.hadoop.hbase.testclassification.LargeTests; 062import org.apache.hadoop.hbase.util.Bytes; 063import org.apache.hadoop.hbase.util.Pair; 064import org.apache.hadoop.hbase.wal.AbstractFSWALProvider; 065import org.junit.Assert; 066import org.junit.ClassRule; 067import org.junit.Test; 068import org.junit.experimental.categories.Category; 069import org.slf4j.Logger; 070import org.slf4j.LoggerFactory; 071 072import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 073 074/** 075 * Class to test HBaseAdmin. 076 * Spins up the minicluster once at test start and then takes it down afterward. 077 * Add any testing of HBaseAdmin functionality here. 078 */ 079@Category({LargeTests.class, ClientTests.class}) 080public class TestAdmin2 extends TestAdminBase { 081 082 @ClassRule 083 public static final HBaseClassTestRule CLASS_RULE = 084 HBaseClassTestRule.forClass(TestAdmin2.class); 085 086 private static final Logger LOG = LoggerFactory.getLogger(TestAdmin2.class); 087 088 @Test 089 public void testCreateBadTables() throws IOException { 090 String msg = null; 091 try { 092 ADMIN.createTable(new HTableDescriptor(TableName.META_TABLE_NAME)); 093 } catch(TableExistsException e) { 094 msg = e.toString(); 095 } 096 assertTrue("Unexcepted exception message " + msg, msg != null && 097 msg.startsWith(TableExistsException.class.getName()) && 098 msg.contains(TableName.META_TABLE_NAME.getNameAsString())); 099 100 // Now try and do concurrent creation with a bunch of threads. 101 final HTableDescriptor threadDesc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 102 threadDesc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); 103 int count = 10; 104 Thread [] threads = new Thread [count]; 105 final AtomicInteger successes = new AtomicInteger(0); 106 final AtomicInteger failures = new AtomicInteger(0); 107 final Admin localAdmin = ADMIN; 108 for (int i = 0; i < count; i++) { 109 threads[i] = new Thread(Integer.toString(i)) { 110 @Override 111 public void run() { 112 try { 113 localAdmin.createTable(threadDesc); 114 successes.incrementAndGet(); 115 } catch (TableExistsException e) { 116 failures.incrementAndGet(); 117 } catch (IOException e) { 118 throw new RuntimeException("Failed threaded create" + getName(), e); 119 } 120 } 121 }; 122 } 123 for (int i = 0; i < count; i++) { 124 threads[i].start(); 125 } 126 for (int i = 0; i < count; i++) { 127 while(threads[i].isAlive()) { 128 try { 129 Thread.sleep(100); 130 } catch (InterruptedException e) { 131 // continue 132 } 133 } 134 } 135 // All threads are now dead. Count up how many tables were created and 136 // how many failed w/ appropriate exception. 137 assertEquals(1, successes.get()); 138 assertEquals(count - 1, failures.get()); 139 } 140 141 /** 142 * Test for hadoop-1581 'HBASE: Unopenable tablename bug'. 143 * @throws Exception 144 */ 145 @Test 146 public void testTableNameClash() throws Exception { 147 final String name = this.name.getMethodName(); 148 HTableDescriptor htd1 = new HTableDescriptor(TableName.valueOf(name + "SOMEUPPERCASE")); 149 HTableDescriptor htd2 = new HTableDescriptor(TableName.valueOf(name)); 150 htd1.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); 151 htd2.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); 152 ADMIN.createTable(htd1); 153 ADMIN.createTable(htd2); 154 // Before fix, below would fail throwing a NoServerForRegionException. 155 TEST_UTIL.getConnection().getTable(htd2.getTableName()).close(); 156 } 157 158 /*** 159 * HMaster.createTable used to be kind of synchronous call 160 * Thus creating of table with lots of regions can cause RPC timeout 161 * After the fix to make createTable truly async, RPC timeout shouldn't be an 162 * issue anymore 163 * @throws Exception 164 */ 165 @Test 166 public void testCreateTableRPCTimeOut() throws Exception { 167 final String name = this.name.getMethodName(); 168 int oldTimeout = TEST_UTIL.getConfiguration(). 169 getInt(HConstants.HBASE_RPC_TIMEOUT_KEY, HConstants.DEFAULT_HBASE_RPC_TIMEOUT); 170 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, 1500); 171 try { 172 int expectedRegions = 100; 173 // Use 80 bit numbers to make sure we aren't limited 174 byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 175 byte [] endKey = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; 176 Admin hbaseadmin = TEST_UTIL.getHBaseAdmin(); 177 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name)); 178 htd.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); 179 hbaseadmin.createTable(htd, startKey, endKey, expectedRegions); 180 } finally { 181 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, oldTimeout); 182 } 183 } 184 185 /** 186 * Test read only tables 187 * @throws Exception 188 */ 189 @Test 190 public void testReadOnlyTable() throws Exception { 191 final TableName name = TableName.valueOf(this.name.getMethodName()); 192 Table table = TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY); 193 byte[] value = Bytes.toBytes("somedata"); 194 // This used to use an empty row... That must have been a bug 195 Put put = new Put(value); 196 put.addColumn(HConstants.CATALOG_FAMILY, HConstants.CATALOG_FAMILY, value); 197 table.put(put); 198 table.close(); 199 } 200 201 /** 202 * Test that user table names can contain '-' and '.' so long as they do not 203 * start with same. HBASE-771 204 * @throws IOException 205 */ 206 @Test 207 public void testTableNames() throws IOException { 208 byte[][] illegalNames = new byte[][] { 209 Bytes.toBytes("-bad"), 210 Bytes.toBytes(".bad") 211 }; 212 for (byte[] illegalName : illegalNames) { 213 try { 214 new HTableDescriptor(TableName.valueOf(illegalName)); 215 throw new IOException("Did not detect '" + 216 Bytes.toString(illegalName) + "' as an illegal user table name"); 217 } catch (IllegalArgumentException e) { 218 // expected 219 } 220 } 221 byte[] legalName = Bytes.toBytes("g-oo.d"); 222 try { 223 new HTableDescriptor(TableName.valueOf(legalName)); 224 } catch (IllegalArgumentException e) { 225 throw new IOException("Legal user table name: '" + 226 Bytes.toString(legalName) + "' caused IllegalArgumentException: " + 227 e.getMessage()); 228 } 229 } 230 231 /** 232 * For HADOOP-2579 233 * @throws IOException 234 */ 235 @Test (expected=TableExistsException.class) 236 public void testTableExistsExceptionWithATable() throws IOException { 237 final TableName name = TableName.valueOf(this.name.getMethodName()); 238 TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY).close(); 239 TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY); 240 } 241 242 /** 243 * Can't disable a table if the table isn't in enabled state 244 * @throws IOException 245 */ 246 @Test (expected=TableNotEnabledException.class) 247 public void testTableNotEnabledExceptionWithATable() throws IOException { 248 final TableName name = TableName.valueOf(this.name.getMethodName()); 249 TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY).close(); 250 ADMIN.disableTable(name); 251 ADMIN.disableTable(name); 252 } 253 254 /** 255 * Can't enable a table if the table isn't in disabled state 256 */ 257 @Test(expected = TableNotDisabledException.class) 258 public void testTableNotDisabledExceptionWithATable() throws IOException { 259 final TableName name = TableName.valueOf(this.name.getMethodName()); 260 Table t = TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY); 261 try { 262 ADMIN.enableTable(name); 263 } finally { 264 t.close(); 265 } 266 } 267 268 /** 269 * For HADOOP-2579 270 */ 271 @Test(expected = TableNotFoundException.class) 272 public void testTableNotFoundExceptionWithoutAnyTables() throws IOException { 273 TableName tableName = TableName.valueOf("testTableNotFoundExceptionWithoutAnyTables"); 274 Table ht = TEST_UTIL.getConnection().getTable(tableName); 275 ht.get(new Get(Bytes.toBytes("e"))); 276 } 277 278 @Test 279 public void testShouldUnassignTheRegion() throws Exception { 280 final TableName tableName = TableName.valueOf(name.getMethodName()); 281 createTableWithDefaultConf(tableName); 282 283 RegionInfo info = null; 284 HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(tableName); 285 List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices()); 286 for (RegionInfo regionInfo : onlineRegions) { 287 if (!regionInfo.getTable().isSystemTable()) { 288 info = regionInfo; 289 ADMIN.unassign(regionInfo.getRegionName(), true); 290 } 291 } 292 boolean isInList = ProtobufUtil.getOnlineRegions( 293 rs.getRSRpcServices()).contains(info); 294 long timeout = System.currentTimeMillis() + 10000; 295 while ((System.currentTimeMillis() < timeout) && (isInList)) { 296 Thread.sleep(100); 297 isInList = ProtobufUtil.getOnlineRegions( 298 rs.getRSRpcServices()).contains(info); 299 } 300 301 assertFalse("The region should not be present in online regions list.", 302 isInList); 303 } 304 305 @Test 306 public void testCloseRegionIfInvalidRegionNameIsPassed() throws Exception { 307 final String name = this.name.getMethodName(); 308 byte[] tableName = Bytes.toBytes(name); 309 createTableWithDefaultConf(tableName); 310 311 RegionInfo info = null; 312 HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TableName.valueOf(tableName)); 313 List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices()); 314 for (RegionInfo regionInfo : onlineRegions) { 315 if (!regionInfo.isMetaRegion()) { 316 if (regionInfo.getRegionNameAsString().contains(name)) { 317 info = regionInfo; 318 try { 319 ADMIN.unassign(Bytes.toBytes("sample"), true); 320 } catch (UnknownRegionException nsre) { 321 // expected, ignore it 322 } 323 } 324 } 325 } 326 onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices()); 327 assertTrue("The region should be present in online regions list.", 328 onlineRegions.contains(info)); 329 } 330 331 @Test 332 public void testCloseRegionThatFetchesTheHRIFromMeta() throws Exception { 333 final TableName tableName = TableName.valueOf(name.getMethodName()); 334 createTableWithDefaultConf(tableName); 335 336 RegionInfo info = null; 337 HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(tableName); 338 List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices()); 339 for (RegionInfo regionInfo : onlineRegions) { 340 if (!regionInfo.isMetaRegion()) { 341 if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion2")) { 342 info = regionInfo; 343 ADMIN.unassign(regionInfo.getRegionName(), true); 344 } 345 } 346 } 347 348 boolean isInList = ProtobufUtil.getOnlineRegions( 349 rs.getRSRpcServices()).contains(info); 350 long timeout = System.currentTimeMillis() + 10000; 351 while ((System.currentTimeMillis() < timeout) && (isInList)) { 352 Thread.sleep(100); 353 isInList = ProtobufUtil.getOnlineRegions( 354 rs.getRSRpcServices()).contains(info); 355 } 356 357 assertFalse("The region should not be present in online regions list.", 358 isInList); 359 } 360 361 private HBaseAdmin createTable(TableName tableName) throws IOException { 362 HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); 363 364 HTableDescriptor htd = new HTableDescriptor(tableName); 365 HColumnDescriptor hcd = new HColumnDescriptor("value"); 366 367 htd.addFamily(hcd); 368 admin.createTable(htd, null); 369 return admin; 370 } 371 372 private void createTableWithDefaultConf(byte[] TABLENAME) throws IOException { 373 createTableWithDefaultConf(TableName.valueOf(TABLENAME)); 374 } 375 376 private void createTableWithDefaultConf(TableName TABLENAME) throws IOException { 377 HTableDescriptor htd = new HTableDescriptor(TABLENAME); 378 HColumnDescriptor hcd = new HColumnDescriptor("value"); 379 htd.addFamily(hcd); 380 381 ADMIN.createTable(htd, null); 382 } 383 384 /** 385 * For HBASE-2556 386 */ 387 @Test 388 public void testGetTableRegions() throws IOException { 389 final TableName tableName = TableName.valueOf(name.getMethodName()); 390 391 int expectedRegions = 10; 392 393 // Use 80 bit numbers to make sure we aren't limited 394 byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 395 byte [] endKey = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; 396 397 398 HTableDescriptor desc = new HTableDescriptor(tableName); 399 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); 400 ADMIN.createTable(desc, startKey, endKey, expectedRegions); 401 402 List<RegionInfo> RegionInfos = ADMIN.getRegions(tableName); 403 404 assertEquals("Tried to create " + expectedRegions + " regions " + 405 "but only found " + RegionInfos.size(), 406 expectedRegions, RegionInfos.size()); 407 } 408 409 @Test 410 public void testMoveToPreviouslyAssignedRS() throws IOException, InterruptedException { 411 MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); 412 HMaster master = cluster.getMaster(); 413 final TableName tableName = TableName.valueOf(name.getMethodName()); 414 Admin localAdmin = createTable(tableName); 415 List<RegionInfo> tableRegions = localAdmin.getRegions(tableName); 416 RegionInfo hri = tableRegions.get(0); 417 AssignmentManager am = master.getAssignmentManager(); 418 ServerName server = am.getRegionStates().getRegionServerOfRegion(hri); 419 localAdmin.move(hri.getEncodedNameAsBytes(), server); 420 assertEquals("Current region server and region server before move should be same.", server, 421 am.getRegionStates().getRegionServerOfRegion(hri)); 422 } 423 424 @Test 425 public void testWALRollWriting() throws Exception { 426 setUpforLogRolling(); 427 String className = this.getClass().getName(); 428 StringBuilder v = new StringBuilder(className); 429 while (v.length() < 1000) { 430 v.append(className); 431 } 432 byte[] value = Bytes.toBytes(v.toString()); 433 HRegionServer regionServer = startAndWriteData(TableName.valueOf(name.getMethodName()), value); 434 LOG.info("after writing there are " 435 + AbstractFSWALProvider.getNumRolledLogFiles(regionServer.getWAL(null)) + " log files"); 436 437 // flush all regions 438 for (HRegion r : regionServer.getOnlineRegionsLocalContext()) { 439 r.flush(true); 440 } 441 ADMIN.rollWALWriter(regionServer.getServerName()); 442 int count = AbstractFSWALProvider.getNumRolledLogFiles(regionServer.getWAL(null)); 443 LOG.info("after flushing all regions and rolling logs there are " + 444 count + " log files"); 445 assertTrue(("actual count: " + count), count <= 2); 446 } 447 448 private void setUpforLogRolling() { 449 // Force a region split after every 768KB 450 TEST_UTIL.getConfiguration().setLong(HConstants.HREGION_MAX_FILESIZE, 451 768L * 1024L); 452 453 // We roll the log after every 32 writes 454 TEST_UTIL.getConfiguration().setInt("hbase.regionserver.maxlogentries", 32); 455 456 TEST_UTIL.getConfiguration().setInt( 457 "hbase.regionserver.logroll.errors.tolerated", 2); 458 TEST_UTIL.getConfiguration().setInt("hbase.rpc.timeout", 10 * 1000); 459 460 // For less frequently updated regions flush after every 2 flushes 461 TEST_UTIL.getConfiguration().setInt( 462 "hbase.hregion.memstore.optionalflushcount", 2); 463 464 // We flush the cache after every 8192 bytes 465 TEST_UTIL.getConfiguration().setInt(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, 466 8192); 467 468 // Increase the amount of time between client retries 469 TEST_UTIL.getConfiguration().setLong("hbase.client.pause", 10 * 1000); 470 471 // Reduce thread wake frequency so that other threads can get 472 // a chance to run. 473 TEST_UTIL.getConfiguration().setInt(HConstants.THREAD_WAKE_FREQUENCY, 474 2 * 1000); 475 476 /**** configuration for testLogRollOnDatanodeDeath ****/ 477 // lower the namenode & datanode heartbeat so the namenode 478 // quickly detects datanode failures 479 TEST_UTIL.getConfiguration().setInt("dfs.namenode.heartbeat.recheck-interval", 5000); 480 TEST_UTIL.getConfiguration().setInt("dfs.heartbeat.interval", 1); 481 // the namenode might still try to choose the recently-dead datanode 482 // for a pipeline, so try to a new pipeline multiple times 483 TEST_UTIL.getConfiguration().setInt("dfs.client.block.write.retries", 30); 484 TEST_UTIL.getConfiguration().setInt( 485 "hbase.regionserver.hlog.tolerable.lowreplication", 2); 486 TEST_UTIL.getConfiguration().setInt( 487 "hbase.regionserver.hlog.lowreplication.rolllimit", 3); 488 } 489 490 private HRegionServer startAndWriteData(TableName tableName, byte[] value) 491 throws IOException, InterruptedException { 492 // When the hbase:meta table can be opened, the region servers are running 493 TEST_UTIL.getConnection().getTable(TableName.META_TABLE_NAME).close(); 494 495 // Create the test table and open it 496 HTableDescriptor desc = new HTableDescriptor(tableName); 497 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); 498 ADMIN.createTable(desc); 499 Table table = TEST_UTIL.getConnection().getTable(tableName); 500 501 HRegionServer regionServer = TEST_UTIL.getRSForFirstRegionInTable(tableName); 502 for (int i = 1; i <= 256; i++) { // 256 writes should cause 8 log rolls 503 Put put = new Put(Bytes.toBytes("row" + String.format("%1$04d", i))); 504 put.addColumn(HConstants.CATALOG_FAMILY, null, value); 505 table.put(put); 506 if (i % 32 == 0) { 507 // After every 32 writes sleep to let the log roller run 508 try { 509 Thread.sleep(2000); 510 } catch (InterruptedException e) { 511 // continue 512 } 513 } 514 } 515 516 table.close(); 517 return regionServer; 518 } 519 520 /** 521 * Check that we have an exception if the cluster is not there. 522 */ 523 @Test 524 public void testCheckHBaseAvailableWithoutCluster() { 525 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 526 527 // Test makes sense only when ZK connection registry is in use. 528 conf.set(HConstants.CLIENT_CONNECTION_REGISTRY_IMPL_CONF_KEY, 529 HConstants.ZK_CONNECTION_REGISTRY_CLASS); 530 // Change the ZK address to go to something not used. 531 conf.setInt(HConstants.ZOOKEEPER_CLIENT_PORT, 532 conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 9999)+10); 533 534 long start = System.currentTimeMillis(); 535 try { 536 HBaseAdmin.available(conf); 537 assertTrue(false); 538 } catch (ZooKeeperConnectionException ignored) { 539 } catch (IOException ignored) { 540 } 541 long end = System.currentTimeMillis(); 542 543 LOG.info("It took "+(end-start)+" ms to find out that" + 544 " HBase was not available"); 545 } 546 547 @Test 548 public void testDisableCatalogTable() throws Exception { 549 try { 550 ADMIN.disableTable(TableName.META_TABLE_NAME); 551 fail("Expected to throw ConstraintException"); 552 } catch (ConstraintException e) { 553 } 554 // Before the fix for HBASE-6146, the below table creation was failing as the hbase:meta table 555 // actually getting disabled by the disableTable() call. 556 HTableDescriptor htd = 557 new HTableDescriptor(TableName.valueOf(Bytes.toBytes(name.getMethodName()))); 558 HColumnDescriptor hcd = new HColumnDescriptor(Bytes.toBytes("cf1")); 559 htd.addFamily(hcd); 560 TEST_UTIL.getHBaseAdmin().createTable(htd); 561 } 562 563 @Test 564 public void testIsEnabledOrDisabledOnUnknownTable() throws Exception { 565 try { 566 ADMIN.isTableEnabled(TableName.valueOf(name.getMethodName())); 567 fail("Test should fail if isTableEnabled called on unknown table."); 568 } catch (IOException e) { 569 } 570 571 try { 572 ADMIN.isTableDisabled(TableName.valueOf(name.getMethodName())); 573 fail("Test should fail if isTableDisabled called on unknown table."); 574 } catch (IOException e) { 575 } 576 } 577 578 @Test 579 public void testGetRegion() throws Exception { 580 // We use actual HBaseAdmin instance instead of going via Admin interface in 581 // here because makes use of an internal HBA method (TODO: Fix.). 582 HBaseAdmin rawAdmin = TEST_UTIL.getHBaseAdmin(); 583 584 final TableName tableName = TableName.valueOf(name.getMethodName()); 585 LOG.info("Started " + tableName); 586 Table t = TEST_UTIL.createMultiRegionTable(tableName, HConstants.CATALOG_FAMILY); 587 588 try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 589 HRegionLocation regionLocation = locator.getRegionLocation(Bytes.toBytes("mmm")); 590 RegionInfo region = regionLocation.getRegionInfo(); 591 byte[] regionName = region.getRegionName(); 592 Pair<RegionInfo, ServerName> pair = rawAdmin.getRegion(regionName); 593 assertTrue(Bytes.equals(regionName, pair.getFirst().getRegionName())); 594 pair = rawAdmin.getRegion(region.getEncodedNameAsBytes()); 595 assertTrue(Bytes.equals(regionName, pair.getFirst().getRegionName())); 596 } 597 } 598 599 @Test 600 public void testBalancer() throws Exception { 601 boolean initialState = ADMIN.isBalancerEnabled(); 602 603 // Start the balancer, wait for it. 604 boolean prevState = ADMIN.setBalancerRunning(!initialState, true); 605 606 // The previous state should be the original state we observed 607 assertEquals(initialState, prevState); 608 609 // Current state should be opposite of the original 610 assertEquals(!initialState, ADMIN.isBalancerEnabled()); 611 612 // Reset it back to what it was 613 prevState = ADMIN.setBalancerRunning(initialState, true); 614 615 // The previous state should be the opposite of the initial state 616 assertEquals(!initialState, prevState); 617 // Current state should be the original state again 618 assertEquals(initialState, ADMIN.isBalancerEnabled()); 619 } 620 621 @Test 622 public void testRegionNormalizer() throws Exception { 623 boolean initialState = ADMIN.isNormalizerEnabled(); 624 625 // flip state 626 boolean prevState = ADMIN.setNormalizerRunning(!initialState); 627 628 // The previous state should be the original state we observed 629 assertEquals(initialState, prevState); 630 631 // Current state should be opposite of the original 632 assertEquals(!initialState, ADMIN.isNormalizerEnabled()); 633 634 // Reset it back to what it was 635 prevState = ADMIN.setNormalizerRunning(initialState); 636 637 // The previous state should be the opposite of the initial state 638 assertEquals(!initialState, prevState); 639 // Current state should be the original state again 640 assertEquals(initialState, ADMIN.isNormalizerEnabled()); 641 } 642 643 @Test 644 public void testAbortProcedureFail() throws Exception { 645 Random randomGenerator = new Random(); 646 long procId = randomGenerator.nextLong(); 647 648 boolean abortResult = ADMIN.abortProcedure(procId, true); 649 assertFalse(abortResult); 650 } 651 652 @Test 653 public void testGetProcedures() throws Exception { 654 String procList = ADMIN.getProcedures(); 655 assertTrue(procList.startsWith("[")); 656 } 657 658 @Test 659 public void testGetLocks() throws Exception { 660 String lockList = ADMIN.getLocks(); 661 assertTrue(lockList.startsWith("[")); 662 } 663 664 @Test 665 public void testDecommissionRegionServers() throws Exception { 666 List<ServerName> decommissionedRegionServers = ADMIN.listDecommissionedRegionServers(); 667 assertTrue(decommissionedRegionServers.isEmpty()); 668 669 final TableName tableName = TableName.valueOf(name.getMethodName()); 670 TEST_UTIL.createMultiRegionTable(tableName, Bytes.toBytes("f"), 6); 671 672 ArrayList<ServerName> clusterRegionServers = 673 new ArrayList<>(ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)) 674 .getLiveServerMetrics().keySet()); 675 676 assertEquals(3, clusterRegionServers.size()); 677 678 HashMap<ServerName, List<RegionInfo>> serversToDecommssion = new HashMap<>(); 679 // Get a server that has meta online. We will decommission two of the servers, 680 // leaving one online. 681 int i; 682 for (i = 0; i < clusterRegionServers.size(); i++) { 683 List<RegionInfo> regionsOnServer = ADMIN.getRegions(clusterRegionServers.get(i)); 684 if (ADMIN.getRegions(clusterRegionServers.get(i)).stream().anyMatch(p -> p.isMetaRegion())) { 685 serversToDecommssion.put(clusterRegionServers.get(i), regionsOnServer); 686 break; 687 } 688 } 689 690 clusterRegionServers.remove(i); 691 // Get another server to decommission. 692 serversToDecommssion.put(clusterRegionServers.get(0), 693 ADMIN.getRegions(clusterRegionServers.get(0))); 694 695 ServerName remainingServer = clusterRegionServers.get(1); 696 697 // Decommission 698 ADMIN.decommissionRegionServers(new ArrayList<ServerName>(serversToDecommssion.keySet()), true); 699 assertEquals(2, ADMIN.listDecommissionedRegionServers().size()); 700 701 // Verify the regions have been off the decommissioned servers, all on the one 702 // remaining server. 703 for (ServerName server : serversToDecommssion.keySet()) { 704 for (RegionInfo region : serversToDecommssion.get(server)) { 705 TEST_UTIL.assertRegionOnServer(region, remainingServer, 10000); 706 } 707 } 708 709 // Recommission and load the regions. 710 for (ServerName server : serversToDecommssion.keySet()) { 711 List<byte[]> encodedRegionNames = serversToDecommssion.get(server).stream() 712 .map(region -> region.getEncodedNameAsBytes()).collect(Collectors.toList()); 713 ADMIN.recommissionRegionServer(server, encodedRegionNames); 714 } 715 assertTrue(ADMIN.listDecommissionedRegionServers().isEmpty()); 716 // Verify the regions have been moved to the recommissioned servers 717 for (ServerName server : serversToDecommssion.keySet()) { 718 for (RegionInfo region : serversToDecommssion.get(server)) { 719 TEST_UTIL.assertRegionOnServer(region, server, 10000); 720 } 721 } 722 } 723 724 /** 725 * TestCase for HBASE-21355 726 */ 727 @Test 728 public void testGetRegionInfo() throws Exception { 729 final TableName tableName = TableName.valueOf(name.getMethodName()); 730 Table table = TEST_UTIL.createTable(tableName, Bytes.toBytes("f")); 731 for (int i = 0; i < 100; i++) { 732 table.put(new Put(Bytes.toBytes(i)).addColumn(Bytes.toBytes("f"), Bytes.toBytes("q"), 733 Bytes.toBytes(i))); 734 } 735 ADMIN.flush(tableName); 736 737 HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(table.getName()); 738 List<HRegion> regions = rs.getRegions(tableName); 739 Assert.assertEquals(1, regions.size()); 740 741 HRegion region = regions.get(0); 742 byte[] regionName = region.getRegionInfo().getRegionName(); 743 HStore store = region.getStore(Bytes.toBytes("f")); 744 long expectedStoreFilesSize = store.getStorefilesSize(); 745 Assert.assertNotNull(store); 746 Assert.assertEquals(expectedStoreFilesSize, store.getSize()); 747 748 ClusterConnection conn = ((ClusterConnection) ADMIN.getConnection()); 749 HBaseRpcController controller = conn.getRpcControllerFactory().newController(); 750 for (int i = 0; i < 10; i++) { 751 RegionInfo ri = 752 ProtobufUtil.getRegionInfo(controller, conn.getAdmin(rs.getServerName()), regionName); 753 Assert.assertEquals(region.getRegionInfo(), ri); 754 755 // Make sure that the store size is still the actual file system's store size. 756 Assert.assertEquals(expectedStoreFilesSize, store.getSize()); 757 } 758 759 // Test querying using the encoded name only. When encoded name passed, 760 // and the target server is the Master, we return the full region name. 761 // Convenience. 762 testGetWithEncodedRegionName(conn, region.getRegionInfo()); 763 testGetWithRegionName(conn, region.getRegionInfo()); 764 // Try querying meta encoded name. 765 testGetWithEncodedRegionName(conn, RegionInfoBuilder.FIRST_META_REGIONINFO); 766 testGetWithRegionName(conn, RegionInfoBuilder.FIRST_META_REGIONINFO); 767 } 768 769 /** 770 * Do get of RegionInfo from Master using encoded region name. 771 */ 772 private void testGetWithEncodedRegionName(ClusterConnection conn, RegionInfo inputRI) 773 throws IOException { 774 RegionInfo ri = ProtobufUtil.getRegionInfo(null, 775 conn.getAdmin(TEST_UTIL.getMiniHBaseCluster().getMaster().getServerName()), 776 inputRI.getEncodedNameAsBytes()); 777 assertEquals(inputRI, ri); 778 } 779 780 private void testGetWithRegionName(ClusterConnection conn, RegionInfo inputRI) 781 throws IOException { 782 RegionInfo ri = ProtobufUtil.getRegionInfo(null, 783 conn.getAdmin(TEST_UTIL.getMiniHBaseCluster().getMaster().getServerName()), 784 inputRI.getRegionName()); 785 assertEquals(inputRI, ri); 786 } 787 788 @Test 789 public void testTableSplitFollowedByModify() throws Exception { 790 final TableName tableName = TableName.valueOf(name.getMethodName()); 791 TEST_UTIL.createTable(tableName, Bytes.toBytes("f")); 792 793 // get the original table region count 794 List<RegionInfo> regions = ADMIN.getRegions(tableName); 795 int originalCount = regions.size(); 796 assertEquals(1, originalCount); 797 798 // split the table and wait until region count increases 799 ADMIN.split(tableName, Bytes.toBytes(3)); 800 TEST_UTIL.waitFor(30000, new Predicate<Exception>() { 801 802 @Override 803 public boolean evaluate() throws Exception { 804 return ADMIN.getRegions(tableName).size() > originalCount; 805 } 806 }); 807 808 // do some table modification 809 TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(ADMIN.getDescriptor(tableName)) 810 .setMaxFileSize(11111111) 811 .build(); 812 ADMIN.modifyTable(tableDesc); 813 assertEquals(11111111, ADMIN.getDescriptor(tableName).getMaxFileSize()); 814 } 815 816 @Test 817 public void testTableMergeFollowedByModify() throws Exception { 818 final TableName tableName = TableName.valueOf(name.getMethodName()); 819 TEST_UTIL.createTable(tableName, new byte[][] { Bytes.toBytes("f") }, 820 new byte[][] { Bytes.toBytes(3) }); 821 822 // assert we have at least 2 regions in the table 823 List<RegionInfo> regions = ADMIN.getRegions(tableName); 824 int originalCount = regions.size(); 825 assertTrue(originalCount >= 2); 826 827 byte[] nameOfRegionA = regions.get(0).getEncodedNameAsBytes(); 828 byte[] nameOfRegionB = regions.get(1).getEncodedNameAsBytes(); 829 830 // merge the table regions and wait until region count decreases 831 ADMIN.mergeRegionsAsync(nameOfRegionA, nameOfRegionB, true); 832 TEST_UTIL.waitFor(30000, new Predicate<Exception>() { 833 834 @Override 835 public boolean evaluate() throws Exception { 836 return ADMIN.getRegions(tableName).size() < originalCount; 837 } 838 }); 839 840 // do some table modification 841 TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(ADMIN.getDescriptor(tableName)) 842 .setMaxFileSize(11111111) 843 .build(); 844 ADMIN.modifyTable(tableDesc); 845 assertEquals(11111111, ADMIN.getDescriptor(tableName).getMaxFileSize()); 846 } 847 848 @Test 849 public void testSnapshotCleanupAsync() throws Exception { 850 testSnapshotCleanup(false); 851 } 852 853 @Test 854 public void testSnapshotCleanupSync() throws Exception { 855 testSnapshotCleanup(true); 856 } 857 858 private void testSnapshotCleanup(final boolean synchronous) throws IOException { 859 final boolean initialState = ADMIN.isSnapshotCleanupEnabled(); 860 // Switch the snapshot auto cleanup state to opposite to initial state 861 boolean prevState = ADMIN.snapshotCleanupSwitch(!initialState, synchronous); 862 // The previous state should be the original state we observed 863 assertEquals(initialState, prevState); 864 // Current state should be opposite of the initial state 865 assertEquals(!initialState, ADMIN.isSnapshotCleanupEnabled()); 866 // Reset the state back to what it was initially 867 prevState = ADMIN.snapshotCleanupSwitch(initialState, synchronous); 868 // The previous state should be the opposite of the initial state 869 assertEquals(!initialState, prevState); 870 // Current state should be the original state again 871 assertEquals(initialState, ADMIN.isSnapshotCleanupEnabled()); 872 } 873 874 @Test 875 public void testSlowLogResponses() throws Exception { 876 // get all live server names 877 Collection<ServerName> serverNames = ADMIN.getRegionServers(); 878 List<ServerName> serverNameList = new ArrayList<>(serverNames); 879 880 // clean up slowlog responses maintained in memory by RegionServers 881 List<Boolean> areSlowLogsCleared = ADMIN.clearSlowLogResponses(new HashSet<>(serverNameList)); 882 883 int countFailedClearSlowResponse = 0; 884 for (Boolean isSlowLogCleared : areSlowLogsCleared) { 885 if (!isSlowLogCleared) { 886 ++countFailedClearSlowResponse; 887 } 888 } 889 Assert.assertEquals(countFailedClearSlowResponse, 0); 890 891 List<LogEntry> onlineLogRecords = ADMIN.getLogEntries(new HashSet<>(serverNames), 892 "SLOW_LOG", ServerType.REGION_SERVER, 100, null); 893 // after cleanup of slowlog responses, total count of slowlog payloads should be 0 894 Assert.assertEquals(onlineLogRecords.size(), 0); 895 List<LogEntry> balancerDecisionRecords = 896 ADMIN.getLogEntries(null, "BALANCER_DECISION", ServerType.MASTER, 100, null); 897 Assert.assertEquals(balancerDecisionRecords.size(), 0); 898 } 899 900 @Test 901 public void testGetRegionServers() throws Exception { 902 // get all live server names 903 List<ServerName> serverNames = new ArrayList<>(ADMIN.getRegionServers(true)); 904 Assert.assertEquals(3, serverNames.size()); 905 906 List<ServerName> serversToDecom = new ArrayList<>(); 907 ServerName serverToDecommission = serverNames.get(0); 908 909 serversToDecom.add(serverToDecommission); 910 ADMIN.decommissionRegionServers(serversToDecom, false); 911 waitForServerCommissioned(serverToDecommission, true); 912 913 Assert.assertEquals(2, ADMIN.getRegionServers(true).size()); 914 Assert.assertEquals(3, ADMIN.getRegionServers(false).size()); 915 916 ADMIN.recommissionRegionServer(serverToDecommission, Collections.emptyList()); 917 waitForServerCommissioned(null, false); 918 919 Assert.assertEquals(3, ADMIN.getRegionServers(true).size()); 920 Assert.assertEquals(3, ADMIN.getRegionServers(false).size()); 921 } 922 923 private static void waitForServerCommissioned(ServerName excludeServer, 924 boolean anyServerDecommissioned) { 925 TEST_UTIL.waitFor(3000, () -> { 926 try { 927 List<ServerName> decomServers = TEST_UTIL.getAdmin().listDecommissionedRegionServers(); 928 if (anyServerDecommissioned) { 929 return decomServers.size() == 1 930 && decomServers.get(0).equals(excludeServer); 931 } else { 932 return decomServers.size() == 0; 933 } 934 } catch (IOException e) { 935 throw new RuntimeException(e); 936 } 937 }); 938 } 939 940}