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