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