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