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; 019 020import java.io.IOException; 021import java.security.PrivilegedAction; 022import java.util.ArrayList; 023import java.util.HashSet; 024import java.util.List; 025import java.util.Set; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.fs.FileSystem; 028import org.apache.hadoop.hbase.client.RegionReplicaUtil; 029import org.apache.hadoop.hbase.master.HMaster; 030import org.apache.hadoop.hbase.regionserver.HRegion; 031import org.apache.hadoop.hbase.regionserver.HRegion.FlushResult; 032import org.apache.hadoop.hbase.regionserver.HRegionServer; 033import org.apache.hadoop.hbase.regionserver.Region; 034import org.apache.hadoop.hbase.security.User; 035import org.apache.hadoop.hbase.test.MetricsAssertHelper; 036import org.apache.hadoop.hbase.util.JVMClusterUtil; 037import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread; 038import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; 039import org.apache.hadoop.hbase.util.Threads; 040import org.apache.yetus.audience.InterfaceAudience; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.AdminService; 045import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService; 046import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MasterService; 047import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStartupResponse; 048 049/** 050 * This class creates a single process HBase cluster. each server. The master uses the 'default' 051 * FileSystem. The RegionServers, if we are running on DistributedFilesystem, create a FileSystem 052 * instance each and will close down their instance on the way out. 053 */ 054@InterfaceAudience.Public 055public class MiniHBaseCluster extends HBaseCluster { 056 private static final Logger LOG = LoggerFactory.getLogger(MiniHBaseCluster.class.getName()); 057 public LocalHBaseCluster hbaseCluster; 058 private static int index; 059 060 /** 061 * Start a MiniHBaseCluster. 062 * @param conf Configuration to be used for cluster 063 * @param numRegionServers initial number of region servers to start. 064 */ 065 public MiniHBaseCluster(Configuration conf, int numRegionServers) 066 throws IOException, InterruptedException { 067 this(conf, 1, numRegionServers); 068 } 069 070 /** 071 * Start a MiniHBaseCluster. 072 * @param conf Configuration to be used for cluster 073 * @param numMasters initial number of masters to start. 074 * @param numRegionServers initial number of region servers to start. 075 */ 076 public MiniHBaseCluster(Configuration conf, int numMasters, int numRegionServers) 077 throws IOException, InterruptedException { 078 this(conf, numMasters, numRegionServers, null, null); 079 } 080 081 /** 082 * Start a MiniHBaseCluster. 083 * @param conf Configuration to be used for cluster 084 * @param numMasters initial number of masters to start. 085 * @param numRegionServers initial number of region servers to start. 086 */ 087 public MiniHBaseCluster(Configuration conf, int numMasters, int numRegionServers, 088 Class<? extends HMaster> masterClass, 089 Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> regionserverClass) 090 throws IOException, InterruptedException { 091 this(conf, numMasters, 0, numRegionServers, null, masterClass, regionserverClass); 092 } 093 094 /** 095 * @param rsPorts Ports that RegionServer should use; pass ports if you want to test cluster 096 * restart where for sure the regionservers come up on same address+port (but just 097 * with different startcode); by default mini hbase clusters choose new arbitrary 098 * ports on each cluster start. 099 */ 100 public MiniHBaseCluster(Configuration conf, int numMasters, int numAlwaysStandByMasters, 101 int numRegionServers, List<Integer> rsPorts, Class<? extends HMaster> masterClass, 102 Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> regionserverClass) 103 throws IOException, InterruptedException { 104 super(conf); 105 106 // Hadoop 2 107 CompatibilityFactory.getInstance(MetricsAssertHelper.class).init(); 108 109 init(numMasters, numAlwaysStandByMasters, numRegionServers, rsPorts, masterClass, 110 regionserverClass); 111 this.initialClusterStatus = getClusterMetrics(); 112 } 113 114 public Configuration getConfiguration() { 115 return this.conf; 116 } 117 118 /** 119 * Subclass so can get at protected methods (none at moment). Also, creates a FileSystem instance 120 * per instantiation. Adds a shutdown own FileSystem on the way out. Shuts down own Filesystem 121 * only, not All filesystems as the FileSystem system exit hook does. 122 */ 123 public static class MiniHBaseClusterRegionServer extends HRegionServer { 124 private Thread shutdownThread = null; 125 private User user = null; 126 /** 127 * List of RegionServers killed so far. ServerName also comprises startCode of a server, so any 128 * restarted instances of the same server will have different ServerName and will not coincide 129 * with past dead ones. So there's no need to cleanup this list. 130 */ 131 static Set<ServerName> killedServers = new HashSet<>(); 132 133 public MiniHBaseClusterRegionServer(Configuration conf) 134 throws IOException, InterruptedException { 135 super(conf); 136 this.user = User.getCurrent(); 137 } 138 139 /* 140 * @param currentfs We return this if we did not make a new one. 141 * @param uniqueName Same name used to help identify the created fs. 142 * @return A new fs instance if we are up on DistributeFileSystem. 143 */ 144 145 @Override 146 protected void handleReportForDutyResponse(final RegionServerStartupResponse c) 147 throws IOException { 148 super.handleReportForDutyResponse(c); 149 // Run this thread to shutdown our filesystem on way out. 150 this.shutdownThread = new SingleFileSystemShutdownThread(getFileSystem()); 151 } 152 153 @Override 154 public void run() { 155 try { 156 this.user.runAs(new PrivilegedAction<Object>() { 157 @Override 158 public Object run() { 159 runRegionServer(); 160 return null; 161 } 162 }); 163 } catch (Throwable t) { 164 LOG.error("Exception in run", t); 165 } finally { 166 // Run this on the way out. 167 if (this.shutdownThread != null) { 168 this.shutdownThread.start(); 169 Threads.shutdown(this.shutdownThread, 30000); 170 } 171 } 172 } 173 174 private void runRegionServer() { 175 super.run(); 176 } 177 178 @Override 179 protected void kill() { 180 killedServers.add(getServerName()); 181 super.kill(); 182 } 183 184 @Override 185 public void abort(final String reason, final Throwable cause) { 186 this.user.runAs(new PrivilegedAction<Object>() { 187 @Override 188 public Object run() { 189 abortRegionServer(reason, cause); 190 return null; 191 } 192 }); 193 } 194 195 private void abortRegionServer(String reason, Throwable cause) { 196 super.abort(reason, cause); 197 } 198 } 199 200 /** 201 * Alternate shutdown hook. Just shuts down the passed fs, not all as default filesystem hook 202 * does. 203 */ 204 static class SingleFileSystemShutdownThread extends Thread { 205 private final FileSystem fs; 206 207 SingleFileSystemShutdownThread(final FileSystem fs) { 208 super("Shutdown of " + fs); 209 this.fs = fs; 210 } 211 212 @Override 213 public void run() { 214 try { 215 LOG.info("Hook closing fs=" + this.fs); 216 this.fs.close(); 217 } catch (IOException e) { 218 LOG.warn("Running hook", e); 219 } 220 } 221 } 222 223 private void init(final int nMasterNodes, final int numAlwaysStandByMasters, 224 final int nRegionNodes, List<Integer> rsPorts, Class<? extends HMaster> masterClass, 225 Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> regionserverClass) 226 throws IOException, InterruptedException { 227 try { 228 if (masterClass == null) { 229 masterClass = HMaster.class; 230 } 231 if (regionserverClass == null) { 232 regionserverClass = MiniHBaseCluster.MiniHBaseClusterRegionServer.class; 233 } 234 235 // start up a LocalHBaseCluster 236 hbaseCluster = new LocalHBaseCluster(conf, nMasterNodes, numAlwaysStandByMasters, 0, 237 masterClass, regionserverClass); 238 239 // manually add the regionservers as other users 240 for (int i = 0; i < nRegionNodes; i++) { 241 Configuration rsConf = HBaseConfiguration.create(conf); 242 if (rsPorts != null) { 243 rsConf.setInt(HConstants.REGIONSERVER_PORT, rsPorts.get(i)); 244 } 245 User user = HBaseTestingUtility.getDifferentUser(rsConf, ".hfs." + index++); 246 hbaseCluster.addRegionServer(rsConf, i, user); 247 } 248 249 hbaseCluster.startup(); 250 } catch (IOException e) { 251 shutdown(); 252 throw e; 253 } catch (Throwable t) { 254 LOG.error("Error starting cluster", t); 255 shutdown(); 256 throw new IOException("Shutting down", t); 257 } 258 } 259 260 @Override 261 public void startRegionServer(String hostname, int port) throws IOException { 262 final Configuration newConf = HBaseConfiguration.create(conf); 263 newConf.setInt(HConstants.REGIONSERVER_PORT, port); 264 startRegionServer(newConf); 265 } 266 267 @Override 268 public void killRegionServer(ServerName serverName) throws IOException { 269 HRegionServer server = getRegionServer(getRegionServerIndex(serverName)); 270 if (server instanceof MiniHBaseClusterRegionServer) { 271 LOG.info("Killing " + server.toString()); 272 ((MiniHBaseClusterRegionServer) server).kill(); 273 } else { 274 abortRegionServer(getRegionServerIndex(serverName)); 275 } 276 } 277 278 @Override 279 public boolean isKilledRS(ServerName serverName) { 280 return MiniHBaseClusterRegionServer.killedServers.contains(serverName); 281 } 282 283 @Override 284 public void stopRegionServer(ServerName serverName) throws IOException { 285 stopRegionServer(getRegionServerIndex(serverName)); 286 } 287 288 @Override 289 public void suspendRegionServer(ServerName serverName) throws IOException { 290 suspendRegionServer(getRegionServerIndex(serverName)); 291 } 292 293 @Override 294 public void resumeRegionServer(ServerName serverName) throws IOException { 295 resumeRegionServer(getRegionServerIndex(serverName)); 296 } 297 298 @Override 299 public void waitForRegionServerToStop(ServerName serverName, long timeout) throws IOException { 300 // ignore timeout for now 301 waitOnRegionServer(getRegionServerIndex(serverName)); 302 } 303 304 @Override 305 public void startZkNode(String hostname, int port) throws IOException { 306 LOG.warn("Starting zookeeper nodes on mini cluster is not supported"); 307 } 308 309 @Override 310 public void killZkNode(ServerName serverName) throws IOException { 311 LOG.warn("Aborting zookeeper nodes on mini cluster is not supported"); 312 } 313 314 @Override 315 public void stopZkNode(ServerName serverName) throws IOException { 316 LOG.warn("Stopping zookeeper nodes on mini cluster is not supported"); 317 } 318 319 @Override 320 public void waitForZkNodeToStart(ServerName serverName, long timeout) throws IOException { 321 LOG.warn("Waiting for zookeeper nodes to start on mini cluster is not supported"); 322 } 323 324 @Override 325 public void waitForZkNodeToStop(ServerName serverName, long timeout) throws IOException { 326 LOG.warn("Waiting for zookeeper nodes to stop on mini cluster is not supported"); 327 } 328 329 @Override 330 public void startDataNode(ServerName serverName) throws IOException { 331 LOG.warn("Starting datanodes on mini cluster is not supported"); 332 } 333 334 @Override 335 public void killDataNode(ServerName serverName) throws IOException { 336 LOG.warn("Aborting datanodes on mini cluster is not supported"); 337 } 338 339 @Override 340 public void stopDataNode(ServerName serverName) throws IOException { 341 LOG.warn("Stopping datanodes on mini cluster is not supported"); 342 } 343 344 @Override 345 public void waitForDataNodeToStart(ServerName serverName, long timeout) throws IOException { 346 LOG.warn("Waiting for datanodes to start on mini cluster is not supported"); 347 } 348 349 @Override 350 public void waitForDataNodeToStop(ServerName serverName, long timeout) throws IOException { 351 LOG.warn("Waiting for datanodes to stop on mini cluster is not supported"); 352 } 353 354 @Override 355 public void startNameNode(ServerName serverName) throws IOException { 356 LOG.warn("Starting namenodes on mini cluster is not supported"); 357 } 358 359 @Override 360 public void killNameNode(ServerName serverName) throws IOException { 361 LOG.warn("Aborting namenodes on mini cluster is not supported"); 362 } 363 364 @Override 365 public void stopNameNode(ServerName serverName) throws IOException { 366 LOG.warn("Stopping namenodes on mini cluster is not supported"); 367 } 368 369 @Override 370 public void waitForNameNodeToStart(ServerName serverName, long timeout) throws IOException { 371 LOG.warn("Waiting for namenodes to start on mini cluster is not supported"); 372 } 373 374 @Override 375 public void waitForNameNodeToStop(ServerName serverName, long timeout) throws IOException { 376 LOG.warn("Waiting for namenodes to stop on mini cluster is not supported"); 377 } 378 379 @Override 380 public void startJournalNode(ServerName serverName) { 381 LOG.warn("Starting journalnodes on mini cluster is not supported"); 382 } 383 384 @Override 385 public void killJournalNode(ServerName serverName) { 386 LOG.warn("Aborting journalnodes on mini cluster is not supported"); 387 } 388 389 @Override 390 public void stopJournalNode(ServerName serverName) { 391 LOG.warn("Stopping journalnodes on mini cluster is not supported"); 392 } 393 394 @Override 395 public void waitForJournalNodeToStart(ServerName serverName, long timeout) { 396 LOG.warn("Waiting for journalnodes to start on mini cluster is not supported"); 397 } 398 399 @Override 400 public void waitForJournalNodeToStop(ServerName serverName, long timeout) { 401 LOG.warn("Waiting for journalnodes to stop on mini cluster is not supported"); 402 } 403 404 @Override 405 public void startMaster(String hostname, int port) throws IOException { 406 this.startMaster(); 407 } 408 409 @Override 410 public void killMaster(ServerName serverName) throws IOException { 411 abortMaster(getMasterIndex(serverName)); 412 } 413 414 @Override 415 public void stopMaster(ServerName serverName) throws IOException { 416 stopMaster(getMasterIndex(serverName)); 417 } 418 419 @Override 420 public void waitForMasterToStop(ServerName serverName, long timeout) throws IOException { 421 // ignore timeout for now 422 waitOnMaster(getMasterIndex(serverName)); 423 } 424 425 /** 426 * Starts a region server thread running 427 * @return New RegionServerThread 428 */ 429 public JVMClusterUtil.RegionServerThread startRegionServer() throws IOException { 430 final Configuration newConf = HBaseConfiguration.create(conf); 431 return startRegionServer(newConf); 432 } 433 434 private JVMClusterUtil.RegionServerThread startRegionServer(Configuration configuration) 435 throws IOException { 436 User rsUser = HBaseTestingUtility.getDifferentUser(configuration, ".hfs." + index++); 437 JVMClusterUtil.RegionServerThread t = null; 438 try { 439 t = 440 hbaseCluster.addRegionServer(configuration, hbaseCluster.getRegionServers().size(), rsUser); 441 t.start(); 442 t.waitForServerOnline(); 443 } catch (InterruptedException ie) { 444 throw new IOException("Interrupted adding regionserver to cluster", ie); 445 } 446 return t; 447 } 448 449 /** 450 * Starts a region server thread and waits until its processed by master. Throws an exception when 451 * it can't start a region server or when the region server is not processed by master within the 452 * timeout. 453 * @return New RegionServerThread 454 */ 455 public JVMClusterUtil.RegionServerThread startRegionServerAndWait(long timeout) 456 throws IOException { 457 458 JVMClusterUtil.RegionServerThread t = startRegionServer(); 459 ServerName rsServerName = t.getRegionServer().getServerName(); 460 461 long start = System.currentTimeMillis(); 462 ClusterStatus clusterStatus = getClusterStatus(); 463 while ((System.currentTimeMillis() - start) < timeout) { 464 if (clusterStatus != null && clusterStatus.getServers().contains(rsServerName)) { 465 return t; 466 } 467 Threads.sleep(100); 468 } 469 if (t.getRegionServer().isOnline()) { 470 throw new IOException("RS: " + rsServerName + " online, but not processed by master"); 471 } else { 472 throw new IOException("RS: " + rsServerName + " is offline"); 473 } 474 } 475 476 /** 477 * Cause a region server to exit doing basic clean up only on its way out. 478 * @param serverNumber Used as index into a list. 479 */ 480 public String abortRegionServer(int serverNumber) { 481 HRegionServer server = getRegionServer(serverNumber); 482 LOG.info("Aborting " + server.toString()); 483 server.abort("Aborting for tests", new Exception("Trace info")); 484 return server.toString(); 485 } 486 487 /** 488 * Shut down the specified region server cleanly 489 * @param serverNumber Used as index into a list. 490 * @return the region server that was stopped 491 */ 492 public JVMClusterUtil.RegionServerThread stopRegionServer(int serverNumber) { 493 return stopRegionServer(serverNumber, true); 494 } 495 496 /** 497 * Shut down the specified region server cleanly 498 * @param serverNumber Used as index into a list. 499 * @param shutdownFS True is we are to shutdown the filesystem as part of this regionserver's 500 * shutdown. Usually we do but you do not want to do this if you are running 501 * multiple regionservers in a test and you shut down one before end of the 502 * test. 503 * @return the region server that was stopped 504 */ 505 public JVMClusterUtil.RegionServerThread stopRegionServer(int serverNumber, 506 final boolean shutdownFS) { 507 JVMClusterUtil.RegionServerThread server = hbaseCluster.getRegionServers().get(serverNumber); 508 LOG.info("Stopping " + server.toString()); 509 server.getRegionServer().stop("Stopping rs " + serverNumber); 510 return server; 511 } 512 513 /** 514 * Suspend the specified region server 515 * @param serverNumber Used as index into a list. 516 */ 517 public JVMClusterUtil.RegionServerThread suspendRegionServer(int serverNumber) { 518 JVMClusterUtil.RegionServerThread server = hbaseCluster.getRegionServers().get(serverNumber); 519 LOG.info("Suspending {}", server.toString()); 520 server.suspend(); 521 return server; 522 } 523 524 /** 525 * Resume the specified region server 526 * @param serverNumber Used as index into a list. 527 */ 528 public JVMClusterUtil.RegionServerThread resumeRegionServer(int serverNumber) { 529 JVMClusterUtil.RegionServerThread server = hbaseCluster.getRegionServers().get(serverNumber); 530 LOG.info("Resuming {}", server.toString()); 531 server.resume(); 532 return server; 533 } 534 535 /** 536 * Wait for the specified region server to stop. Removes this thread from list of running threads. 537 * @return Name of region server that just went down. 538 */ 539 public String waitOnRegionServer(final int serverNumber) { 540 return this.hbaseCluster.waitOnRegionServer(serverNumber); 541 } 542 543 /** 544 * Starts a master thread running 545 * @return New RegionServerThread 546 */ 547 public JVMClusterUtil.MasterThread startMaster() throws IOException { 548 Configuration c = HBaseConfiguration.create(conf); 549 User user = HBaseTestingUtility.getDifferentUser(c, ".hfs." + index++); 550 551 JVMClusterUtil.MasterThread t = null; 552 try { 553 t = hbaseCluster.addMaster(c, hbaseCluster.getMasters().size(), user); 554 t.start(); 555 } catch (InterruptedException ie) { 556 throw new IOException("Interrupted adding master to cluster", ie); 557 } 558 conf.set(HConstants.MASTER_ADDRS_KEY, 559 hbaseCluster.getConfiguration().get(HConstants.MASTER_ADDRS_KEY)); 560 return t; 561 } 562 563 /** 564 * Returns the current active master, if available. 565 * @return the active HMaster, null if none is active. 566 */ 567 @Override 568 public MasterService.BlockingInterface getMasterAdminService() { 569 return this.hbaseCluster.getActiveMaster().getMasterRpcServices(); 570 } 571 572 /** 573 * Returns the current active master, if available. 574 * @return the active HMaster, null if none is active. 575 */ 576 public HMaster getMaster() { 577 return this.hbaseCluster.getActiveMaster(); 578 } 579 580 /** 581 * Returns the current active master thread, if available. 582 * @return the active MasterThread, null if none is active. 583 */ 584 public MasterThread getMasterThread() { 585 for (MasterThread mt : hbaseCluster.getLiveMasters()) { 586 if (mt.getMaster().isActiveMaster()) { 587 return mt; 588 } 589 } 590 return null; 591 } 592 593 /** 594 * Returns the master at the specified index, if available. 595 * @return the active HMaster, null if none is active. 596 */ 597 public HMaster getMaster(final int serverNumber) { 598 return this.hbaseCluster.getMaster(serverNumber); 599 } 600 601 /** 602 * Cause a master to exit without shutting down entire cluster. 603 * @param serverNumber Used as index into a list. 604 */ 605 public String abortMaster(int serverNumber) { 606 HMaster server = getMaster(serverNumber); 607 LOG.info("Aborting " + server.toString()); 608 server.abort("Aborting for tests", new Exception("Trace info")); 609 return server.toString(); 610 } 611 612 /** 613 * Shut down the specified master cleanly 614 * @param serverNumber Used as index into a list. 615 * @return the region server that was stopped 616 */ 617 public JVMClusterUtil.MasterThread stopMaster(int serverNumber) { 618 return stopMaster(serverNumber, true); 619 } 620 621 /** 622 * Shut down the specified master cleanly 623 * @param serverNumber Used as index into a list. 624 * @param shutdownFS True is we are to shutdown the filesystem as part of this master's 625 * shutdown. Usually we do but you do not want to do this if you are running 626 * multiple master in a test and you shut down one before end of the test. 627 * @return the master that was stopped 628 */ 629 public JVMClusterUtil.MasterThread stopMaster(int serverNumber, final boolean shutdownFS) { 630 JVMClusterUtil.MasterThread server = hbaseCluster.getMasters().get(serverNumber); 631 LOG.info("Stopping " + server.toString()); 632 server.getMaster().stop("Stopping master " + serverNumber); 633 return server; 634 } 635 636 /** 637 * Wait for the specified master to stop. Removes this thread from list of running threads. 638 * @return Name of master that just went down. 639 */ 640 public String waitOnMaster(final int serverNumber) { 641 return this.hbaseCluster.waitOnMaster(serverNumber); 642 } 643 644 /** 645 * Blocks until there is an active master and that master has completed initialization. 646 * @return true if an active master becomes available. false if there are no masters left. 647 */ 648 @Override 649 public boolean waitForActiveAndReadyMaster(long timeout) throws IOException { 650 List<JVMClusterUtil.MasterThread> mts; 651 long start = System.currentTimeMillis(); 652 while ( 653 !(mts = getMasterThreads()).isEmpty() && (System.currentTimeMillis() - start) < timeout 654 ) { 655 for (JVMClusterUtil.MasterThread mt : mts) { 656 if (mt.getMaster().isActiveMaster() && mt.getMaster().isInitialized()) { 657 return true; 658 } 659 } 660 661 Threads.sleep(100); 662 } 663 return false; 664 } 665 666 /** Returns List of master threads. */ 667 public List<JVMClusterUtil.MasterThread> getMasterThreads() { 668 return this.hbaseCluster.getMasters(); 669 } 670 671 /** Returns List of live master threads (skips the aborted and the killed) */ 672 public List<JVMClusterUtil.MasterThread> getLiveMasterThreads() { 673 return this.hbaseCluster.getLiveMasters(); 674 } 675 676 /** 677 * Wait for Mini HBase Cluster to shut down. 678 */ 679 public void join() { 680 this.hbaseCluster.join(); 681 } 682 683 /** 684 * Shut down the mini HBase cluster 685 */ 686 @Override 687 public void shutdown() throws IOException { 688 if (this.hbaseCluster != null) { 689 this.hbaseCluster.shutdown(); 690 } 691 } 692 693 @Override 694 public void close() throws IOException { 695 } 696 697 /** 698 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0 Use 699 * {@link #getClusterMetrics()} instead. 700 */ 701 @Deprecated 702 public ClusterStatus getClusterStatus() throws IOException { 703 HMaster master = getMaster(); 704 return master == null ? null : new ClusterStatus(master.getClusterMetrics()); 705 } 706 707 @Override 708 public ClusterMetrics getClusterMetrics() throws IOException { 709 HMaster master = getMaster(); 710 return master == null ? null : master.getClusterMetrics(); 711 } 712 713 private void executeFlush(HRegion region) throws IOException { 714 if (!RegionReplicaUtil.isDefaultReplica(region.getRegionInfo())) { 715 return; 716 } 717 // retry 5 times if we can not flush 718 for (int i = 0; i < 5; i++) { 719 FlushResult result = region.flush(true); 720 if (result.getResult() != FlushResult.Result.CANNOT_FLUSH) { 721 return; 722 } 723 Threads.sleep(1000); 724 } 725 } 726 727 /** 728 * Call flushCache on all regions on all participating regionservers. 729 */ 730 public void flushcache() throws IOException { 731 for (JVMClusterUtil.RegionServerThread t : this.hbaseCluster.getRegionServers()) { 732 for (HRegion r : t.getRegionServer().getOnlineRegionsLocalContext()) { 733 executeFlush(r); 734 } 735 } 736 } 737 738 /** 739 * Call flushCache on all regions of the specified table. 740 */ 741 public void flushcache(TableName tableName) throws IOException { 742 for (JVMClusterUtil.RegionServerThread t : this.hbaseCluster.getRegionServers()) { 743 for (HRegion r : t.getRegionServer().getOnlineRegionsLocalContext()) { 744 if (r.getTableDescriptor().getTableName().equals(tableName)) { 745 executeFlush(r); 746 } 747 } 748 } 749 } 750 751 /** 752 * Call flushCache on all regions on all participating regionservers. 753 */ 754 public void compact(boolean major) throws IOException { 755 for (JVMClusterUtil.RegionServerThread t : this.hbaseCluster.getRegionServers()) { 756 for (HRegion r : t.getRegionServer().getOnlineRegionsLocalContext()) { 757 if (RegionReplicaUtil.isDefaultReplica(r.getRegionInfo())) { 758 r.compact(major); 759 } 760 } 761 } 762 } 763 764 /** 765 * Call flushCache on all regions of the specified table. 766 */ 767 public void compact(TableName tableName, boolean major) throws IOException { 768 for (JVMClusterUtil.RegionServerThread t : this.hbaseCluster.getRegionServers()) { 769 for (HRegion r : t.getRegionServer().getOnlineRegionsLocalContext()) { 770 if (r.getTableDescriptor().getTableName().equals(tableName)) { 771 if (RegionReplicaUtil.isDefaultReplica(r.getRegionInfo())) { 772 r.compact(major); 773 } 774 } 775 } 776 } 777 } 778 779 /** Returns Number of live region servers in the cluster currently. */ 780 public int getNumLiveRegionServers() { 781 return this.hbaseCluster.getLiveRegionServers().size(); 782 } 783 784 /** 785 * @return List of region server threads. Does not return the master even though it is also a 786 * region server. 787 */ 788 public List<JVMClusterUtil.RegionServerThread> getRegionServerThreads() { 789 return this.hbaseCluster.getRegionServers(); 790 } 791 792 /** Returns List of live region server threads (skips the aborted and the killed) */ 793 public List<JVMClusterUtil.RegionServerThread> getLiveRegionServerThreads() { 794 return this.hbaseCluster.getLiveRegionServers(); 795 } 796 797 /** 798 * Grab a numbered region server of your choice. 799 * @return region server 800 */ 801 public HRegionServer getRegionServer(int serverNumber) { 802 return hbaseCluster.getRegionServer(serverNumber); 803 } 804 805 public HRegionServer getRegionServer(ServerName serverName) { 806 return hbaseCluster.getRegionServers().stream().map(t -> t.getRegionServer()) 807 .filter(r -> r.getServerName().equals(serverName)).findFirst().orElse(null); 808 } 809 810 public List<HRegion> getRegions(byte[] tableName) { 811 return getRegions(TableName.valueOf(tableName)); 812 } 813 814 public List<HRegion> getRegions(TableName tableName) { 815 List<HRegion> ret = new ArrayList<>(); 816 for (JVMClusterUtil.RegionServerThread rst : getRegionServerThreads()) { 817 HRegionServer hrs = rst.getRegionServer(); 818 for (Region region : hrs.getOnlineRegionsLocalContext()) { 819 if (region.getTableDescriptor().getTableName().equals(tableName)) { 820 ret.add((HRegion) region); 821 } 822 } 823 } 824 return ret; 825 } 826 827 /** 828 * @return Index into List of {@link MiniHBaseCluster#getRegionServerThreads()} of HRS carrying 829 * regionName. Returns -1 if none found. 830 */ 831 public int getServerWithMeta() { 832 return getServerWith(HRegionInfo.FIRST_META_REGIONINFO.getRegionName()); 833 } 834 835 /** 836 * Get the location of the specified region 837 * @param regionName Name of the region in bytes 838 * @return Index into List of {@link MiniHBaseCluster#getRegionServerThreads()} of HRS carrying 839 * hbase:meta. Returns -1 if none found. 840 */ 841 public int getServerWith(byte[] regionName) { 842 int index = -1; 843 int count = 0; 844 for (JVMClusterUtil.RegionServerThread rst : getRegionServerThreads()) { 845 HRegionServer hrs = rst.getRegionServer(); 846 if (!hrs.isStopped()) { 847 Region region = hrs.getOnlineRegion(regionName); 848 if (region != null) { 849 index = count; 850 break; 851 } 852 } 853 count++; 854 } 855 return index; 856 } 857 858 @Override 859 public ServerName getServerHoldingRegion(final TableName tn, byte[] regionName) 860 throws IOException { 861 // Assume there is only one master thread which is the active master. 862 // If there are multiple master threads, the backup master threads 863 // should hold some regions. Please refer to #countServedRegions 864 // to see how we find out all regions. 865 HMaster master = getMaster(); 866 Region region = master.getOnlineRegion(regionName); 867 if (region != null) { 868 return master.getServerName(); 869 } 870 int index = getServerWith(regionName); 871 if (index < 0) { 872 return null; 873 } 874 return getRegionServer(index).getServerName(); 875 } 876 877 /** 878 * Counts the total numbers of regions being served by the currently online region servers by 879 * asking each how many regions they have. Does not look at hbase:meta at all. Count includes 880 * catalog tables. 881 * @return number of regions being served by all region servers 882 */ 883 public long countServedRegions() { 884 long count = 0; 885 for (JVMClusterUtil.RegionServerThread rst : getLiveRegionServerThreads()) { 886 count += rst.getRegionServer().getNumberOfOnlineRegions(); 887 } 888 for (JVMClusterUtil.MasterThread mt : getLiveMasterThreads()) { 889 count += mt.getMaster().getNumberOfOnlineRegions(); 890 } 891 return count; 892 } 893 894 /** 895 * Do a simulated kill all masters and regionservers. Useful when it is impossible to bring the 896 * mini-cluster back for clean shutdown. 897 */ 898 public void killAll() { 899 // Do backups first. 900 MasterThread activeMaster = null; 901 for (MasterThread masterThread : getMasterThreads()) { 902 if (!masterThread.getMaster().isActiveMaster()) { 903 masterThread.getMaster().abort("killAll"); 904 } else { 905 activeMaster = masterThread; 906 } 907 } 908 // Do active after. 909 if (activeMaster != null) { 910 activeMaster.getMaster().abort("killAll"); 911 } 912 for (RegionServerThread rst : getRegionServerThreads()) { 913 rst.getRegionServer().abort("killAll"); 914 } 915 } 916 917 @Override 918 public void waitUntilShutDown() { 919 this.hbaseCluster.join(); 920 } 921 922 public List<HRegion> findRegionsForTable(TableName tableName) { 923 ArrayList<HRegion> ret = new ArrayList<>(); 924 for (JVMClusterUtil.RegionServerThread rst : getRegionServerThreads()) { 925 HRegionServer hrs = rst.getRegionServer(); 926 for (Region region : hrs.getRegions(tableName)) { 927 if (region.getTableDescriptor().getTableName().equals(tableName)) { 928 ret.add((HRegion) region); 929 } 930 } 931 } 932 return ret; 933 } 934 935 protected int getRegionServerIndex(ServerName serverName) { 936 // we have a small number of region servers, this should be fine for now. 937 List<RegionServerThread> servers = getRegionServerThreads(); 938 for (int i = 0; i < servers.size(); i++) { 939 if (servers.get(i).getRegionServer().getServerName().equals(serverName)) { 940 return i; 941 } 942 } 943 return -1; 944 } 945 946 protected int getMasterIndex(ServerName serverName) { 947 List<MasterThread> masters = getMasterThreads(); 948 for (int i = 0; i < masters.size(); i++) { 949 if (masters.get(i).getMaster().getServerName().equals(serverName)) { 950 return i; 951 } 952 } 953 return -1; 954 } 955 956 @Override 957 public AdminService.BlockingInterface getAdminProtocol(ServerName serverName) throws IOException { 958 return getRegionServer(getRegionServerIndex(serverName)).getRSRpcServices(); 959 } 960 961 @Override 962 public ClientService.BlockingInterface getClientProtocol(ServerName serverName) 963 throws IOException { 964 return getRegionServer(getRegionServerIndex(serverName)).getRSRpcServices(); 965 } 966}