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 static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022import static org.junit.Assert.fail; 023 024import edu.umd.cs.findbugs.annotations.Nullable; 025import java.io.File; 026import java.io.IOException; 027import java.io.OutputStream; 028import java.lang.reflect.Field; 029import java.lang.reflect.Modifier; 030import java.net.BindException; 031import java.net.DatagramSocket; 032import java.net.InetAddress; 033import java.net.ServerSocket; 034import java.net.Socket; 035import java.net.UnknownHostException; 036import java.nio.charset.StandardCharsets; 037import java.security.MessageDigest; 038import java.util.ArrayList; 039import java.util.Arrays; 040import java.util.Collection; 041import java.util.Collections; 042import java.util.HashSet; 043import java.util.Iterator; 044import java.util.List; 045import java.util.Map; 046import java.util.NavigableSet; 047import java.util.Properties; 048import java.util.Random; 049import java.util.Set; 050import java.util.TreeSet; 051import java.util.concurrent.TimeUnit; 052import java.util.concurrent.atomic.AtomicReference; 053import java.util.stream.Collectors; 054import org.apache.commons.io.FileUtils; 055import org.apache.commons.lang3.RandomStringUtils; 056import org.apache.commons.logging.impl.Jdk14Logger; 057import org.apache.commons.logging.impl.Log4JLogger; 058import org.apache.hadoop.conf.Configuration; 059import org.apache.hadoop.fs.FileSystem; 060import org.apache.hadoop.fs.Path; 061import org.apache.hadoop.hbase.Waiter.ExplainingPredicate; 062import org.apache.hadoop.hbase.Waiter.Predicate; 063import org.apache.hadoop.hbase.client.Admin; 064import org.apache.hadoop.hbase.client.BufferedMutator; 065import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 066import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 067import org.apache.hadoop.hbase.client.Connection; 068import org.apache.hadoop.hbase.client.ConnectionFactory; 069import org.apache.hadoop.hbase.client.Consistency; 070import org.apache.hadoop.hbase.client.Delete; 071import org.apache.hadoop.hbase.client.Durability; 072import org.apache.hadoop.hbase.client.Get; 073import org.apache.hadoop.hbase.client.HBaseAdmin; 074import org.apache.hadoop.hbase.client.Hbck; 075import org.apache.hadoop.hbase.client.ImmutableHRegionInfo; 076import org.apache.hadoop.hbase.client.ImmutableHTableDescriptor; 077import org.apache.hadoop.hbase.client.Put; 078import org.apache.hadoop.hbase.client.RegionInfo; 079import org.apache.hadoop.hbase.client.RegionInfoBuilder; 080import org.apache.hadoop.hbase.client.RegionLocator; 081import org.apache.hadoop.hbase.client.Result; 082import org.apache.hadoop.hbase.client.ResultScanner; 083import org.apache.hadoop.hbase.client.Scan; 084import org.apache.hadoop.hbase.client.Table; 085import org.apache.hadoop.hbase.client.TableDescriptor; 086import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 087import org.apache.hadoop.hbase.client.TableState; 088import org.apache.hadoop.hbase.fs.HFileSystem; 089import org.apache.hadoop.hbase.io.compress.Compression; 090import org.apache.hadoop.hbase.io.compress.Compression.Algorithm; 091import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; 092import org.apache.hadoop.hbase.io.hfile.BlockCache; 093import org.apache.hadoop.hbase.io.hfile.ChecksumUtil; 094import org.apache.hadoop.hbase.io.hfile.HFile; 095import org.apache.hadoop.hbase.ipc.RpcServerInterface; 096import org.apache.hadoop.hbase.ipc.ServerNotRunningYetException; 097import org.apache.hadoop.hbase.mapreduce.MapreduceTestingShim; 098import org.apache.hadoop.hbase.master.HMaster; 099import org.apache.hadoop.hbase.master.RegionState; 100import org.apache.hadoop.hbase.master.ServerManager; 101import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 102import org.apache.hadoop.hbase.master.assignment.AssignmentTestingUtil; 103import org.apache.hadoop.hbase.master.assignment.RegionStateStore; 104import org.apache.hadoop.hbase.master.assignment.RegionStates; 105import org.apache.hadoop.hbase.mob.MobFileCache; 106import org.apache.hadoop.hbase.regionserver.BloomType; 107import org.apache.hadoop.hbase.regionserver.ChunkCreator; 108import org.apache.hadoop.hbase.regionserver.HRegion; 109import org.apache.hadoop.hbase.regionserver.HRegionServer; 110import org.apache.hadoop.hbase.regionserver.HStore; 111import org.apache.hadoop.hbase.regionserver.InternalScanner; 112import org.apache.hadoop.hbase.regionserver.MemStoreLAB; 113import org.apache.hadoop.hbase.regionserver.Region; 114import org.apache.hadoop.hbase.regionserver.RegionScanner; 115import org.apache.hadoop.hbase.regionserver.RegionServerServices; 116import org.apache.hadoop.hbase.regionserver.RegionServerStoppedException; 117import org.apache.hadoop.hbase.security.HBaseKerberosUtils; 118import org.apache.hadoop.hbase.security.User; 119import org.apache.hadoop.hbase.security.visibility.VisibilityLabelsCache; 120import org.apache.hadoop.hbase.trace.TraceUtil; 121import org.apache.hadoop.hbase.util.Bytes; 122import org.apache.hadoop.hbase.util.CommonFSUtils; 123import org.apache.hadoop.hbase.util.FSTableDescriptors; 124import org.apache.hadoop.hbase.util.FSUtils; 125import org.apache.hadoop.hbase.util.JVMClusterUtil; 126import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread; 127import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; 128import org.apache.hadoop.hbase.util.Pair; 129import org.apache.hadoop.hbase.util.RegionSplitter; 130import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm; 131import org.apache.hadoop.hbase.util.RetryCounter; 132import org.apache.hadoop.hbase.util.Threads; 133import org.apache.hadoop.hbase.wal.WAL; 134import org.apache.hadoop.hbase.wal.WALFactory; 135import org.apache.hadoop.hbase.zookeeper.EmptyWatcher; 136import org.apache.hadoop.hbase.zookeeper.ZKConfig; 137import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 138import org.apache.hadoop.hdfs.DFSClient; 139import org.apache.hadoop.hdfs.DistributedFileSystem; 140import org.apache.hadoop.hdfs.MiniDFSCluster; 141import org.apache.hadoop.hdfs.server.namenode.EditLogFileOutputStream; 142import org.apache.hadoop.mapred.JobConf; 143import org.apache.hadoop.mapred.MiniMRCluster; 144import org.apache.hadoop.mapred.TaskLog; 145import org.apache.hadoop.minikdc.MiniKdc; 146import org.apache.log4j.LogManager; 147import org.apache.yetus.audience.InterfaceAudience; 148import org.apache.zookeeper.WatchedEvent; 149import org.apache.zookeeper.ZooKeeper; 150import org.apache.zookeeper.ZooKeeper.States; 151import org.slf4j.Logger; 152import org.slf4j.LoggerFactory; 153import org.slf4j.impl.Log4jLoggerAdapter; 154 155import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 156 157/** 158 * Facility for testing HBase. Replacement for 159 * old HBaseTestCase and HBaseClusterTestCase functionality. 160 * Create an instance and keep it around testing HBase. This class is 161 * meant to be your one-stop shop for anything you might need testing. Manages 162 * one cluster at a time only. Managed cluster can be an in-process 163 * {@link MiniHBaseCluster}, or a deployed cluster of type {@code DistributedHBaseCluster}. 164 * Not all methods work with the real cluster. 165 * Depends on log4j being on classpath and 166 * hbase-site.xml for logging and test-run configuration. It does not set 167 * logging levels. 168 * In the configuration properties, default values for master-info-port and 169 * region-server-port are overridden such that a random port will be assigned (thus 170 * avoiding port contention if another local HBase instance is already running). 171 * <p>To preserve test data directories, pass the system property "hbase.testing.preserve.testdir" 172 * setting it to true. 173 */ 174@InterfaceAudience.Public 175@SuppressWarnings("deprecation") 176public class HBaseTestingUtility extends HBaseZKTestingUtility { 177 178 /** 179 * System property key to get test directory value. Name is as it is because mini dfs has 180 * hard-codings to put test data here. It should NOT be used directly in HBase, as it's a property 181 * used in mini dfs. 182 * @deprecated since 2.0.0 and will be removed in 3.0.0. Can be used only with mini dfs. 183 * @see <a href="https://issues.apache.org/jira/browse/HBASE-19410">HBASE-19410</a> 184 */ 185 @Deprecated 186 private static final String TEST_DIRECTORY_KEY = "test.build.data"; 187 188 public static final String REGIONS_PER_SERVER_KEY = "hbase.test.regions-per-server"; 189 /** 190 * The default number of regions per regionserver when creating a pre-split 191 * table. 192 */ 193 public static final int DEFAULT_REGIONS_PER_SERVER = 3; 194 195 196 public static final String PRESPLIT_TEST_TABLE_KEY = "hbase.test.pre-split-table"; 197 public static final boolean PRESPLIT_TEST_TABLE = true; 198 199 private MiniDFSCluster dfsCluster = null; 200 201 private volatile HBaseCluster hbaseCluster = null; 202 private MiniMRCluster mrCluster = null; 203 204 /** If there is a mini cluster running for this testing utility instance. */ 205 private volatile boolean miniClusterRunning; 206 207 private String hadoopLogDir; 208 209 /** Directory on test filesystem where we put the data for this instance of 210 * HBaseTestingUtility*/ 211 private Path dataTestDirOnTestFS = null; 212 213 /** 214 * Shared cluster connection. 215 */ 216 private volatile Connection connection; 217 218 /** Filesystem URI used for map-reduce mini-cluster setup */ 219 private static String FS_URI; 220 221 /** This is for unit tests parameterized with a single boolean. */ 222 public static final List<Object[]> MEMSTORETS_TAGS_PARAMETRIZED = memStoreTSAndTagsCombination(); 223 224 /** 225 * Checks to see if a specific port is available. 226 * 227 * @param port the port number to check for availability 228 * @return <tt>true</tt> if the port is available, or <tt>false</tt> if not 229 */ 230 public static boolean available(int port) { 231 ServerSocket ss = null; 232 DatagramSocket ds = null; 233 try { 234 ss = new ServerSocket(port); 235 ss.setReuseAddress(true); 236 ds = new DatagramSocket(port); 237 ds.setReuseAddress(true); 238 return true; 239 } catch (IOException e) { 240 // Do nothing 241 } finally { 242 if (ds != null) { 243 ds.close(); 244 } 245 246 if (ss != null) { 247 try { 248 ss.close(); 249 } catch (IOException e) { 250 /* should not be thrown */ 251 } 252 } 253 } 254 255 return false; 256 } 257 258 /** 259 * Create all combinations of Bloom filters and compression algorithms for 260 * testing. 261 */ 262 private static List<Object[]> bloomAndCompressionCombinations() { 263 List<Object[]> configurations = new ArrayList<>(); 264 for (Compression.Algorithm comprAlgo : 265 HBaseCommonTestingUtility.COMPRESSION_ALGORITHMS) { 266 for (BloomType bloomType : BloomType.values()) { 267 configurations.add(new Object[] { comprAlgo, bloomType }); 268 } 269 } 270 return Collections.unmodifiableList(configurations); 271 } 272 273 /** 274 * Create combination of memstoreTS and tags 275 */ 276 private static List<Object[]> memStoreTSAndTagsCombination() { 277 List<Object[]> configurations = new ArrayList<>(); 278 configurations.add(new Object[] { false, false }); 279 configurations.add(new Object[] { false, true }); 280 configurations.add(new Object[] { true, false }); 281 configurations.add(new Object[] { true, true }); 282 return Collections.unmodifiableList(configurations); 283 } 284 285 public static List<Object[]> memStoreTSTagsAndOffheapCombination() { 286 List<Object[]> configurations = new ArrayList<>(); 287 configurations.add(new Object[] { false, false, true }); 288 configurations.add(new Object[] { false, false, false }); 289 configurations.add(new Object[] { false, true, true }); 290 configurations.add(new Object[] { false, true, false }); 291 configurations.add(new Object[] { true, false, true }); 292 configurations.add(new Object[] { true, false, false }); 293 configurations.add(new Object[] { true, true, true }); 294 configurations.add(new Object[] { true, true, false }); 295 return Collections.unmodifiableList(configurations); 296 } 297 298 public static final Collection<Object[]> BLOOM_AND_COMPRESSION_COMBINATIONS = 299 bloomAndCompressionCombinations(); 300 301 302 /** 303 * <p>Create an HBaseTestingUtility using a default configuration. 304 * 305 * <p>Initially, all tmp files are written to a local test data directory. 306 * Once {@link #startMiniDFSCluster} is called, either directly or via 307 * {@link #startMiniCluster()}, tmp data will be written to the DFS directory instead. 308 * 309 * <p>Previously, there was a distinction between the type of utility returned by 310 * {@link #createLocalHTU()} and this constructor; this is no longer the case. All 311 * HBaseTestingUtility objects will behave as local until a DFS cluster is started, 312 * at which point they will switch to using mini DFS for storage. 313 */ 314 public HBaseTestingUtility() { 315 this(HBaseConfiguration.create()); 316 } 317 318 /** 319 * <p>Create an HBaseTestingUtility using a given configuration. 320 * 321 * <p>Initially, all tmp files are written to a local test data directory. 322 * Once {@link #startMiniDFSCluster} is called, either directly or via 323 * {@link #startMiniCluster()}, tmp data will be written to the DFS directory instead. 324 * 325 * <p>Previously, there was a distinction between the type of utility returned by 326 * {@link #createLocalHTU()} and this constructor; this is no longer the case. All 327 * HBaseTestingUtility objects will behave as local until a DFS cluster is started, 328 * at which point they will switch to using mini DFS for storage. 329 * 330 * @param conf The configuration to use for further operations 331 */ 332 public HBaseTestingUtility(@Nullable Configuration conf) { 333 super(conf); 334 335 // a hbase checksum verification failure will cause unit tests to fail 336 ChecksumUtil.generateExceptionForChecksumFailureForTest(true); 337 338 // Save this for when setting default file:// breaks things 339 if (this.conf.get("fs.defaultFS") != null) { 340 this.conf.set("original.defaultFS", this.conf.get("fs.defaultFS")); 341 } 342 if (this.conf.get(HConstants.HBASE_DIR) != null) { 343 this.conf.set("original.hbase.dir", this.conf.get(HConstants.HBASE_DIR)); 344 } 345 // Every cluster is a local cluster until we start DFS 346 // Note that conf could be null, but this.conf will not be 347 String dataTestDir = getDataTestDir().toString(); 348 this.conf.set("fs.defaultFS","file:///"); 349 this.conf.set(HConstants.HBASE_DIR, "file://" + dataTestDir); 350 LOG.debug("Setting {} to {}", HConstants.HBASE_DIR, dataTestDir); 351 this.conf.setBoolean(CommonFSUtils.UNSAFE_STREAM_CAPABILITY_ENFORCE,false); 352 // If the value for random ports isn't set set it to true, thus making 353 // tests opt-out for random port assignment 354 this.conf.setBoolean(LocalHBaseCluster.ASSIGN_RANDOM_PORTS, 355 this.conf.getBoolean(LocalHBaseCluster.ASSIGN_RANDOM_PORTS, true)); 356 } 357 358 /** 359 * @deprecated since 2.0.0 and will be removed in 3.0.0. Use {@link #HBaseTestingUtility()} 360 * instead. 361 * @return a normal HBaseTestingUtility 362 * @see #HBaseTestingUtility() 363 * @see <a href="https://issues.apache.org/jira/browse/HBASE-19841">HBASE-19841</a> 364 */ 365 @Deprecated 366 public static HBaseTestingUtility createLocalHTU() { 367 return new HBaseTestingUtility(); 368 } 369 370 /** 371 * @deprecated since 2.0.0 and will be removed in 3.0.0. Use 372 * {@link #HBaseTestingUtility(Configuration)} instead. 373 * @return a normal HBaseTestingUtility 374 * @see #HBaseTestingUtility(Configuration) 375 * @see <a href="https://issues.apache.org/jira/browse/HBASE-19841">HBASE-19841</a> 376 */ 377 @Deprecated 378 public static HBaseTestingUtility createLocalHTU(Configuration c) { 379 return new HBaseTestingUtility(c); 380 } 381 382 /** 383 * Close both the region {@code r} and it's underlying WAL. For use in tests. 384 */ 385 public static void closeRegionAndWAL(final Region r) throws IOException { 386 closeRegionAndWAL((HRegion)r); 387 } 388 389 /** 390 * Close both the HRegion {@code r} and it's underlying WAL. For use in tests. 391 */ 392 public static void closeRegionAndWAL(final HRegion r) throws IOException { 393 if (r == null) return; 394 r.close(); 395 if (r.getWAL() == null) return; 396 r.getWAL().close(); 397 } 398 399 /** 400 * Returns this classes's instance of {@link Configuration}. Be careful how 401 * you use the returned Configuration since {@link Connection} instances 402 * can be shared. The Map of Connections is keyed by the Configuration. If 403 * say, a Connection was being used against a cluster that had been shutdown, 404 * see {@link #shutdownMiniCluster()}, then the Connection will no longer 405 * be wholesome. Rather than use the return direct, its usually best to 406 * make a copy and use that. Do 407 * <code>Configuration c = new Configuration(INSTANCE.getConfiguration());</code> 408 * @return Instance of Configuration. 409 */ 410 @Override 411 public Configuration getConfiguration() { 412 return super.getConfiguration(); 413 } 414 415 public void setHBaseCluster(HBaseCluster hbaseCluster) { 416 this.hbaseCluster = hbaseCluster; 417 } 418 419 /** 420 * Home our data in a dir under {@link #DEFAULT_BASE_TEST_DIRECTORY}. 421 * Give it a random name so can have many concurrent tests running if 422 * we need to. It needs to amend the {@link #TEST_DIRECTORY_KEY} 423 * System property, as it's what minidfscluster bases 424 * it data dir on. Moding a System property is not the way to do concurrent 425 * instances -- another instance could grab the temporary 426 * value unintentionally -- but not anything can do about it at moment; 427 * single instance only is how the minidfscluster works. 428 * 429 * We also create the underlying directory for 430 * hadoop.log.dir, mapreduce.cluster.local.dir and hadoop.tmp.dir, and set the values 431 * in the conf, and as a system property for hadoop.tmp.dir 432 * 433 * @return The calculated data test build directory, if newly-created. 434 */ 435 @Override 436 protected Path setupDataTestDir() { 437 Path testPath = super.setupDataTestDir(); 438 if (null == testPath) { 439 return null; 440 } 441 442 createSubDirAndSystemProperty( 443 "hadoop.log.dir", 444 testPath, "hadoop-log-dir"); 445 446 // This is defaulted in core-default.xml to /tmp/hadoop-${user.name}, but 447 // we want our own value to ensure uniqueness on the same machine 448 createSubDirAndSystemProperty( 449 "hadoop.tmp.dir", 450 testPath, "hadoop-tmp-dir"); 451 452 // Read and modified in org.apache.hadoop.mapred.MiniMRCluster 453 createSubDir( 454 "mapreduce.cluster.local.dir", 455 testPath, "mapred-local-dir"); 456 return testPath; 457 } 458 459 private void createSubDirAndSystemProperty( 460 String propertyName, Path parent, String subDirName){ 461 462 String sysValue = System.getProperty(propertyName); 463 464 if (sysValue != null) { 465 // There is already a value set. So we do nothing but hope 466 // that there will be no conflicts 467 LOG.info("System.getProperty(\""+propertyName+"\") already set to: "+ 468 sysValue + " so I do NOT create it in " + parent); 469 String confValue = conf.get(propertyName); 470 if (confValue != null && !confValue.endsWith(sysValue)){ 471 LOG.warn( 472 propertyName + " property value differs in configuration and system: "+ 473 "Configuration="+confValue+" while System="+sysValue+ 474 " Erasing configuration value by system value." 475 ); 476 } 477 conf.set(propertyName, sysValue); 478 } else { 479 // Ok, it's not set, so we create it as a subdirectory 480 createSubDir(propertyName, parent, subDirName); 481 System.setProperty(propertyName, conf.get(propertyName)); 482 } 483 } 484 485 /** 486 * @return Where to write test data on the test filesystem; Returns working directory 487 * for the test filesystem by default 488 * @see #setupDataTestDirOnTestFS() 489 * @see #getTestFileSystem() 490 */ 491 private Path getBaseTestDirOnTestFS() throws IOException { 492 FileSystem fs = getTestFileSystem(); 493 return new Path(fs.getWorkingDirectory(), "test-data"); 494 } 495 496 /** 497 * @return META table descriptor 498 * @deprecated since 2.0 version and will be removed in 3.0 version. 499 * use {@link #getMetaTableDescriptorBuilder()} 500 */ 501 @Deprecated 502 public HTableDescriptor getMetaTableDescriptor() { 503 return new ImmutableHTableDescriptor(getMetaTableDescriptorBuilder().build()); 504 } 505 506 /** 507 * @return META table descriptor 508 */ 509 public TableDescriptorBuilder getMetaTableDescriptorBuilder() { 510 try { 511 return FSTableDescriptors.createMetaTableDescriptorBuilder(conf); 512 } catch (IOException e) { 513 throw new RuntimeException("Unable to create META table descriptor", e); 514 } 515 } 516 517 /** 518 * Returns a Path in the test filesystem, obtained from {@link #getTestFileSystem()} 519 * to write temporary test data. Call this method after setting up the mini dfs cluster 520 * if the test relies on it. 521 * @return a unique path in the test filesystem 522 */ 523 public Path getDataTestDirOnTestFS() throws IOException { 524 if (dataTestDirOnTestFS == null) { 525 setupDataTestDirOnTestFS(); 526 } 527 528 return dataTestDirOnTestFS; 529 } 530 531 /** 532 * Returns a Path in the test filesystem, obtained from {@link #getTestFileSystem()} 533 * to write temporary test data. Call this method after setting up the mini dfs cluster 534 * if the test relies on it. 535 * @return a unique path in the test filesystem 536 * @param subdirName name of the subdir to create under the base test dir 537 */ 538 public Path getDataTestDirOnTestFS(final String subdirName) throws IOException { 539 return new Path(getDataTestDirOnTestFS(), subdirName); 540 } 541 542 /** 543 * Sets up a path in test filesystem to be used by tests. 544 * Creates a new directory if not already setup. 545 */ 546 private void setupDataTestDirOnTestFS() throws IOException { 547 if (dataTestDirOnTestFS != null) { 548 LOG.warn("Data test on test fs dir already setup in " 549 + dataTestDirOnTestFS.toString()); 550 return; 551 } 552 dataTestDirOnTestFS = getNewDataTestDirOnTestFS(); 553 } 554 555 /** 556 * Sets up a new path in test filesystem to be used by tests. 557 */ 558 private Path getNewDataTestDirOnTestFS() throws IOException { 559 //The file system can be either local, mini dfs, or if the configuration 560 //is supplied externally, it can be an external cluster FS. If it is a local 561 //file system, the tests should use getBaseTestDir, otherwise, we can use 562 //the working directory, and create a unique sub dir there 563 FileSystem fs = getTestFileSystem(); 564 Path newDataTestDir; 565 String randomStr = getRandomUUID().toString(); 566 if (fs.getUri().getScheme().equals(FileSystem.getLocal(conf).getUri().getScheme())) { 567 newDataTestDir = new Path(getDataTestDir(), randomStr); 568 File dataTestDir = new File(newDataTestDir.toString()); 569 if (deleteOnExit()) dataTestDir.deleteOnExit(); 570 } else { 571 Path base = getBaseTestDirOnTestFS(); 572 newDataTestDir = new Path(base, randomStr); 573 if (deleteOnExit()) fs.deleteOnExit(newDataTestDir); 574 } 575 return newDataTestDir; 576 } 577 578 /** 579 * Cleans the test data directory on the test filesystem. 580 * @return True if we removed the test dirs 581 * @throws IOException 582 */ 583 public boolean cleanupDataTestDirOnTestFS() throws IOException { 584 boolean ret = getTestFileSystem().delete(dataTestDirOnTestFS, true); 585 if (ret) 586 dataTestDirOnTestFS = null; 587 return ret; 588 } 589 590 /** 591 * Cleans a subdirectory under the test data directory on the test filesystem. 592 * @return True if we removed child 593 * @throws IOException 594 */ 595 public boolean cleanupDataTestDirOnTestFS(String subdirName) throws IOException { 596 Path cpath = getDataTestDirOnTestFS(subdirName); 597 return getTestFileSystem().delete(cpath, true); 598 } 599 600 /** 601 * Start a minidfscluster. 602 * @param servers How many DNs to start. 603 * @throws Exception 604 * @see #shutdownMiniDFSCluster() 605 * @return The mini dfs cluster created. 606 */ 607 public MiniDFSCluster startMiniDFSCluster(int servers) throws Exception { 608 return startMiniDFSCluster(servers, null); 609 } 610 611 /** 612 * Start a minidfscluster. 613 * This is useful if you want to run datanode on distinct hosts for things 614 * like HDFS block location verification. 615 * If you start MiniDFSCluster without host names, all instances of the 616 * datanodes will have the same host name. 617 * @param hosts hostnames DNs to run on. 618 * @throws Exception 619 * @see #shutdownMiniDFSCluster() 620 * @return The mini dfs cluster created. 621 */ 622 public MiniDFSCluster startMiniDFSCluster(final String hosts[]) 623 throws Exception { 624 if ( hosts != null && hosts.length != 0) { 625 return startMiniDFSCluster(hosts.length, hosts); 626 } else { 627 return startMiniDFSCluster(1, null); 628 } 629 } 630 631 /** 632 * Start a minidfscluster. 633 * Can only create one. 634 * @param servers How many DNs to start. 635 * @param hosts hostnames DNs to run on. 636 * @throws Exception 637 * @see #shutdownMiniDFSCluster() 638 * @return The mini dfs cluster created. 639 */ 640 public MiniDFSCluster startMiniDFSCluster(int servers, final String hosts[]) 641 throws Exception { 642 return startMiniDFSCluster(servers, null, hosts); 643 } 644 645 private void setFs() throws IOException { 646 if(this.dfsCluster == null){ 647 LOG.info("Skipping setting fs because dfsCluster is null"); 648 return; 649 } 650 FileSystem fs = this.dfsCluster.getFileSystem(); 651 FSUtils.setFsDefault(this.conf, new Path(fs.getUri())); 652 653 // re-enable this check with dfs 654 conf.unset(CommonFSUtils.UNSAFE_STREAM_CAPABILITY_ENFORCE); 655 } 656 657 public MiniDFSCluster startMiniDFSCluster(int servers, final String racks[], String hosts[]) 658 throws Exception { 659 createDirsAndSetProperties(); 660 EditLogFileOutputStream.setShouldSkipFsyncForTesting(true); 661 662 // Error level to skip some warnings specific to the minicluster. See HBASE-4709 663 org.apache.log4j.Logger.getLogger(org.apache.hadoop.metrics2.util.MBeans.class). 664 setLevel(org.apache.log4j.Level.ERROR); 665 org.apache.log4j.Logger.getLogger(org.apache.hadoop.metrics2.impl.MetricsSystemImpl.class). 666 setLevel(org.apache.log4j.Level.ERROR); 667 668 TraceUtil.initTracer(conf); 669 670 this.dfsCluster = new MiniDFSCluster(0, this.conf, servers, true, true, 671 true, null, racks, hosts, null); 672 673 // Set this just-started cluster as our filesystem. 674 setFs(); 675 676 // Wait for the cluster to be totally up 677 this.dfsCluster.waitClusterUp(); 678 679 //reset the test directory for test file system 680 dataTestDirOnTestFS = null; 681 String dataTestDir = getDataTestDir().toString(); 682 conf.set(HConstants.HBASE_DIR, dataTestDir); 683 LOG.debug("Setting {} to {}", HConstants.HBASE_DIR, dataTestDir); 684 685 return this.dfsCluster; 686 } 687 688 public MiniDFSCluster startMiniDFSClusterForTestWAL(int namenodePort) throws IOException { 689 createDirsAndSetProperties(); 690 dfsCluster = new MiniDFSCluster(namenodePort, conf, 5, false, true, true, null, 691 null, null, null); 692 return dfsCluster; 693 } 694 695 /** This is used before starting HDFS and map-reduce mini-clusters 696 * Run something like the below to check for the likes of '/tmp' references -- i.e. 697 * references outside of the test data dir -- in the conf. 698 * Configuration conf = TEST_UTIL.getConfiguration(); 699 * for (Iterator<Map.Entry<String, String>> i = conf.iterator(); i.hasNext();) { 700 * Map.Entry<String, String> e = i.next(); 701 * assertFalse(e.getKey() + " " + e.getValue(), e.getValue().contains("/tmp")); 702 * } 703 */ 704 private void createDirsAndSetProperties() throws IOException { 705 setupClusterTestDir(); 706 conf.set(TEST_DIRECTORY_KEY, clusterTestDir.getPath()); 707 System.setProperty(TEST_DIRECTORY_KEY, clusterTestDir.getPath()); 708 createDirAndSetProperty("test.cache.data", "test.cache.data"); 709 createDirAndSetProperty("hadoop.tmp.dir", "hadoop.tmp.dir"); 710 hadoopLogDir = createDirAndSetProperty("hadoop.log.dir", "hadoop.log.dir"); 711 createDirAndSetProperty("mapreduce.cluster.local.dir", "mapreduce.cluster.local.dir"); 712 createDirAndSetProperty("mapreduce.cluster.temp.dir", "mapreduce.cluster.temp.dir"); 713 enableShortCircuit(); 714 715 Path root = getDataTestDirOnTestFS("hadoop"); 716 conf.set(MapreduceTestingShim.getMROutputDirProp(), 717 new Path(root, "mapred-output-dir").toString()); 718 conf.set("mapreduce.jobtracker.system.dir", new Path(root, "mapred-system-dir").toString()); 719 conf.set("mapreduce.jobtracker.staging.root.dir", 720 new Path(root, "mapreduce-jobtracker-staging-root-dir").toString()); 721 conf.set("mapreduce.job.working.dir", new Path(root, "mapred-working-dir").toString()); 722 conf.set("yarn.app.mapreduce.am.staging-dir", 723 new Path(root, "mapreduce-am-staging-root-dir").toString()); 724 725 // Frustrate yarn's and hdfs's attempts at writing /tmp. 726 // Below is fragile. Make it so we just interpolate any 'tmp' reference. 727 createDirAndSetProperty("yarn.node-labels.fs-store.root-dir"); 728 createDirAndSetProperty("yarn.nodemanager.log-dirs"); 729 createDirAndSetProperty("yarn.nodemanager.remote-app-log-dir"); 730 createDirAndSetProperty("yarn.timeline-service.entity-group-fs-store.active-dir"); 731 createDirAndSetProperty("yarn.timeline-service.entity-group-fs-store.done-dir"); 732 createDirAndSetProperty("yarn.nodemanager.remote-app-log-dir"); 733 createDirAndSetProperty("dfs.journalnode.edits.dir"); 734 createDirAndSetProperty("dfs.datanode.shared.file.descriptor.paths"); 735 createDirAndSetProperty("nfs.dump.dir"); 736 createDirAndSetProperty("java.io.tmpdir"); 737 createDirAndSetProperty("java.io.tmpdir"); 738 createDirAndSetProperty("dfs.journalnode.edits.dir"); 739 createDirAndSetProperty("dfs.provided.aliasmap.inmemory.leveldb.dir"); 740 } 741 742 /** 743 * Check whether the tests should assume NEW_VERSION_BEHAVIOR when creating 744 * new column families. Default to false. 745 */ 746 public boolean isNewVersionBehaviorEnabled(){ 747 final String propName = "hbase.tests.new.version.behavior"; 748 String v = System.getProperty(propName); 749 if (v != null){ 750 return Boolean.parseBoolean(v); 751 } 752 return false; 753 } 754 755 /** 756 * Get the HBase setting for dfs.client.read.shortcircuit from the conf or a system property. 757 * This allows to specify this parameter on the command line. 758 * If not set, default is true. 759 */ 760 public boolean isReadShortCircuitOn(){ 761 final String propName = "hbase.tests.use.shortcircuit.reads"; 762 String readOnProp = System.getProperty(propName); 763 if (readOnProp != null){ 764 return Boolean.parseBoolean(readOnProp); 765 } else { 766 return conf.getBoolean(propName, false); 767 } 768 } 769 770 /** Enable the short circuit read, unless configured differently. 771 * Set both HBase and HDFS settings, including skipping the hdfs checksum checks. 772 */ 773 private void enableShortCircuit() { 774 if (isReadShortCircuitOn()) { 775 String curUser = System.getProperty("user.name"); 776 LOG.info("read short circuit is ON for user " + curUser); 777 // read short circuit, for hdfs 778 conf.set("dfs.block.local-path-access.user", curUser); 779 // read short circuit, for hbase 780 conf.setBoolean("dfs.client.read.shortcircuit", true); 781 // Skip checking checksum, for the hdfs client and the datanode 782 conf.setBoolean("dfs.client.read.shortcircuit.skip.checksum", true); 783 } else { 784 LOG.info("read short circuit is OFF"); 785 } 786 } 787 788 private String createDirAndSetProperty(String property) { 789 return createDirAndSetProperty(property, property); 790 } 791 792 private String createDirAndSetProperty(final String relPath, String property) { 793 String path = getDataTestDir(relPath).toString(); 794 System.setProperty(property, path); 795 conf.set(property, path); 796 new File(path).mkdirs(); 797 LOG.info("Setting " + property + " to " + path + " in system properties and HBase conf"); 798 return path; 799 } 800 801 /** 802 * Shuts down instance created by call to {@link #startMiniDFSCluster(int)} 803 * or does nothing. 804 * @throws IOException 805 */ 806 public void shutdownMiniDFSCluster() throws IOException { 807 if (this.dfsCluster != null) { 808 // The below throws an exception per dn, AsynchronousCloseException. 809 this.dfsCluster.shutdown(); 810 dfsCluster = null; 811 dataTestDirOnTestFS = null; 812 FSUtils.setFsDefault(this.conf, new Path("file:///")); 813 } 814 } 815 816 /** 817 * Start up a minicluster of hbase, dfs, and zookeeper where WAL's walDir is created separately. 818 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 819 * @param createWALDir Whether to create a new WAL directory. 820 * @return The mini HBase cluster created. 821 * @see #shutdownMiniCluster() 822 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 823 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 824 * @see #startMiniCluster(StartMiniClusterOption) 825 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 826 */ 827 @Deprecated 828 public MiniHBaseCluster startMiniCluster(boolean createWALDir) throws Exception { 829 StartMiniClusterOption option = StartMiniClusterOption.builder() 830 .createWALDir(createWALDir).build(); 831 return startMiniCluster(option); 832 } 833 834 /** 835 * Start up a minicluster of hbase, dfs, and zookeeper. 836 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 837 * @param numSlaves Slave node number, for both HBase region server and HDFS data node. 838 * @param createRootDir Whether to create a new root or data directory path. 839 * @return The mini HBase cluster created. 840 * @see #shutdownMiniCluster() 841 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 842 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 843 * @see #startMiniCluster(StartMiniClusterOption) 844 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 845 */ 846 @Deprecated 847 public MiniHBaseCluster startMiniCluster(int numSlaves, boolean createRootDir) 848 throws Exception { 849 StartMiniClusterOption option = StartMiniClusterOption.builder() 850 .numRegionServers(numSlaves).numDataNodes(numSlaves).createRootDir(createRootDir).build(); 851 return startMiniCluster(option); 852 } 853 854 /** 855 * Start up a minicluster of hbase, dfs, and zookeeper. 856 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 857 * @param numSlaves Slave node number, for both HBase region server and HDFS data node. 858 * @param createRootDir Whether to create a new root or data directory path. 859 * @param createWALDir Whether to create a new WAL directory. 860 * @return The mini HBase cluster created. 861 * @see #shutdownMiniCluster() 862 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 863 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 864 * @see #startMiniCluster(StartMiniClusterOption) 865 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 866 */ 867 @Deprecated 868 public MiniHBaseCluster startMiniCluster(int numSlaves, boolean createRootDir, 869 boolean createWALDir) throws Exception { 870 StartMiniClusterOption option = StartMiniClusterOption.builder() 871 .numRegionServers(numSlaves).numDataNodes(numSlaves).createRootDir(createRootDir) 872 .createWALDir(createWALDir).build(); 873 return startMiniCluster(option); 874 } 875 876 /** 877 * Start up a minicluster of hbase, dfs, and zookeeper. 878 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 879 * @param numMasters Master node number. 880 * @param numSlaves Slave node number, for both HBase region server and HDFS data node. 881 * @param createRootDir Whether to create a new root or data directory path. 882 * @return The mini HBase cluster created. 883 * @see #shutdownMiniCluster() 884 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 885 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 886 * @see #startMiniCluster(StartMiniClusterOption) 887 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 888 */ 889 @Deprecated 890 public MiniHBaseCluster startMiniCluster(int numMasters, int numSlaves, boolean createRootDir) 891 throws Exception { 892 StartMiniClusterOption option = StartMiniClusterOption.builder() 893 .numMasters(numMasters).numRegionServers(numSlaves).createRootDir(createRootDir) 894 .numDataNodes(numSlaves).build(); 895 return startMiniCluster(option); 896 } 897 898 /** 899 * Start up a minicluster of hbase, dfs, and zookeeper. 900 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 901 * @param numMasters Master node number. 902 * @param numSlaves Slave node number, for both HBase region server and HDFS data node. 903 * @return The mini HBase cluster created. 904 * @see #shutdownMiniCluster() 905 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 906 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 907 * @see #startMiniCluster(StartMiniClusterOption) 908 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 909 */ 910 @Deprecated 911 public MiniHBaseCluster startMiniCluster(int numMasters, int numSlaves) throws Exception { 912 StartMiniClusterOption option = StartMiniClusterOption.builder() 913 .numMasters(numMasters).numRegionServers(numSlaves).numDataNodes(numSlaves).build(); 914 return startMiniCluster(option); 915 } 916 917 /** 918 * Start up a minicluster of hbase, dfs, and zookeeper. 919 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 920 * @param numMasters Master node number. 921 * @param numSlaves Slave node number, for both HBase region server and HDFS data node. 922 * @param dataNodeHosts The hostnames of DataNodes to run on. If not null, its size will overwrite 923 * HDFS data node number. 924 * @param createRootDir Whether to create a new root or data directory path. 925 * @return The mini HBase cluster created. 926 * @see #shutdownMiniCluster() 927 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 928 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 929 * @see #startMiniCluster(StartMiniClusterOption) 930 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 931 */ 932 @Deprecated 933 public MiniHBaseCluster startMiniCluster(int numMasters, int numSlaves, String[] dataNodeHosts, 934 boolean createRootDir) throws Exception { 935 StartMiniClusterOption option = StartMiniClusterOption.builder() 936 .numMasters(numMasters).numRegionServers(numSlaves).createRootDir(createRootDir) 937 .numDataNodes(numSlaves).dataNodeHosts(dataNodeHosts).build(); 938 return startMiniCluster(option); 939 } 940 941 /** 942 * Start up a minicluster of hbase, dfs, and zookeeper. 943 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 944 * @param numMasters Master node number. 945 * @param numSlaves Slave node number, for both HBase region server and HDFS data node. 946 * @param dataNodeHosts The hostnames of DataNodes to run on. If not null, its size will overwrite 947 * HDFS data node number. 948 * @return The mini HBase cluster created. 949 * @see #shutdownMiniCluster() 950 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 951 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 952 * @see #startMiniCluster(StartMiniClusterOption) 953 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 954 */ 955 @Deprecated 956 public MiniHBaseCluster startMiniCluster(int numMasters, int numSlaves, String[] dataNodeHosts) 957 throws Exception { 958 StartMiniClusterOption option = StartMiniClusterOption.builder() 959 .numMasters(numMasters).numRegionServers(numSlaves) 960 .numDataNodes(numSlaves).dataNodeHosts(dataNodeHosts).build(); 961 return startMiniCluster(option); 962 } 963 964 /** 965 * Start up a minicluster of hbase, dfs, and zookeeper. 966 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 967 * @param numMasters Master node number. 968 * @param numRegionServers Number of region servers. 969 * @param numDataNodes Number of datanodes. 970 * @return The mini HBase cluster created. 971 * @see #shutdownMiniCluster() 972 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 973 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 974 * @see #startMiniCluster(StartMiniClusterOption) 975 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 976 */ 977 @Deprecated 978 public MiniHBaseCluster startMiniCluster(int numMasters, int numRegionServers, int numDataNodes) 979 throws Exception { 980 StartMiniClusterOption option = StartMiniClusterOption.builder() 981 .numMasters(numMasters).numRegionServers(numRegionServers).numDataNodes(numDataNodes) 982 .build(); 983 return startMiniCluster(option); 984 } 985 986 /** 987 * Start up a minicluster of hbase, dfs, and zookeeper. 988 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 989 * @param numMasters Master node number. 990 * @param numSlaves Slave node number, for both HBase region server and HDFS data node. 991 * @param dataNodeHosts The hostnames of DataNodes to run on. If not null, its size will overwrite 992 * HDFS data node number. 993 * @param masterClass The class to use as HMaster, or null for default. 994 * @param rsClass The class to use as HRegionServer, or null for default. 995 * @return The mini HBase cluster created. 996 * @see #shutdownMiniCluster() 997 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 998 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 999 * @see #startMiniCluster(StartMiniClusterOption) 1000 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 1001 */ 1002 @Deprecated 1003 public MiniHBaseCluster startMiniCluster(int numMasters, int numSlaves, String[] dataNodeHosts, 1004 Class<? extends HMaster> masterClass, 1005 Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass) 1006 throws Exception { 1007 StartMiniClusterOption option = StartMiniClusterOption.builder() 1008 .numMasters(numMasters).masterClass(masterClass) 1009 .numRegionServers(numSlaves).rsClass(rsClass) 1010 .numDataNodes(numSlaves).dataNodeHosts(dataNodeHosts) 1011 .build(); 1012 return startMiniCluster(option); 1013 } 1014 1015 /** 1016 * Start up a minicluster of hbase, dfs, and zookeeper. 1017 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 1018 * @param numMasters Master node number. 1019 * @param numRegionServers Number of region servers. 1020 * @param numDataNodes Number of datanodes. 1021 * @param dataNodeHosts The hostnames of DataNodes to run on. If not null, its size will overwrite 1022 * HDFS data node number. 1023 * @param masterClass The class to use as HMaster, or null for default. 1024 * @param rsClass The class to use as HRegionServer, or null for default. 1025 * @return The mini HBase cluster created. 1026 * @see #shutdownMiniCluster() 1027 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 1028 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 1029 * @see #startMiniCluster(StartMiniClusterOption) 1030 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 1031 */ 1032 @Deprecated 1033 public MiniHBaseCluster startMiniCluster(int numMasters, int numRegionServers, int numDataNodes, 1034 String[] dataNodeHosts, Class<? extends HMaster> masterClass, 1035 Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass) 1036 throws Exception { 1037 StartMiniClusterOption option = StartMiniClusterOption.builder() 1038 .numMasters(numMasters).masterClass(masterClass) 1039 .numRegionServers(numRegionServers).rsClass(rsClass) 1040 .numDataNodes(numDataNodes).dataNodeHosts(dataNodeHosts) 1041 .build(); 1042 return startMiniCluster(option); 1043 } 1044 1045 /** 1046 * Start up a minicluster of hbase, dfs, and zookeeper. 1047 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 1048 * @param numMasters Master node number. 1049 * @param numRegionServers Number of region servers. 1050 * @param numDataNodes Number of datanodes. 1051 * @param dataNodeHosts The hostnames of DataNodes to run on. If not null, its size will overwrite 1052 * HDFS data node number. 1053 * @param masterClass The class to use as HMaster, or null for default. 1054 * @param rsClass The class to use as HRegionServer, or null for default. 1055 * @param createRootDir Whether to create a new root or data directory path. 1056 * @param createWALDir Whether to create a new WAL directory. 1057 * @return The mini HBase cluster created. 1058 * @see #shutdownMiniCluster() 1059 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 1060 * {@link #startMiniCluster(StartMiniClusterOption)} instead. 1061 * @see #startMiniCluster(StartMiniClusterOption) 1062 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 1063 */ 1064 @Deprecated 1065 public MiniHBaseCluster startMiniCluster(int numMasters, int numRegionServers, int numDataNodes, 1066 String[] dataNodeHosts, Class<? extends HMaster> masterClass, 1067 Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass, boolean createRootDir, 1068 boolean createWALDir) throws Exception { 1069 StartMiniClusterOption option = StartMiniClusterOption.builder() 1070 .numMasters(numMasters).masterClass(masterClass) 1071 .numRegionServers(numRegionServers).rsClass(rsClass) 1072 .numDataNodes(numDataNodes).dataNodeHosts(dataNodeHosts) 1073 .createRootDir(createRootDir).createWALDir(createWALDir) 1074 .build(); 1075 return startMiniCluster(option); 1076 } 1077 1078 /** 1079 * Start up a minicluster of hbase, dfs and zookeeper clusters with given slave node number. 1080 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 1081 * @param numSlaves slave node number, for both HBase region server and HDFS data node. 1082 * @see #startMiniCluster(StartMiniClusterOption option) 1083 * @see #shutdownMiniDFSCluster() 1084 */ 1085 public MiniHBaseCluster startMiniCluster(int numSlaves) throws Exception { 1086 StartMiniClusterOption option = StartMiniClusterOption.builder() 1087 .numRegionServers(numSlaves).numDataNodes(numSlaves).build(); 1088 return startMiniCluster(option); 1089 } 1090 1091 /** 1092 * Start up a minicluster of hbase, dfs and zookeeper all using default options. 1093 * Option default value can be found in {@link StartMiniClusterOption.Builder}. 1094 * @see #startMiniCluster(StartMiniClusterOption option) 1095 * @see #shutdownMiniDFSCluster() 1096 */ 1097 public MiniHBaseCluster startMiniCluster() throws Exception { 1098 return startMiniCluster(StartMiniClusterOption.builder().build()); 1099 } 1100 1101 /** 1102 * Start up a mini cluster of hbase, optionally dfs and zookeeper if needed. 1103 * It modifies Configuration. It homes the cluster data directory under a random 1104 * subdirectory in a directory under System property test.build.data, to be cleaned up on exit. 1105 * @see #shutdownMiniDFSCluster() 1106 */ 1107 public MiniHBaseCluster startMiniCluster(StartMiniClusterOption option) throws Exception { 1108 LOG.info("Starting up minicluster with option: {}", option); 1109 1110 // If we already put up a cluster, fail. 1111 if (miniClusterRunning) { 1112 throw new IllegalStateException("A mini-cluster is already running"); 1113 } 1114 miniClusterRunning = true; 1115 1116 setupClusterTestDir(); 1117 System.setProperty(TEST_DIRECTORY_KEY, this.clusterTestDir.getPath()); 1118 1119 // Bring up mini dfs cluster. This spews a bunch of warnings about missing 1120 // scheme. Complaints are 'Scheme is undefined for build/test/data/dfs/name1'. 1121 if (dfsCluster == null) { 1122 LOG.info("STARTING DFS"); 1123 dfsCluster = startMiniDFSCluster(option.getNumDataNodes(), option.getDataNodeHosts()); 1124 } else { 1125 LOG.info("NOT STARTING DFS"); 1126 } 1127 1128 // Start up a zk cluster. 1129 if (getZkCluster() == null) { 1130 startMiniZKCluster(option.getNumZkServers()); 1131 } 1132 1133 // Start the MiniHBaseCluster 1134 return startMiniHBaseCluster(option); 1135 } 1136 1137 /** 1138 * Starts up mini hbase cluster. 1139 * Usually you won't want this. You'll usually want {@link #startMiniCluster()}. 1140 * This is useful when doing stepped startup of clusters. 1141 * @return Reference to the hbase mini hbase cluster. 1142 * @see #startMiniCluster(StartMiniClusterOption) 1143 * @see #shutdownMiniHBaseCluster() 1144 */ 1145 public MiniHBaseCluster startMiniHBaseCluster(StartMiniClusterOption option) 1146 throws IOException, InterruptedException { 1147 // Now do the mini hbase cluster. Set the hbase.rootdir in config. 1148 createRootDir(option.isCreateRootDir()); 1149 if (option.isCreateWALDir()) { 1150 createWALRootDir(); 1151 } 1152 // Set the hbase.fs.tmp.dir config to make sure that we have some default value. This is 1153 // for tests that do not read hbase-defaults.xml 1154 setHBaseFsTmpDir(); 1155 1156 // These settings will make the server waits until this exact number of 1157 // regions servers are connected. 1158 if (conf.getInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, -1) == -1) { 1159 conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, option.getNumRegionServers()); 1160 } 1161 if (conf.getInt(ServerManager.WAIT_ON_REGIONSERVERS_MAXTOSTART, -1) == -1) { 1162 conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MAXTOSTART, option.getNumRegionServers()); 1163 } 1164 1165 Configuration c = new Configuration(this.conf); 1166 TraceUtil.initTracer(c); 1167 this.hbaseCluster = 1168 new MiniHBaseCluster(c, option.getNumMasters(), option.getNumRegionServers(), 1169 option.getRsPorts(), option.getMasterClass(), option.getRsClass()); 1170 // Don't leave here till we've done a successful scan of the hbase:meta 1171 Table t = getConnection().getTable(TableName.META_TABLE_NAME); 1172 ResultScanner s = t.getScanner(new Scan()); 1173 while (s.next() != null) { 1174 continue; 1175 } 1176 s.close(); 1177 t.close(); 1178 1179 getAdmin(); // create immediately the hbaseAdmin 1180 LOG.info("Minicluster is up; activeMaster={}", getHBaseCluster().getMaster()); 1181 1182 return (MiniHBaseCluster) hbaseCluster; 1183 } 1184 1185 /** 1186 * Starts up mini hbase cluster using default options. 1187 * Default options can be found in {@link StartMiniClusterOption.Builder}. 1188 * @see #startMiniHBaseCluster(StartMiniClusterOption) 1189 * @see #shutdownMiniHBaseCluster() 1190 */ 1191 public MiniHBaseCluster startMiniHBaseCluster() throws IOException, InterruptedException { 1192 return startMiniHBaseCluster(StartMiniClusterOption.builder().build()); 1193 } 1194 1195 /** 1196 * Starts up mini hbase cluster. 1197 * Usually you won't want this. You'll usually want {@link #startMiniCluster()}. 1198 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 1199 * @param numMasters Master node number. 1200 * @param numRegionServers Number of region servers. 1201 * @return The mini HBase cluster created. 1202 * @see #shutdownMiniHBaseCluster() 1203 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 1204 * {@link #startMiniHBaseCluster(StartMiniClusterOption)} instead. 1205 * @see #startMiniHBaseCluster(StartMiniClusterOption) 1206 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 1207 */ 1208 @Deprecated 1209 public MiniHBaseCluster startMiniHBaseCluster(int numMasters, int numRegionServers) 1210 throws IOException, InterruptedException { 1211 StartMiniClusterOption option = StartMiniClusterOption.builder() 1212 .numMasters(numMasters).numRegionServers(numRegionServers).build(); 1213 return startMiniHBaseCluster(option); 1214 } 1215 1216 /** 1217 * Starts up mini hbase cluster. 1218 * Usually you won't want this. You'll usually want {@link #startMiniCluster()}. 1219 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 1220 * @param numMasters Master node number. 1221 * @param numRegionServers Number of region servers. 1222 * @param rsPorts Ports that RegionServer should use. 1223 * @return The mini HBase cluster created. 1224 * @see #shutdownMiniHBaseCluster() 1225 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 1226 * {@link #startMiniHBaseCluster(StartMiniClusterOption)} instead. 1227 * @see #startMiniHBaseCluster(StartMiniClusterOption) 1228 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 1229 */ 1230 @Deprecated 1231 public MiniHBaseCluster startMiniHBaseCluster(int numMasters, int numRegionServers, 1232 List<Integer> rsPorts) throws IOException, InterruptedException { 1233 StartMiniClusterOption option = StartMiniClusterOption.builder() 1234 .numMasters(numMasters).numRegionServers(numRegionServers).rsPorts(rsPorts).build(); 1235 return startMiniHBaseCluster(option); 1236 } 1237 1238 /** 1239 * Starts up mini hbase cluster. 1240 * Usually you won't want this. You'll usually want {@link #startMiniCluster()}. 1241 * All other options will use default values, defined in {@link StartMiniClusterOption.Builder}. 1242 * @param numMasters Master node number. 1243 * @param numRegionServers Number of region servers. 1244 * @param rsPorts Ports that RegionServer should use. 1245 * @param masterClass The class to use as HMaster, or null for default. 1246 * @param rsClass The class to use as HRegionServer, or null for default. 1247 * @param createRootDir Whether to create a new root or data directory path. 1248 * @param createWALDir Whether to create a new WAL directory. 1249 * @return The mini HBase cluster created. 1250 * @see #shutdownMiniHBaseCluster() 1251 * @deprecated since 2.2.0 and will be removed in 4.0.0. Use 1252 * {@link #startMiniHBaseCluster(StartMiniClusterOption)} instead. 1253 * @see #startMiniHBaseCluster(StartMiniClusterOption) 1254 * @see <a href="https://issues.apache.org/jira/browse/HBASE-21071">HBASE-21071</a> 1255 */ 1256 @Deprecated 1257 public MiniHBaseCluster startMiniHBaseCluster(int numMasters, int numRegionServers, 1258 List<Integer> rsPorts, Class<? extends HMaster> masterClass, 1259 Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> rsClass, 1260 boolean createRootDir, boolean createWALDir) throws IOException, InterruptedException { 1261 StartMiniClusterOption option = StartMiniClusterOption.builder() 1262 .numMasters(numMasters).masterClass(masterClass) 1263 .numRegionServers(numRegionServers).rsClass(rsClass).rsPorts(rsPorts) 1264 .createRootDir(createRootDir).createWALDir(createWALDir).build(); 1265 return startMiniHBaseCluster(option); 1266 } 1267 1268 /** 1269 * Starts the hbase cluster up again after shutting it down previously in a 1270 * test. Use this if you want to keep dfs/zk up and just stop/start hbase. 1271 * @param servers number of region servers 1272 */ 1273 public void restartHBaseCluster(int servers) throws IOException, InterruptedException { 1274 this.restartHBaseCluster(servers, null); 1275 } 1276 1277 public void restartHBaseCluster(int servers, List<Integer> ports) 1278 throws IOException, InterruptedException { 1279 StartMiniClusterOption option = 1280 StartMiniClusterOption.builder().numRegionServers(servers).rsPorts(ports).build(); 1281 restartHBaseCluster(option); 1282 } 1283 1284 public void restartHBaseCluster(StartMiniClusterOption option) 1285 throws IOException, InterruptedException { 1286 if (hbaseAdmin != null) { 1287 hbaseAdmin.close(); 1288 hbaseAdmin = null; 1289 } 1290 if (this.connection != null) { 1291 this.connection.close(); 1292 this.connection = null; 1293 } 1294 this.hbaseCluster = 1295 new MiniHBaseCluster(this.conf, option.getNumMasters(), option.getNumRegionServers(), 1296 option.getRsPorts(), option.getMasterClass(), option.getRsClass()); 1297 // Don't leave here till we've done a successful scan of the hbase:meta 1298 Connection conn = ConnectionFactory.createConnection(this.conf); 1299 Table t = conn.getTable(TableName.META_TABLE_NAME); 1300 ResultScanner s = t.getScanner(new Scan()); 1301 while (s.next() != null) { 1302 // do nothing 1303 } 1304 LOG.info("HBase has been restarted"); 1305 s.close(); 1306 t.close(); 1307 conn.close(); 1308 } 1309 1310 /** 1311 * @return Current mini hbase cluster. Only has something in it after a call 1312 * to {@link #startMiniCluster()}. 1313 * @see #startMiniCluster() 1314 */ 1315 public MiniHBaseCluster getMiniHBaseCluster() { 1316 if (this.hbaseCluster == null || this.hbaseCluster instanceof MiniHBaseCluster) { 1317 return (MiniHBaseCluster)this.hbaseCluster; 1318 } 1319 throw new RuntimeException(hbaseCluster + " not an instance of " + 1320 MiniHBaseCluster.class.getName()); 1321 } 1322 1323 /** 1324 * Stops mini hbase, zk, and hdfs clusters. 1325 * @throws IOException 1326 * @see #startMiniCluster(int) 1327 */ 1328 public void shutdownMiniCluster() throws Exception { 1329 LOG.info("Shutting down minicluster"); 1330 shutdownMiniHBaseCluster(); 1331 shutdownMiniDFSCluster(); 1332 shutdownMiniZKCluster(); 1333 1334 cleanupTestDir(); 1335 miniClusterRunning = false; 1336 LOG.info("Minicluster is down"); 1337 } 1338 1339 /** 1340 * Shutdown HBase mini cluster.Does not shutdown zk or dfs if running. 1341 * @throws java.io.IOException in case command is unsuccessful 1342 */ 1343 public void shutdownMiniHBaseCluster() throws IOException { 1344 cleanup(); 1345 if (this.hbaseCluster != null) { 1346 this.hbaseCluster.shutdown(); 1347 // Wait till hbase is down before going on to shutdown zk. 1348 this.hbaseCluster.waitUntilShutDown(); 1349 this.hbaseCluster = null; 1350 } 1351 if (zooKeeperWatcher != null) { 1352 zooKeeperWatcher.close(); 1353 zooKeeperWatcher = null; 1354 } 1355 } 1356 1357 /** 1358 * Abruptly Shutdown HBase mini cluster. Does not shutdown zk or dfs if running. 1359 * @throws java.io.IOException throws in case command is unsuccessful 1360 */ 1361 public void killMiniHBaseCluster() throws IOException { 1362 cleanup(); 1363 if (this.hbaseCluster != null) { 1364 getMiniHBaseCluster().killAll(); 1365 this.hbaseCluster = null; 1366 } 1367 if (zooKeeperWatcher != null) { 1368 zooKeeperWatcher.close(); 1369 zooKeeperWatcher = null; 1370 } 1371 } 1372 1373 // close hbase admin, close current connection and reset MIN MAX configs for RS. 1374 private void cleanup() throws IOException { 1375 if (hbaseAdmin != null) { 1376 hbaseAdmin.close(); 1377 hbaseAdmin = null; 1378 } 1379 if (this.connection != null) { 1380 this.connection.close(); 1381 this.connection = null; 1382 } 1383 // unset the configuration for MIN and MAX RS to start 1384 conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, -1); 1385 conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MAXTOSTART, -1); 1386 } 1387 1388 /** 1389 * Returns the path to the default root dir the minicluster uses. If <code>create</code> 1390 * is true, a new root directory path is fetched irrespective of whether it has been fetched 1391 * before or not. If false, previous path is used. 1392 * Note: this does not cause the root dir to be created. 1393 * @return Fully qualified path for the default hbase root dir 1394 * @throws IOException 1395 */ 1396 public Path getDefaultRootDirPath(boolean create) throws IOException { 1397 if (!create) { 1398 return getDataTestDirOnTestFS(); 1399 } else { 1400 return getNewDataTestDirOnTestFS(); 1401 } 1402 } 1403 1404 /** 1405 * Same as {{@link HBaseTestingUtility#getDefaultRootDirPath(boolean create)} 1406 * except that <code>create</code> flag is false. 1407 * Note: this does not cause the root dir to be created. 1408 * @return Fully qualified path for the default hbase root dir 1409 * @throws IOException 1410 */ 1411 public Path getDefaultRootDirPath() throws IOException { 1412 return getDefaultRootDirPath(false); 1413 } 1414 1415 /** 1416 * Creates an hbase rootdir in user home directory. Also creates hbase 1417 * version file. Normally you won't make use of this method. Root hbasedir 1418 * is created for you as part of mini cluster startup. You'd only use this 1419 * method if you were doing manual operation. 1420 * @param create This flag decides whether to get a new 1421 * root or data directory path or not, if it has been fetched already. 1422 * Note : Directory will be made irrespective of whether path has been fetched or not. 1423 * If directory already exists, it will be overwritten 1424 * @return Fully qualified path to hbase root dir 1425 * @throws IOException 1426 */ 1427 public Path createRootDir(boolean create) throws IOException { 1428 FileSystem fs = FileSystem.get(this.conf); 1429 Path hbaseRootdir = getDefaultRootDirPath(create); 1430 FSUtils.setRootDir(this.conf, hbaseRootdir); 1431 fs.mkdirs(hbaseRootdir); 1432 FSUtils.setVersion(fs, hbaseRootdir); 1433 return hbaseRootdir; 1434 } 1435 1436 /** 1437 * Same as {@link HBaseTestingUtility#createRootDir(boolean create)} 1438 * except that <code>create</code> flag is false. 1439 * @return Fully qualified path to hbase root dir 1440 * @throws IOException 1441 */ 1442 public Path createRootDir() throws IOException { 1443 return createRootDir(false); 1444 } 1445 1446 /** 1447 * Creates a hbase walDir in the user's home directory. 1448 * Normally you won't make use of this method. Root hbaseWALDir 1449 * is created for you as part of mini cluster startup. You'd only use this 1450 * method if you were doing manual operation. 1451 * 1452 * @return Fully qualified path to hbase root dir 1453 * @throws IOException 1454 */ 1455 public Path createWALRootDir() throws IOException { 1456 FileSystem fs = FileSystem.get(this.conf); 1457 Path walDir = getNewDataTestDirOnTestFS(); 1458 FSUtils.setWALRootDir(this.conf, walDir); 1459 fs.mkdirs(walDir); 1460 return walDir; 1461 } 1462 1463 private void setHBaseFsTmpDir() throws IOException { 1464 String hbaseFsTmpDirInString = this.conf.get("hbase.fs.tmp.dir"); 1465 if (hbaseFsTmpDirInString == null) { 1466 this.conf.set("hbase.fs.tmp.dir", getDataTestDirOnTestFS("hbase-staging").toString()); 1467 LOG.info("Setting hbase.fs.tmp.dir to " + this.conf.get("hbase.fs.tmp.dir")); 1468 } else { 1469 LOG.info("The hbase.fs.tmp.dir is set to " + hbaseFsTmpDirInString); 1470 } 1471 } 1472 1473 /** 1474 * Flushes all caches in the mini hbase cluster 1475 * @throws IOException 1476 */ 1477 public void flush() throws IOException { 1478 getMiniHBaseCluster().flushcache(); 1479 } 1480 1481 /** 1482 * Flushes all caches in the mini hbase cluster 1483 * @throws IOException 1484 */ 1485 public void flush(TableName tableName) throws IOException { 1486 getMiniHBaseCluster().flushcache(tableName); 1487 } 1488 1489 /** 1490 * Compact all regions in the mini hbase cluster 1491 * @throws IOException 1492 */ 1493 public void compact(boolean major) throws IOException { 1494 getMiniHBaseCluster().compact(major); 1495 } 1496 1497 /** 1498 * Compact all of a table's reagion in the mini hbase cluster 1499 * @throws IOException 1500 */ 1501 public void compact(TableName tableName, boolean major) throws IOException { 1502 getMiniHBaseCluster().compact(tableName, major); 1503 } 1504 1505 /** 1506 * Create a table. 1507 * @param tableName 1508 * @param family 1509 * @return A Table instance for the created table. 1510 * @throws IOException 1511 */ 1512 public Table createTable(TableName tableName, String family) 1513 throws IOException{ 1514 return createTable(tableName, new String[]{family}); 1515 } 1516 1517 /** 1518 * Create a table. 1519 * @param tableName 1520 * @param families 1521 * @return A Table instance for the created table. 1522 * @throws IOException 1523 */ 1524 public Table createTable(TableName tableName, String[] families) 1525 throws IOException { 1526 List<byte[]> fams = new ArrayList<>(families.length); 1527 for (String family : families) { 1528 fams.add(Bytes.toBytes(family)); 1529 } 1530 return createTable(tableName, fams.toArray(new byte[0][])); 1531 } 1532 1533 /** 1534 * Create a table. 1535 * @param tableName 1536 * @param family 1537 * @return A Table instance for the created table. 1538 * @throws IOException 1539 */ 1540 public Table createTable(TableName tableName, byte[] family) 1541 throws IOException{ 1542 return createTable(tableName, new byte[][]{family}); 1543 } 1544 1545 /** 1546 * Create a table with multiple regions. 1547 * @param tableName 1548 * @param family 1549 * @param numRegions 1550 * @return A Table instance for the created table. 1551 * @throws IOException 1552 */ 1553 public Table createMultiRegionTable(TableName tableName, byte[] family, int numRegions) 1554 throws IOException { 1555 if (numRegions < 3) throw new IOException("Must create at least 3 regions"); 1556 byte[] startKey = Bytes.toBytes("aaaaa"); 1557 byte[] endKey = Bytes.toBytes("zzzzz"); 1558 byte[][] splitKeys = Bytes.split(startKey, endKey, numRegions - 3); 1559 1560 return createTable(tableName, new byte[][] { family }, splitKeys); 1561 } 1562 1563 /** 1564 * Create a table. 1565 * @param tableName 1566 * @param families 1567 * @return A Table instance for the created table. 1568 * @throws IOException 1569 */ 1570 public Table createTable(TableName tableName, byte[][] families) 1571 throws IOException { 1572 return createTable(tableName, families, (byte[][]) null); 1573 } 1574 1575 /** 1576 * Create a table with multiple regions. 1577 * @param tableName 1578 * @param families 1579 * @return A Table instance for the created table. 1580 * @throws IOException 1581 */ 1582 public Table createMultiRegionTable(TableName tableName, byte[][] families) throws IOException { 1583 return createTable(tableName, families, KEYS_FOR_HBA_CREATE_TABLE); 1584 } 1585 1586 /** 1587 * Create a table. 1588 * @param tableName 1589 * @param families 1590 * @param splitKeys 1591 * @return A Table instance for the created table. 1592 * @throws IOException 1593 */ 1594 public Table createTable(TableName tableName, byte[][] families, byte[][] splitKeys) 1595 throws IOException { 1596 return createTable(tableName, families, splitKeys, 1, new Configuration(getConfiguration())); 1597 } 1598 1599 /** 1600 * Create a table. 1601 * @param tableName the table name 1602 * @param families the families 1603 * @param splitKeys the splitkeys 1604 * @param replicaCount the region replica count 1605 * @return A Table instance for the created table. 1606 * @throws IOException throws IOException 1607 */ 1608 public Table createTable(TableName tableName, byte[][] families, byte[][] splitKeys, 1609 int replicaCount) throws IOException { 1610 return createTable(tableName, families, splitKeys, replicaCount, 1611 new Configuration(getConfiguration())); 1612 } 1613 1614 public Table createTable(TableName tableName, byte[][] families, 1615 int numVersions, byte[] startKey, byte[] endKey, int numRegions) 1616 throws IOException{ 1617 HTableDescriptor desc = createTableDescriptor(tableName, families, numVersions); 1618 1619 getAdmin().createTable(desc, startKey, endKey, numRegions); 1620 // HBaseAdmin only waits for regions to appear in hbase:meta we 1621 // should wait until they are assigned 1622 waitUntilAllRegionsAssigned(tableName); 1623 return getConnection().getTable(tableName); 1624 } 1625 1626 /** 1627 * Create a table. 1628 * @param htd 1629 * @param families 1630 * @param c Configuration to use 1631 * @return A Table instance for the created table. 1632 * @throws IOException 1633 */ 1634 public Table createTable(TableDescriptor htd, byte[][] families, Configuration c) 1635 throws IOException { 1636 return createTable(htd, families, null, c); 1637 } 1638 1639 /** 1640 * Create a table. 1641 * @param htd table descriptor 1642 * @param families array of column families 1643 * @param splitKeys array of split keys 1644 * @param c Configuration to use 1645 * @return A Table instance for the created table. 1646 * @throws IOException if getAdmin or createTable fails 1647 */ 1648 public Table createTable(TableDescriptor htd, byte[][] families, byte[][] splitKeys, 1649 Configuration c) throws IOException { 1650 // Disable blooms (they are on by default as of 0.95) but we disable them here because 1651 // tests have hard coded counts of what to expect in block cache, etc., and blooms being 1652 // on is interfering. 1653 return createTable(htd, families, splitKeys, BloomType.NONE, HConstants.DEFAULT_BLOCKSIZE, c); 1654 } 1655 1656 /** 1657 * Create a table. 1658 * @param htd table descriptor 1659 * @param families array of column families 1660 * @param splitKeys array of split keys 1661 * @param type Bloom type 1662 * @param blockSize block size 1663 * @param c Configuration to use 1664 * @return A Table instance for the created table. 1665 * @throws IOException if getAdmin or createTable fails 1666 */ 1667 1668 public Table createTable(TableDescriptor htd, byte[][] families, byte[][] splitKeys, 1669 BloomType type, int blockSize, Configuration c) throws IOException { 1670 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(htd); 1671 for (byte[] family : families) { 1672 ColumnFamilyDescriptorBuilder cfdb = ColumnFamilyDescriptorBuilder.newBuilder(family) 1673 .setBloomFilterType(type) 1674 .setBlocksize(blockSize); 1675 if (isNewVersionBehaviorEnabled()) { 1676 cfdb.setNewVersionBehavior(true); 1677 } 1678 builder.setColumnFamily(cfdb.build()); 1679 } 1680 TableDescriptor td = builder.build(); 1681 getAdmin().createTable(td, splitKeys); 1682 // HBaseAdmin only waits for regions to appear in hbase:meta 1683 // we should wait until they are assigned 1684 waitUntilAllRegionsAssigned(td.getTableName()); 1685 return getConnection().getTable(td.getTableName()); 1686 } 1687 1688 /** 1689 * Create a table. 1690 * @param htd table descriptor 1691 * @param splitRows array of split keys 1692 * @return A Table instance for the created table. 1693 * @throws IOException 1694 */ 1695 public Table createTable(TableDescriptor htd, byte[][] splitRows) 1696 throws IOException { 1697 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(htd); 1698 if (isNewVersionBehaviorEnabled()) { 1699 for (ColumnFamilyDescriptor family : htd.getColumnFamilies()) { 1700 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(family) 1701 .setNewVersionBehavior(true).build()); 1702 } 1703 } 1704 getAdmin().createTable(builder.build(), splitRows); 1705 // HBaseAdmin only waits for regions to appear in hbase:meta 1706 // we should wait until they are assigned 1707 waitUntilAllRegionsAssigned(htd.getTableName()); 1708 return getConnection().getTable(htd.getTableName()); 1709 } 1710 1711 /** 1712 * Create a table. 1713 * @param tableName the table name 1714 * @param families the families 1715 * @param splitKeys the split keys 1716 * @param replicaCount the replica count 1717 * @param c Configuration to use 1718 * @return A Table instance for the created table. 1719 * @throws IOException 1720 */ 1721 public Table createTable(TableName tableName, byte[][] families, byte[][] splitKeys, 1722 int replicaCount, final Configuration c) throws IOException { 1723 HTableDescriptor htd = new HTableDescriptor(tableName); 1724 htd.setRegionReplication(replicaCount); 1725 return createTable(htd, families, splitKeys, c); 1726 } 1727 1728 /** 1729 * Create a table. 1730 * @param tableName 1731 * @param family 1732 * @param numVersions 1733 * @return A Table instance for the created table. 1734 * @throws IOException 1735 */ 1736 public Table createTable(TableName tableName, byte[] family, int numVersions) 1737 throws IOException { 1738 return createTable(tableName, new byte[][]{family}, numVersions); 1739 } 1740 1741 /** 1742 * Create a table. 1743 * @param tableName 1744 * @param families 1745 * @param numVersions 1746 * @return A Table instance for the created table. 1747 * @throws IOException 1748 */ 1749 public Table createTable(TableName tableName, byte[][] families, int numVersions) 1750 throws IOException { 1751 return createTable(tableName, families, numVersions, (byte[][]) null); 1752 } 1753 1754 /** 1755 * Create a table. 1756 * @param tableName 1757 * @param families 1758 * @param numVersions 1759 * @param splitKeys 1760 * @return A Table instance for the created table. 1761 * @throws IOException 1762 */ 1763 public Table createTable(TableName tableName, byte[][] families, int numVersions, 1764 byte[][] splitKeys) throws IOException { 1765 HTableDescriptor desc = new HTableDescriptor(tableName); 1766 for (byte[] family : families) { 1767 HColumnDescriptor hcd = new HColumnDescriptor(family).setMaxVersions(numVersions); 1768 if (isNewVersionBehaviorEnabled()) { 1769 hcd.setNewVersionBehavior(true); 1770 } 1771 desc.addFamily(hcd); 1772 } 1773 getAdmin().createTable(desc, splitKeys); 1774 // HBaseAdmin only waits for regions to appear in hbase:meta we should wait until they are 1775 // assigned 1776 waitUntilAllRegionsAssigned(tableName); 1777 return getConnection().getTable(tableName); 1778 } 1779 1780 /** 1781 * Create a table with multiple regions. 1782 * @param tableName 1783 * @param families 1784 * @param numVersions 1785 * @return A Table instance for the created table. 1786 * @throws IOException 1787 */ 1788 public Table createMultiRegionTable(TableName tableName, byte[][] families, int numVersions) 1789 throws IOException { 1790 return createTable(tableName, families, numVersions, KEYS_FOR_HBA_CREATE_TABLE); 1791 } 1792 1793 /** 1794 * Create a table. 1795 * @param tableName 1796 * @param families 1797 * @param numVersions 1798 * @param blockSize 1799 * @return A Table instance for the created table. 1800 * @throws IOException 1801 */ 1802 public Table createTable(TableName tableName, byte[][] families, 1803 int numVersions, int blockSize) throws IOException { 1804 HTableDescriptor desc = new HTableDescriptor(tableName); 1805 for (byte[] family : families) { 1806 HColumnDescriptor hcd = new HColumnDescriptor(family) 1807 .setMaxVersions(numVersions) 1808 .setBlocksize(blockSize); 1809 if (isNewVersionBehaviorEnabled()) { 1810 hcd.setNewVersionBehavior(true); 1811 } 1812 desc.addFamily(hcd); 1813 } 1814 getAdmin().createTable(desc); 1815 // HBaseAdmin only waits for regions to appear in hbase:meta we should wait until they are 1816 // assigned 1817 waitUntilAllRegionsAssigned(tableName); 1818 return getConnection().getTable(tableName); 1819 } 1820 1821 public Table createTable(TableName tableName, byte[][] families, 1822 int numVersions, int blockSize, String cpName) throws IOException { 1823 HTableDescriptor desc = new HTableDescriptor(tableName); 1824 for (byte[] family : families) { 1825 HColumnDescriptor hcd = new HColumnDescriptor(family) 1826 .setMaxVersions(numVersions) 1827 .setBlocksize(blockSize); 1828 if (isNewVersionBehaviorEnabled()) { 1829 hcd.setNewVersionBehavior(true); 1830 } 1831 desc.addFamily(hcd); 1832 } 1833 if(cpName != null) { 1834 desc.addCoprocessor(cpName); 1835 } 1836 getAdmin().createTable(desc); 1837 // HBaseAdmin only waits for regions to appear in hbase:meta we should wait until they are 1838 // assigned 1839 waitUntilAllRegionsAssigned(tableName); 1840 return getConnection().getTable(tableName); 1841 } 1842 1843 /** 1844 * Create a table. 1845 * @param tableName 1846 * @param families 1847 * @param numVersions 1848 * @return A Table instance for the created table. 1849 * @throws IOException 1850 */ 1851 public Table createTable(TableName tableName, byte[][] families, 1852 int[] numVersions) 1853 throws IOException { 1854 HTableDescriptor desc = new HTableDescriptor(tableName); 1855 int i = 0; 1856 for (byte[] family : families) { 1857 HColumnDescriptor hcd = new HColumnDescriptor(family) 1858 .setMaxVersions(numVersions[i]); 1859 if (isNewVersionBehaviorEnabled()) { 1860 hcd.setNewVersionBehavior(true); 1861 } 1862 desc.addFamily(hcd); 1863 i++; 1864 } 1865 getAdmin().createTable(desc); 1866 // HBaseAdmin only waits for regions to appear in hbase:meta we should wait until they are 1867 // assigned 1868 waitUntilAllRegionsAssigned(tableName); 1869 return getConnection().getTable(tableName); 1870 } 1871 1872 /** 1873 * Create a table. 1874 * @param tableName 1875 * @param family 1876 * @param splitRows 1877 * @return A Table instance for the created table. 1878 * @throws IOException 1879 */ 1880 public Table createTable(TableName tableName, byte[] family, byte[][] splitRows) 1881 throws IOException { 1882 HTableDescriptor desc = new HTableDescriptor(tableName); 1883 HColumnDescriptor hcd = new HColumnDescriptor(family); 1884 if (isNewVersionBehaviorEnabled()) { 1885 hcd.setNewVersionBehavior(true); 1886 } 1887 desc.addFamily(hcd); 1888 getAdmin().createTable(desc, splitRows); 1889 // HBaseAdmin only waits for regions to appear in hbase:meta we should wait until they are 1890 // assigned 1891 waitUntilAllRegionsAssigned(tableName); 1892 return getConnection().getTable(tableName); 1893 } 1894 1895 /** 1896 * Create a table with multiple regions. 1897 * @param tableName 1898 * @param family 1899 * @return A Table instance for the created table. 1900 * @throws IOException 1901 */ 1902 public Table createMultiRegionTable(TableName tableName, byte[] family) throws IOException { 1903 return createTable(tableName, family, KEYS_FOR_HBA_CREATE_TABLE); 1904 } 1905 1906 /** 1907 * Modify a table, synchronous. Waiting logic similar to that of {@code admin.rb#alter_status}. 1908 */ 1909 @SuppressWarnings("serial") 1910 public static void modifyTableSync(Admin admin, TableDescriptor desc) 1911 throws IOException, InterruptedException { 1912 admin.modifyTable(desc); 1913 Pair<Integer, Integer> status = new Pair<Integer, Integer>() {{ 1914 setFirst(0); 1915 setSecond(0); 1916 }}; 1917 int i = 0; 1918 do { 1919 status = admin.getAlterStatus(desc.getTableName()); 1920 if (status.getSecond() != 0) { 1921 LOG.debug(status.getSecond() - status.getFirst() + "/" + status.getSecond() 1922 + " regions updated."); 1923 Thread.sleep(1 * 1000L); 1924 } else { 1925 LOG.debug("All regions updated."); 1926 break; 1927 } 1928 } while (status.getFirst() != 0 && i++ < 500); 1929 if (status.getFirst() != 0) { 1930 throw new IOException("Failed to update all regions even after 500 seconds."); 1931 } 1932 } 1933 1934 /** 1935 * Set the number of Region replicas. 1936 */ 1937 public static void setReplicas(Admin admin, TableName table, int replicaCount) 1938 throws IOException, InterruptedException { 1939 admin.disableTable(table); 1940 HTableDescriptor desc = new HTableDescriptor(admin.getTableDescriptor(table)); 1941 desc.setRegionReplication(replicaCount); 1942 admin.modifyTable(desc.getTableName(), desc); 1943 admin.enableTable(table); 1944 } 1945 1946 /** 1947 * Drop an existing table 1948 * @param tableName existing table 1949 */ 1950 public void deleteTable(TableName tableName) throws IOException { 1951 try { 1952 getAdmin().disableTable(tableName); 1953 } catch (TableNotEnabledException e) { 1954 LOG.debug("Table: " + tableName + " already disabled, so just deleting it."); 1955 } 1956 getAdmin().deleteTable(tableName); 1957 } 1958 1959 /** 1960 * Drop an existing table 1961 * @param tableName existing table 1962 */ 1963 public void deleteTableIfAny(TableName tableName) throws IOException { 1964 try { 1965 deleteTable(tableName); 1966 } catch (TableNotFoundException e) { 1967 // ignore 1968 } 1969 } 1970 1971 // ========================================================================== 1972 // Canned table and table descriptor creation 1973 // TODO replace HBaseTestCase 1974 1975 public final static byte [] fam1 = Bytes.toBytes("colfamily11"); 1976 public final static byte [] fam2 = Bytes.toBytes("colfamily21"); 1977 public final static byte [] fam3 = Bytes.toBytes("colfamily31"); 1978 public static final byte[][] COLUMNS = {fam1, fam2, fam3}; 1979 private static final int MAXVERSIONS = 3; 1980 1981 public static final char FIRST_CHAR = 'a'; 1982 public static final char LAST_CHAR = 'z'; 1983 public static final byte [] START_KEY_BYTES = {FIRST_CHAR, FIRST_CHAR, FIRST_CHAR}; 1984 public static final String START_KEY = new String(START_KEY_BYTES, HConstants.UTF8_CHARSET); 1985 1986 /** 1987 * @deprecated since 2.0.0 and will be removed in 3.0.0. Use 1988 * {@link #createTableDescriptor(TableName, int, int, int, KeepDeletedCells)} instead. 1989 * @see #createTableDescriptor(TableName, int, int, int, KeepDeletedCells) 1990 * @see <a href="https://issues.apache.org/jira/browse/HBASE-13893">HBASE-13893</a> 1991 */ 1992 @Deprecated 1993 public HTableDescriptor createTableDescriptor(final String name, 1994 final int minVersions, final int versions, final int ttl, KeepDeletedCells keepDeleted) { 1995 return this.createTableDescriptor(TableName.valueOf(name), minVersions, versions, ttl, 1996 keepDeleted); 1997 } 1998 1999 /** 2000 * Create a table of name <code>name</code>. 2001 * @param name Name to give table. 2002 * @return Column descriptor. 2003 * @deprecated since 2.0.0 and will be removed in 3.0.0. Use 2004 * {@link #createTableDescriptor(TableName, int, int, int, KeepDeletedCells)} instead. 2005 * @see #createTableDescriptor(TableName, int, int, int, KeepDeletedCells) 2006 * @see <a href="https://issues.apache.org/jira/browse/HBASE-13893">HBASE-13893</a> 2007 */ 2008 @Deprecated 2009 public HTableDescriptor createTableDescriptor(final String name) { 2010 return createTableDescriptor(TableName.valueOf(name), HColumnDescriptor.DEFAULT_MIN_VERSIONS, 2011 MAXVERSIONS, HConstants.FOREVER, HColumnDescriptor.DEFAULT_KEEP_DELETED); 2012 } 2013 2014 public HTableDescriptor createTableDescriptor(final TableName name, 2015 final int minVersions, final int versions, final int ttl, KeepDeletedCells keepDeleted) { 2016 HTableDescriptor htd = new HTableDescriptor(name); 2017 for (byte[] cfName : new byte[][]{ fam1, fam2, fam3 }) { 2018 HColumnDescriptor hcd = new HColumnDescriptor(cfName) 2019 .setMinVersions(minVersions) 2020 .setMaxVersions(versions) 2021 .setKeepDeletedCells(keepDeleted) 2022 .setBlockCacheEnabled(false) 2023 .setTimeToLive(ttl); 2024 if (isNewVersionBehaviorEnabled()) { 2025 hcd.setNewVersionBehavior(true); 2026 } 2027 htd.addFamily(hcd); 2028 } 2029 return htd; 2030 } 2031 2032 /** 2033 * Create a table of name <code>name</code>. 2034 * @param name Name to give table. 2035 * @return Column descriptor. 2036 */ 2037 public HTableDescriptor createTableDescriptor(final TableName name) { 2038 return createTableDescriptor(name, HColumnDescriptor.DEFAULT_MIN_VERSIONS, 2039 MAXVERSIONS, HConstants.FOREVER, HColumnDescriptor.DEFAULT_KEEP_DELETED); 2040 } 2041 2042 public HTableDescriptor createTableDescriptor(final TableName tableName, 2043 byte[] family) { 2044 return createTableDescriptor(tableName, new byte[][] {family}, 1); 2045 } 2046 2047 public HTableDescriptor createTableDescriptor(final TableName tableName, 2048 byte[][] families, int maxVersions) { 2049 HTableDescriptor desc = new HTableDescriptor(tableName); 2050 for (byte[] family : families) { 2051 HColumnDescriptor hcd = new HColumnDescriptor(family) 2052 .setMaxVersions(maxVersions); 2053 if (isNewVersionBehaviorEnabled()) { 2054 hcd.setNewVersionBehavior(true); 2055 } 2056 desc.addFamily(hcd); 2057 } 2058 return desc; 2059 } 2060 2061 /** 2062 * Create an HRegion that writes to the local tmp dirs 2063 * @param desc a table descriptor indicating which table the region belongs to 2064 * @param startKey the start boundary of the region 2065 * @param endKey the end boundary of the region 2066 * @return a region that writes to local dir for testing 2067 * @throws IOException 2068 */ 2069 public HRegion createLocalHRegion(TableDescriptor desc, byte [] startKey, 2070 byte [] endKey) 2071 throws IOException { 2072 HRegionInfo hri = new HRegionInfo(desc.getTableName(), startKey, endKey); 2073 return createLocalHRegion(hri, desc); 2074 } 2075 2076 /** 2077 * Create an HRegion that writes to the local tmp dirs. Creates the WAL for you. Be sure to call 2078 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} when you're finished with it. 2079 */ 2080 public HRegion createLocalHRegion(RegionInfo info, TableDescriptor desc) throws IOException { 2081 return createRegionAndWAL(info, getDataTestDir(), getConfiguration(), desc); 2082 } 2083 2084 /** 2085 * Create an HRegion that writes to the local tmp dirs with specified wal 2086 * @param info regioninfo 2087 * @param desc table descriptor 2088 * @param wal wal for this region. 2089 * @return created hregion 2090 * @throws IOException 2091 */ 2092 public HRegion createLocalHRegion(RegionInfo info, TableDescriptor desc, WAL wal) 2093 throws IOException { 2094 return HRegion.createHRegion(info, getDataTestDir(), getConfiguration(), desc, wal); 2095 } 2096 2097 /** 2098 * @param tableName the name of the table 2099 * @param startKey the start key of the region 2100 * @param stopKey the stop key of the region 2101 * @param callingMethod the name of the calling method probably a test method 2102 * @param conf the configuration to use 2103 * @param isReadOnly {@code true} if the table is read only, {@code false} otherwise 2104 * @param families the column families to use 2105 * @throws IOException if an IO problem is encountered 2106 * @return A region on which you must call {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} 2107 * when done. 2108 * @deprecated since 2.0.0 and will be removed in 3.0.0. Use 2109 * {@link #createLocalHRegion(TableName, byte[], byte[], boolean, Durability, WAL, byte[]...)} 2110 * instead. 2111 * @see #createLocalHRegion(TableName, byte[], byte[], boolean, Durability, WAL, byte[]...) 2112 * @see <a href="https://issues.apache.org/jira/browse/HBASE-13893">HBASE-13893</a> 2113 */ 2114 @Deprecated 2115 public HRegion createLocalHRegion(byte[] tableName, byte[] startKey, byte[] stopKey, 2116 String callingMethod, Configuration conf, boolean isReadOnly, Durability durability, 2117 WAL wal, byte[]... families) throws IOException { 2118 return this 2119 .createLocalHRegion(TableName.valueOf(tableName), startKey, stopKey, isReadOnly, durability, 2120 wal, families); 2121 } 2122 2123 /** 2124 * @param tableName 2125 * @param startKey 2126 * @param stopKey 2127 * @param isReadOnly 2128 * @param families 2129 * @return A region on which you must call 2130 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} when done. 2131 * @throws IOException 2132 */ 2133 public HRegion createLocalHRegion(TableName tableName, byte[] startKey, byte[] stopKey, 2134 boolean isReadOnly, Durability durability, WAL wal, byte[]... families) throws IOException { 2135 return createLocalHRegionWithInMemoryFlags(tableName,startKey, stopKey, isReadOnly, 2136 durability, wal, null, families); 2137 } 2138 2139 public HRegion createLocalHRegionWithInMemoryFlags(TableName tableName, byte[] startKey, 2140 byte[] stopKey, 2141 boolean isReadOnly, Durability durability, WAL wal, boolean[] compactedMemStore, 2142 byte[]... families) 2143 throws IOException { 2144 HTableDescriptor htd = new HTableDescriptor(tableName); 2145 htd.setReadOnly(isReadOnly); 2146 int i=0; 2147 for (byte[] family : families) { 2148 HColumnDescriptor hcd = new HColumnDescriptor(family); 2149 if(compactedMemStore != null && i < compactedMemStore.length) { 2150 hcd.setInMemoryCompaction(MemoryCompactionPolicy.BASIC); 2151 } else { 2152 hcd.setInMemoryCompaction(MemoryCompactionPolicy.NONE); 2153 2154 } 2155 i++; 2156 // Set default to be three versions. 2157 hcd.setMaxVersions(Integer.MAX_VALUE); 2158 htd.addFamily(hcd); 2159 } 2160 htd.setDurability(durability); 2161 HRegionInfo info = new HRegionInfo(htd.getTableName(), startKey, stopKey, false); 2162 return createLocalHRegion(info, htd, wal); 2163 } 2164 2165 // 2166 // ========================================================================== 2167 2168 /** 2169 * Provide an existing table name to truncate. 2170 * Scans the table and issues a delete for each row read. 2171 * @param tableName existing table 2172 * @return HTable to that new table 2173 * @throws IOException 2174 */ 2175 public Table deleteTableData(TableName tableName) throws IOException { 2176 Table table = getConnection().getTable(tableName); 2177 Scan scan = new Scan(); 2178 ResultScanner resScan = table.getScanner(scan); 2179 for(Result res : resScan) { 2180 Delete del = new Delete(res.getRow()); 2181 table.delete(del); 2182 } 2183 resScan = table.getScanner(scan); 2184 resScan.close(); 2185 return table; 2186 } 2187 2188 /** 2189 * Truncate a table using the admin command. 2190 * Effectively disables, deletes, and recreates the table. 2191 * @param tableName table which must exist. 2192 * @param preserveRegions keep the existing split points 2193 * @return HTable for the new table 2194 */ 2195 public Table truncateTable(final TableName tableName, final boolean preserveRegions) throws 2196 IOException { 2197 Admin admin = getAdmin(); 2198 if (!admin.isTableDisabled(tableName)) { 2199 admin.disableTable(tableName); 2200 } 2201 admin.truncateTable(tableName, preserveRegions); 2202 return getConnection().getTable(tableName); 2203 } 2204 2205 /** 2206 * Truncate a table using the admin command. 2207 * Effectively disables, deletes, and recreates the table. 2208 * For previous behavior of issuing row deletes, see 2209 * deleteTableData. 2210 * Expressly does not preserve regions of existing table. 2211 * @param tableName table which must exist. 2212 * @return HTable for the new table 2213 */ 2214 public Table truncateTable(final TableName tableName) throws IOException { 2215 return truncateTable(tableName, false); 2216 } 2217 2218 /** 2219 * Load table with rows from 'aaa' to 'zzz'. 2220 * @param t Table 2221 * @param f Family 2222 * @return Count of rows loaded. 2223 * @throws IOException 2224 */ 2225 public int loadTable(final Table t, final byte[] f) throws IOException { 2226 return loadTable(t, new byte[][] {f}); 2227 } 2228 2229 /** 2230 * Load table with rows from 'aaa' to 'zzz'. 2231 * @param t Table 2232 * @param f Family 2233 * @return Count of rows loaded. 2234 * @throws IOException 2235 */ 2236 public int loadTable(final Table t, final byte[] f, boolean writeToWAL) throws IOException { 2237 return loadTable(t, new byte[][] {f}, null, writeToWAL); 2238 } 2239 2240 /** 2241 * Load table of multiple column families with rows from 'aaa' to 'zzz'. 2242 * @param t Table 2243 * @param f Array of Families to load 2244 * @return Count of rows loaded. 2245 * @throws IOException 2246 */ 2247 public int loadTable(final Table t, final byte[][] f) throws IOException { 2248 return loadTable(t, f, null); 2249 } 2250 2251 /** 2252 * Load table of multiple column families with rows from 'aaa' to 'zzz'. 2253 * @param t Table 2254 * @param f Array of Families to load 2255 * @param value the values of the cells. If null is passed, the row key is used as value 2256 * @return Count of rows loaded. 2257 * @throws IOException 2258 */ 2259 public int loadTable(final Table t, final byte[][] f, byte[] value) throws IOException { 2260 return loadTable(t, f, value, true); 2261 } 2262 2263 /** 2264 * Load table of multiple column families with rows from 'aaa' to 'zzz'. 2265 * @param t Table 2266 * @param f Array of Families to load 2267 * @param value the values of the cells. If null is passed, the row key is used as value 2268 * @return Count of rows loaded. 2269 * @throws IOException 2270 */ 2271 public int loadTable(final Table t, final byte[][] f, byte[] value, 2272 boolean writeToWAL) throws IOException { 2273 List<Put> puts = new ArrayList<>(); 2274 for (byte[] row : HBaseTestingUtility.ROWS) { 2275 Put put = new Put(row); 2276 put.setDurability(writeToWAL ? Durability.USE_DEFAULT : Durability.SKIP_WAL); 2277 for (int i = 0; i < f.length; i++) { 2278 byte[] value1 = value != null ? value : row; 2279 put.addColumn(f[i], f[i], value1); 2280 } 2281 puts.add(put); 2282 } 2283 t.put(puts); 2284 return puts.size(); 2285 } 2286 2287 /** A tracker for tracking and validating table rows 2288 * generated with {@link HBaseTestingUtility#loadTable(Table, byte[])} 2289 */ 2290 public static class SeenRowTracker { 2291 int dim = 'z' - 'a' + 1; 2292 int[][][] seenRows = new int[dim][dim][dim]; //count of how many times the row is seen 2293 byte[] startRow; 2294 byte[] stopRow; 2295 2296 public SeenRowTracker(byte[] startRow, byte[] stopRow) { 2297 this.startRow = startRow; 2298 this.stopRow = stopRow; 2299 } 2300 2301 void reset() { 2302 for (byte[] row : ROWS) { 2303 seenRows[i(row[0])][i(row[1])][i(row[2])] = 0; 2304 } 2305 } 2306 2307 int i(byte b) { 2308 return b - 'a'; 2309 } 2310 2311 public void addRow(byte[] row) { 2312 seenRows[i(row[0])][i(row[1])][i(row[2])]++; 2313 } 2314 2315 /** Validate that all the rows between startRow and stopRow are seen exactly once, and 2316 * all other rows none 2317 */ 2318 public void validate() { 2319 for (byte b1 = 'a'; b1 <= 'z'; b1++) { 2320 for (byte b2 = 'a'; b2 <= 'z'; b2++) { 2321 for (byte b3 = 'a'; b3 <= 'z'; b3++) { 2322 int count = seenRows[i(b1)][i(b2)][i(b3)]; 2323 int expectedCount = 0; 2324 if (Bytes.compareTo(new byte[] {b1,b2,b3}, startRow) >= 0 2325 && Bytes.compareTo(new byte[] {b1,b2,b3}, stopRow) < 0) { 2326 expectedCount = 1; 2327 } 2328 if (count != expectedCount) { 2329 String row = new String(new byte[] {b1,b2,b3}, StandardCharsets.UTF_8); 2330 throw new RuntimeException("Row:" + row + " has a seen count of " + count + " " + 2331 "instead of " + expectedCount); 2332 } 2333 } 2334 } 2335 } 2336 } 2337 } 2338 2339 public int loadRegion(final HRegion r, final byte[] f) throws IOException { 2340 return loadRegion(r, f, false); 2341 } 2342 2343 public int loadRegion(final Region r, final byte[] f) throws IOException { 2344 return loadRegion((HRegion)r, f); 2345 } 2346 2347 /** 2348 * Load region with rows from 'aaa' to 'zzz'. 2349 * @param r Region 2350 * @param f Family 2351 * @param flush flush the cache if true 2352 * @return Count of rows loaded. 2353 * @throws IOException 2354 */ 2355 public int loadRegion(final HRegion r, final byte[] f, final boolean flush) 2356 throws IOException { 2357 byte[] k = new byte[3]; 2358 int rowCount = 0; 2359 for (byte b1 = 'a'; b1 <= 'z'; b1++) { 2360 for (byte b2 = 'a'; b2 <= 'z'; b2++) { 2361 for (byte b3 = 'a'; b3 <= 'z'; b3++) { 2362 k[0] = b1; 2363 k[1] = b2; 2364 k[2] = b3; 2365 Put put = new Put(k); 2366 put.setDurability(Durability.SKIP_WAL); 2367 put.addColumn(f, null, k); 2368 if (r.getWAL() == null) { 2369 put.setDurability(Durability.SKIP_WAL); 2370 } 2371 int preRowCount = rowCount; 2372 int pause = 10; 2373 int maxPause = 1000; 2374 while (rowCount == preRowCount) { 2375 try { 2376 r.put(put); 2377 rowCount++; 2378 } catch (RegionTooBusyException e) { 2379 pause = (pause * 2 >= maxPause) ? maxPause : pause * 2; 2380 Threads.sleep(pause); 2381 } 2382 } 2383 } 2384 } 2385 if (flush) { 2386 r.flush(true); 2387 } 2388 } 2389 return rowCount; 2390 } 2391 2392 public void loadNumericRows(final Table t, final byte[] f, int startRow, int endRow) 2393 throws IOException { 2394 for (int i = startRow; i < endRow; i++) { 2395 byte[] data = Bytes.toBytes(String.valueOf(i)); 2396 Put put = new Put(data); 2397 put.addColumn(f, null, data); 2398 t.put(put); 2399 } 2400 } 2401 2402 public void loadRandomRows(final Table t, final byte[] f, int rowSize, int totalRows) 2403 throws IOException { 2404 Random r = new Random(); 2405 byte[] row = new byte[rowSize]; 2406 for (int i = 0; i < totalRows; i++) { 2407 r.nextBytes(row); 2408 Put put = new Put(row); 2409 put.addColumn(f, new byte[]{0}, new byte[]{0}); 2410 t.put(put); 2411 } 2412 } 2413 2414 public void verifyNumericRows(Table table, final byte[] f, int startRow, int endRow, 2415 int replicaId) 2416 throws IOException { 2417 for (int i = startRow; i < endRow; i++) { 2418 String failMsg = "Failed verification of row :" + i; 2419 byte[] data = Bytes.toBytes(String.valueOf(i)); 2420 Get get = new Get(data); 2421 get.setReplicaId(replicaId); 2422 get.setConsistency(Consistency.TIMELINE); 2423 Result result = table.get(get); 2424 assertTrue(failMsg, result.containsColumn(f, null)); 2425 assertEquals(failMsg, 1, result.getColumnCells(f, null).size()); 2426 Cell cell = result.getColumnLatestCell(f, null); 2427 assertTrue(failMsg, 2428 Bytes.equals(data, 0, data.length, cell.getValueArray(), cell.getValueOffset(), 2429 cell.getValueLength())); 2430 } 2431 } 2432 2433 public void verifyNumericRows(Region region, final byte[] f, int startRow, int endRow) 2434 throws IOException { 2435 verifyNumericRows((HRegion)region, f, startRow, endRow); 2436 } 2437 2438 public void verifyNumericRows(HRegion region, final byte[] f, int startRow, int endRow) 2439 throws IOException { 2440 verifyNumericRows(region, f, startRow, endRow, true); 2441 } 2442 2443 public void verifyNumericRows(Region region, final byte[] f, int startRow, int endRow, 2444 final boolean present) throws IOException { 2445 verifyNumericRows((HRegion)region, f, startRow, endRow, present); 2446 } 2447 2448 public void verifyNumericRows(HRegion region, final byte[] f, int startRow, int endRow, 2449 final boolean present) throws IOException { 2450 for (int i = startRow; i < endRow; i++) { 2451 String failMsg = "Failed verification of row :" + i; 2452 byte[] data = Bytes.toBytes(String.valueOf(i)); 2453 Result result = region.get(new Get(data)); 2454 2455 boolean hasResult = result != null && !result.isEmpty(); 2456 assertEquals(failMsg + result, present, hasResult); 2457 if (!present) continue; 2458 2459 assertTrue(failMsg, result.containsColumn(f, null)); 2460 assertEquals(failMsg, 1, result.getColumnCells(f, null).size()); 2461 Cell cell = result.getColumnLatestCell(f, null); 2462 assertTrue(failMsg, 2463 Bytes.equals(data, 0, data.length, cell.getValueArray(), cell.getValueOffset(), 2464 cell.getValueLength())); 2465 } 2466 } 2467 2468 public void deleteNumericRows(final Table t, final byte[] f, int startRow, int endRow) 2469 throws IOException { 2470 for (int i = startRow; i < endRow; i++) { 2471 byte[] data = Bytes.toBytes(String.valueOf(i)); 2472 Delete delete = new Delete(data); 2473 delete.addFamily(f); 2474 t.delete(delete); 2475 } 2476 } 2477 2478 /** 2479 * Return the number of rows in the given table. 2480 */ 2481 public int countRows(final Table table) throws IOException { 2482 return countRows(table, new Scan()); 2483 } 2484 2485 public int countRows(final Table table, final Scan scan) throws IOException { 2486 try (ResultScanner results = table.getScanner(scan)) { 2487 int count = 0; 2488 while (results.next() != null) { 2489 count++; 2490 } 2491 return count; 2492 } 2493 } 2494 2495 public int countRows(final Table table, final byte[]... families) throws IOException { 2496 Scan scan = new Scan(); 2497 for (byte[] family: families) { 2498 scan.addFamily(family); 2499 } 2500 return countRows(table, scan); 2501 } 2502 2503 /** 2504 * Return the number of rows in the given table. 2505 */ 2506 public int countRows(final TableName tableName) throws IOException { 2507 Table table = getConnection().getTable(tableName); 2508 try { 2509 return countRows(table); 2510 } finally { 2511 table.close(); 2512 } 2513 } 2514 2515 public int countRows(final Region region) throws IOException { 2516 return countRows(region, new Scan()); 2517 } 2518 2519 public int countRows(final Region region, final Scan scan) throws IOException { 2520 InternalScanner scanner = region.getScanner(scan); 2521 try { 2522 return countRows(scanner); 2523 } finally { 2524 scanner.close(); 2525 } 2526 } 2527 2528 public int countRows(final InternalScanner scanner) throws IOException { 2529 int scannedCount = 0; 2530 List<Cell> results = new ArrayList<>(); 2531 boolean hasMore = true; 2532 while (hasMore) { 2533 hasMore = scanner.next(results); 2534 scannedCount += results.size(); 2535 results.clear(); 2536 } 2537 return scannedCount; 2538 } 2539 2540 /** 2541 * Return an md5 digest of the entire contents of a table. 2542 */ 2543 public String checksumRows(final Table table) throws Exception { 2544 2545 Scan scan = new Scan(); 2546 ResultScanner results = table.getScanner(scan); 2547 MessageDigest digest = MessageDigest.getInstance("MD5"); 2548 for (Result res : results) { 2549 digest.update(res.getRow()); 2550 } 2551 results.close(); 2552 return digest.toString(); 2553 } 2554 2555 /** All the row values for the data loaded by {@link #loadTable(Table, byte[])} */ 2556 public static final byte[][] ROWS = new byte[(int) Math.pow('z' - 'a' + 1, 3)][3]; // ~52KB 2557 static { 2558 int i = 0; 2559 for (byte b1 = 'a'; b1 <= 'z'; b1++) { 2560 for (byte b2 = 'a'; b2 <= 'z'; b2++) { 2561 for (byte b3 = 'a'; b3 <= 'z'; b3++) { 2562 ROWS[i][0] = b1; 2563 ROWS[i][1] = b2; 2564 ROWS[i][2] = b3; 2565 i++; 2566 } 2567 } 2568 } 2569 } 2570 2571 public static final byte[][] KEYS = { 2572 HConstants.EMPTY_BYTE_ARRAY, Bytes.toBytes("bbb"), 2573 Bytes.toBytes("ccc"), Bytes.toBytes("ddd"), Bytes.toBytes("eee"), 2574 Bytes.toBytes("fff"), Bytes.toBytes("ggg"), Bytes.toBytes("hhh"), 2575 Bytes.toBytes("iii"), Bytes.toBytes("jjj"), Bytes.toBytes("kkk"), 2576 Bytes.toBytes("lll"), Bytes.toBytes("mmm"), Bytes.toBytes("nnn"), 2577 Bytes.toBytes("ooo"), Bytes.toBytes("ppp"), Bytes.toBytes("qqq"), 2578 Bytes.toBytes("rrr"), Bytes.toBytes("sss"), Bytes.toBytes("ttt"), 2579 Bytes.toBytes("uuu"), Bytes.toBytes("vvv"), Bytes.toBytes("www"), 2580 Bytes.toBytes("xxx"), Bytes.toBytes("yyy") 2581 }; 2582 2583 public static final byte[][] KEYS_FOR_HBA_CREATE_TABLE = { 2584 Bytes.toBytes("bbb"), 2585 Bytes.toBytes("ccc"), Bytes.toBytes("ddd"), Bytes.toBytes("eee"), 2586 Bytes.toBytes("fff"), Bytes.toBytes("ggg"), Bytes.toBytes("hhh"), 2587 Bytes.toBytes("iii"), Bytes.toBytes("jjj"), Bytes.toBytes("kkk"), 2588 Bytes.toBytes("lll"), Bytes.toBytes("mmm"), Bytes.toBytes("nnn"), 2589 Bytes.toBytes("ooo"), Bytes.toBytes("ppp"), Bytes.toBytes("qqq"), 2590 Bytes.toBytes("rrr"), Bytes.toBytes("sss"), Bytes.toBytes("ttt"), 2591 Bytes.toBytes("uuu"), Bytes.toBytes("vvv"), Bytes.toBytes("www"), 2592 Bytes.toBytes("xxx"), Bytes.toBytes("yyy"), Bytes.toBytes("zzz") 2593 }; 2594 2595 /** 2596 * Create rows in hbase:meta for regions of the specified table with the specified 2597 * start keys. The first startKey should be a 0 length byte array if you 2598 * want to form a proper range of regions. 2599 * @param conf 2600 * @param htd 2601 * @param startKeys 2602 * @return list of region info for regions added to meta 2603 * @throws IOException 2604 * @deprecated since 2.0 version and will be removed in 3.0 version. 2605 * use {@link #createMultiRegionsInMeta(Configuration, TableDescriptor, byte[][])} 2606 */ 2607 @Deprecated 2608 public List<HRegionInfo> createMultiRegionsInMeta(final Configuration conf, 2609 final HTableDescriptor htd, byte [][] startKeys) throws IOException { 2610 return createMultiRegionsInMeta(conf, (TableDescriptor) htd, startKeys) 2611 .stream().map(ImmutableHRegionInfo::new).collect(Collectors.toList()); 2612 } 2613 /** 2614 * Create rows in hbase:meta for regions of the specified table with the specified 2615 * start keys. The first startKey should be a 0 length byte array if you 2616 * want to form a proper range of regions. 2617 * @param conf 2618 * @param htd 2619 * @param startKeys 2620 * @return list of region info for regions added to meta 2621 * @throws IOException 2622 */ 2623 public List<RegionInfo> createMultiRegionsInMeta(final Configuration conf, 2624 final TableDescriptor htd, byte [][] startKeys) 2625 throws IOException { 2626 Table meta = getConnection().getTable(TableName.META_TABLE_NAME); 2627 Arrays.sort(startKeys, Bytes.BYTES_COMPARATOR); 2628 List<RegionInfo> newRegions = new ArrayList<>(startKeys.length); 2629 MetaTableAccessor 2630 .updateTableState(getConnection(), htd.getTableName(), TableState.State.ENABLED); 2631 // add custom ones 2632 for (int i = 0; i < startKeys.length; i++) { 2633 int j = (i + 1) % startKeys.length; 2634 RegionInfo hri = RegionInfoBuilder.newBuilder(htd.getTableName()) 2635 .setStartKey(startKeys[i]) 2636 .setEndKey(startKeys[j]) 2637 .build(); 2638 MetaTableAccessor.addRegionToMeta(getConnection(), hri); 2639 newRegions.add(hri); 2640 } 2641 2642 meta.close(); 2643 return newRegions; 2644 } 2645 2646 /** 2647 * Create an unmanaged WAL. Be sure to close it when you're through. 2648 */ 2649 public static WAL createWal(final Configuration conf, final Path rootDir, final RegionInfo hri) 2650 throws IOException { 2651 // The WAL subsystem will use the default rootDir rather than the passed in rootDir 2652 // unless I pass along via the conf. 2653 Configuration confForWAL = new Configuration(conf); 2654 confForWAL.set(HConstants.HBASE_DIR, rootDir.toString()); 2655 return new WALFactory(confForWAL, "hregion-" + RandomStringUtils.randomNumeric(8)).getWAL(hri); 2656 } 2657 2658 2659 /** 2660 * Create a region with it's own WAL. Be sure to call 2661 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} to clean up all resources. 2662 */ 2663 public static HRegion createRegionAndWAL(final RegionInfo info, final Path rootDir, 2664 final Configuration conf, final TableDescriptor htd) throws IOException { 2665 return createRegionAndWAL(info, rootDir, conf, htd, true); 2666 } 2667 2668 /** 2669 * Create a region with it's own WAL. Be sure to call 2670 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} to clean up all resources. 2671 */ 2672 public static HRegion createRegionAndWAL(final RegionInfo info, final Path rootDir, 2673 final Configuration conf, final TableDescriptor htd, BlockCache blockCache) 2674 throws IOException { 2675 HRegion region = createRegionAndWAL(info, rootDir, conf, htd, false); 2676 region.setBlockCache(blockCache); 2677 region.initialize(); 2678 return region; 2679 } 2680 /** 2681 * Create a region with it's own WAL. Be sure to call 2682 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} to clean up all resources. 2683 */ 2684 public static HRegion createRegionAndWAL(final RegionInfo info, final Path rootDir, 2685 final Configuration conf, final TableDescriptor htd, MobFileCache mobFileCache) 2686 throws IOException { 2687 HRegion region = createRegionAndWAL(info, rootDir, conf, htd, false); 2688 region.setMobFileCache(mobFileCache); 2689 region.initialize(); 2690 return region; 2691 } 2692 2693 /** 2694 * Create a region with it's own WAL. Be sure to call 2695 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} to clean up all resources. 2696 */ 2697 public static HRegion createRegionAndWAL(final RegionInfo info, final Path rootDir, 2698 final Configuration conf, final TableDescriptor htd, boolean initialize) 2699 throws IOException { 2700 ChunkCreator.initialize(MemStoreLAB.CHUNK_SIZE_DEFAULT, false, 0, 0, 2701 0, null, MemStoreLAB.INDEX_CHUNK_SIZE_PERCENTAGE_DEFAULT); 2702 WAL wal = createWal(conf, rootDir, info); 2703 return HRegion.createHRegion(info, rootDir, conf, htd, wal, initialize); 2704 } 2705 2706 /** 2707 * Returns all rows from the hbase:meta table. 2708 * 2709 * @throws IOException When reading the rows fails. 2710 */ 2711 public List<byte[]> getMetaTableRows() throws IOException { 2712 // TODO: Redo using MetaTableAccessor class 2713 Table t = getConnection().getTable(TableName.META_TABLE_NAME); 2714 List<byte[]> rows = new ArrayList<>(); 2715 ResultScanner s = t.getScanner(new Scan()); 2716 for (Result result : s) { 2717 LOG.info("getMetaTableRows: row -> " + 2718 Bytes.toStringBinary(result.getRow())); 2719 rows.add(result.getRow()); 2720 } 2721 s.close(); 2722 t.close(); 2723 return rows; 2724 } 2725 2726 /** 2727 * Returns all rows from the hbase:meta table for a given user table 2728 * 2729 * @throws IOException When reading the rows fails. 2730 */ 2731 public List<byte[]> getMetaTableRows(TableName tableName) throws IOException { 2732 // TODO: Redo using MetaTableAccessor. 2733 Table t = getConnection().getTable(TableName.META_TABLE_NAME); 2734 List<byte[]> rows = new ArrayList<>(); 2735 ResultScanner s = t.getScanner(new Scan()); 2736 for (Result result : s) { 2737 RegionInfo info = MetaTableAccessor.getRegionInfo(result); 2738 if (info == null) { 2739 LOG.error("No region info for row " + Bytes.toString(result.getRow())); 2740 // TODO figure out what to do for this new hosed case. 2741 continue; 2742 } 2743 2744 if (info.getTable().equals(tableName)) { 2745 LOG.info("getMetaTableRows: row -> " + 2746 Bytes.toStringBinary(result.getRow()) + info); 2747 rows.add(result.getRow()); 2748 } 2749 } 2750 s.close(); 2751 t.close(); 2752 return rows; 2753 } 2754 2755 /** 2756 * Returns all regions of the specified table 2757 * 2758 * @param tableName the table name 2759 * @return all regions of the specified table 2760 * @throws IOException when getting the regions fails. 2761 */ 2762 private List<RegionInfo> getRegions(TableName tableName) throws IOException { 2763 try (Admin admin = getConnection().getAdmin()) { 2764 return admin.getRegions(tableName); 2765 } 2766 } 2767 2768 /* 2769 * Find any other region server which is different from the one identified by parameter 2770 * @param rs 2771 * @return another region server 2772 */ 2773 public HRegionServer getOtherRegionServer(HRegionServer rs) { 2774 for (JVMClusterUtil.RegionServerThread rst : 2775 getMiniHBaseCluster().getRegionServerThreads()) { 2776 if (!(rst.getRegionServer() == rs)) { 2777 return rst.getRegionServer(); 2778 } 2779 } 2780 return null; 2781 } 2782 2783 /** 2784 * Tool to get the reference to the region server object that holds the 2785 * region of the specified user table. 2786 * @param tableName user table to lookup in hbase:meta 2787 * @return region server that holds it, null if the row doesn't exist 2788 * @throws IOException 2789 * @throws InterruptedException 2790 */ 2791 public HRegionServer getRSForFirstRegionInTable(TableName tableName) 2792 throws IOException, InterruptedException { 2793 List<RegionInfo> regions = getRegions(tableName); 2794 if (regions == null || regions.isEmpty()) { 2795 return null; 2796 } 2797 LOG.debug("Found " + regions.size() + " regions for table " + 2798 tableName); 2799 2800 byte[] firstRegionName = regions.stream() 2801 .filter(r -> !r.isOffline()) 2802 .map(RegionInfo::getRegionName) 2803 .findFirst() 2804 .orElseThrow(() -> new IOException("online regions not found in table " + tableName)); 2805 2806 LOG.debug("firstRegionName=" + Bytes.toString(firstRegionName)); 2807 long pause = getConfiguration().getLong(HConstants.HBASE_CLIENT_PAUSE, 2808 HConstants.DEFAULT_HBASE_CLIENT_PAUSE); 2809 int numRetries = getConfiguration().getInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2810 HConstants.DEFAULT_HBASE_CLIENT_RETRIES_NUMBER); 2811 RetryCounter retrier = new RetryCounter(numRetries+1, (int)pause, TimeUnit.MICROSECONDS); 2812 while(retrier.shouldRetry()) { 2813 int index = getMiniHBaseCluster().getServerWith(firstRegionName); 2814 if (index != -1) { 2815 return getMiniHBaseCluster().getRegionServerThreads().get(index).getRegionServer(); 2816 } 2817 // Came back -1. Region may not be online yet. Sleep a while. 2818 retrier.sleepUntilNextRetry(); 2819 } 2820 return null; 2821 } 2822 2823 /** 2824 * Starts a <code>MiniMRCluster</code> with a default number of 2825 * <code>TaskTracker</code>'s. 2826 * 2827 * @throws IOException When starting the cluster fails. 2828 */ 2829 public MiniMRCluster startMiniMapReduceCluster() throws IOException { 2830 // Set a very high max-disk-utilization percentage to avoid the NodeManagers from failing. 2831 conf.setIfUnset( 2832 "yarn.nodemanager.disk-health-checker.max-disk-utilization-per-disk-percentage", 2833 "99.0"); 2834 startMiniMapReduceCluster(2); 2835 return mrCluster; 2836 } 2837 2838 /** 2839 * Tasktracker has a bug where changing the hadoop.log.dir system property 2840 * will not change its internal static LOG_DIR variable. 2841 */ 2842 private void forceChangeTaskLogDir() { 2843 Field logDirField; 2844 try { 2845 logDirField = TaskLog.class.getDeclaredField("LOG_DIR"); 2846 logDirField.setAccessible(true); 2847 2848 Field modifiersField = Field.class.getDeclaredField("modifiers"); 2849 modifiersField.setAccessible(true); 2850 modifiersField.setInt(logDirField, logDirField.getModifiers() & ~Modifier.FINAL); 2851 2852 logDirField.set(null, new File(hadoopLogDir, "userlogs")); 2853 } catch (SecurityException e) { 2854 throw new RuntimeException(e); 2855 } catch (NoSuchFieldException e) { 2856 // TODO Auto-generated catch block 2857 throw new RuntimeException(e); 2858 } catch (IllegalArgumentException e) { 2859 throw new RuntimeException(e); 2860 } catch (IllegalAccessException e) { 2861 throw new RuntimeException(e); 2862 } 2863 } 2864 2865 /** 2866 * Starts a <code>MiniMRCluster</code>. Call {@link #setFileSystemURI(String)} to use a different 2867 * filesystem. 2868 * @param servers The number of <code>TaskTracker</code>'s to start. 2869 * @throws IOException When starting the cluster fails. 2870 */ 2871 private void startMiniMapReduceCluster(final int servers) throws IOException { 2872 if (mrCluster != null) { 2873 throw new IllegalStateException("MiniMRCluster is already running"); 2874 } 2875 LOG.info("Starting mini mapreduce cluster..."); 2876 setupClusterTestDir(); 2877 createDirsAndSetProperties(); 2878 2879 forceChangeTaskLogDir(); 2880 2881 //// hadoop2 specific settings 2882 // Tests were failing because this process used 6GB of virtual memory and was getting killed. 2883 // we up the VM usable so that processes don't get killed. 2884 conf.setFloat("yarn.nodemanager.vmem-pmem-ratio", 8.0f); 2885 2886 // Tests were failing due to MAPREDUCE-4880 / MAPREDUCE-4607 against hadoop 2.0.2-alpha and 2887 // this avoids the problem by disabling speculative task execution in tests. 2888 conf.setBoolean("mapreduce.map.speculative", false); 2889 conf.setBoolean("mapreduce.reduce.speculative", false); 2890 //// 2891 2892 // Allow the user to override FS URI for this map-reduce cluster to use. 2893 mrCluster = new MiniMRCluster(servers, 2894 FS_URI != null ? FS_URI : FileSystem.get(conf).getUri().toString(), 1, 2895 null, null, new JobConf(this.conf)); 2896 JobConf jobConf = MapreduceTestingShim.getJobConf(mrCluster); 2897 if (jobConf == null) { 2898 jobConf = mrCluster.createJobConf(); 2899 } 2900 2901 jobConf.set("mapreduce.cluster.local.dir", 2902 conf.get("mapreduce.cluster.local.dir")); //Hadoop MiniMR overwrites this while it should not 2903 LOG.info("Mini mapreduce cluster started"); 2904 2905 // In hadoop2, YARN/MR2 starts a mini cluster with its own conf instance and updates settings. 2906 // Our HBase MR jobs need several of these settings in order to properly run. So we copy the 2907 // necessary config properties here. YARN-129 required adding a few properties. 2908 conf.set("mapreduce.jobtracker.address", jobConf.get("mapreduce.jobtracker.address")); 2909 // this for mrv2 support; mr1 ignores this 2910 conf.set("mapreduce.framework.name", "yarn"); 2911 conf.setBoolean("yarn.is.minicluster", true); 2912 String rmAddress = jobConf.get("yarn.resourcemanager.address"); 2913 if (rmAddress != null) { 2914 conf.set("yarn.resourcemanager.address", rmAddress); 2915 } 2916 String historyAddress = jobConf.get("mapreduce.jobhistory.address"); 2917 if (historyAddress != null) { 2918 conf.set("mapreduce.jobhistory.address", historyAddress); 2919 } 2920 String schedulerAddress = 2921 jobConf.get("yarn.resourcemanager.scheduler.address"); 2922 if (schedulerAddress != null) { 2923 conf.set("yarn.resourcemanager.scheduler.address", schedulerAddress); 2924 } 2925 String mrJobHistoryWebappAddress = 2926 jobConf.get("mapreduce.jobhistory.webapp.address"); 2927 if (mrJobHistoryWebappAddress != null) { 2928 conf.set("mapreduce.jobhistory.webapp.address", mrJobHistoryWebappAddress); 2929 } 2930 String yarnRMWebappAddress = 2931 jobConf.get("yarn.resourcemanager.webapp.address"); 2932 if (yarnRMWebappAddress != null) { 2933 conf.set("yarn.resourcemanager.webapp.address", yarnRMWebappAddress); 2934 } 2935 } 2936 2937 /** 2938 * Stops the previously started <code>MiniMRCluster</code>. 2939 */ 2940 public void shutdownMiniMapReduceCluster() { 2941 if (mrCluster != null) { 2942 LOG.info("Stopping mini mapreduce cluster..."); 2943 mrCluster.shutdown(); 2944 mrCluster = null; 2945 LOG.info("Mini mapreduce cluster stopped"); 2946 } 2947 // Restore configuration to point to local jobtracker 2948 conf.set("mapreduce.jobtracker.address", "local"); 2949 } 2950 2951 /** 2952 * Create a stubbed out RegionServerService, mainly for getting FS. 2953 */ 2954 public RegionServerServices createMockRegionServerService() throws IOException { 2955 return createMockRegionServerService((ServerName)null); 2956 } 2957 2958 /** 2959 * Create a stubbed out RegionServerService, mainly for getting FS. 2960 * This version is used by TestTokenAuthentication 2961 */ 2962 public RegionServerServices createMockRegionServerService(RpcServerInterface rpc) throws 2963 IOException { 2964 final MockRegionServerServices rss = new MockRegionServerServices(getZooKeeperWatcher()); 2965 rss.setFileSystem(getTestFileSystem()); 2966 rss.setRpcServer(rpc); 2967 return rss; 2968 } 2969 2970 /** 2971 * Create a stubbed out RegionServerService, mainly for getting FS. 2972 * This version is used by TestOpenRegionHandler 2973 */ 2974 public RegionServerServices createMockRegionServerService(ServerName name) throws IOException { 2975 final MockRegionServerServices rss = new MockRegionServerServices(getZooKeeperWatcher(), name); 2976 rss.setFileSystem(getTestFileSystem()); 2977 return rss; 2978 } 2979 2980 /** 2981 * Switches the logger for the given class to DEBUG level. 2982 * 2983 * @param clazz The class for which to switch to debug logging. 2984 */ 2985 public void enableDebug(Class<?> clazz) { 2986 Logger l = LoggerFactory.getLogger(clazz); 2987 if (l instanceof Log4JLogger) { 2988 ((Log4JLogger) l).getLogger().setLevel(org.apache.log4j.Level.DEBUG); 2989 } else if (l instanceof Log4jLoggerAdapter) { 2990 LogManager.getLogger(clazz).setLevel(org.apache.log4j.Level.DEBUG); 2991 } else if (l instanceof Jdk14Logger) { 2992 ((Jdk14Logger) l).getLogger().setLevel(java.util.logging.Level.ALL); 2993 } 2994 } 2995 2996 /** 2997 * Expire the Master's session 2998 * @throws Exception 2999 */ 3000 public void expireMasterSession() throws Exception { 3001 HMaster master = getMiniHBaseCluster().getMaster(); 3002 expireSession(master.getZooKeeper(), false); 3003 } 3004 3005 /** 3006 * Expire a region server's session 3007 * @param index which RS 3008 */ 3009 public void expireRegionServerSession(int index) throws Exception { 3010 HRegionServer rs = getMiniHBaseCluster().getRegionServer(index); 3011 expireSession(rs.getZooKeeper(), false); 3012 decrementMinRegionServerCount(); 3013 } 3014 3015 private void decrementMinRegionServerCount() { 3016 // decrement the count for this.conf, for newly spwaned master 3017 // this.hbaseCluster shares this configuration too 3018 decrementMinRegionServerCount(getConfiguration()); 3019 3020 // each master thread keeps a copy of configuration 3021 for (MasterThread master : getHBaseCluster().getMasterThreads()) { 3022 decrementMinRegionServerCount(master.getMaster().getConfiguration()); 3023 } 3024 } 3025 3026 private void decrementMinRegionServerCount(Configuration conf) { 3027 int currentCount = conf.getInt( 3028 ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, -1); 3029 if (currentCount != -1) { 3030 conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, 3031 Math.max(currentCount - 1, 1)); 3032 } 3033 } 3034 3035 public void expireSession(ZKWatcher nodeZK) throws Exception { 3036 expireSession(nodeZK, false); 3037 } 3038 3039 /** 3040 * Expire a ZooKeeper session as recommended in ZooKeeper documentation 3041 * http://hbase.apache.org/book.html#trouble.zookeeper 3042 * There are issues when doing this: 3043 * [1] http://www.mail-archive.com/dev@zookeeper.apache.org/msg01942.html 3044 * [2] https://issues.apache.org/jira/browse/ZOOKEEPER-1105 3045 * 3046 * @param nodeZK - the ZK watcher to expire 3047 * @param checkStatus - true to check if we can create a Table with the 3048 * current configuration. 3049 */ 3050 public void expireSession(ZKWatcher nodeZK, boolean checkStatus) 3051 throws Exception { 3052 Configuration c = new Configuration(this.conf); 3053 String quorumServers = ZKConfig.getZKQuorumServersString(c); 3054 ZooKeeper zk = nodeZK.getRecoverableZooKeeper().getZooKeeper(); 3055 byte[] password = zk.getSessionPasswd(); 3056 long sessionID = zk.getSessionId(); 3057 3058 // Expiry seems to be asynchronous (see comment from P. Hunt in [1]), 3059 // so we create a first watcher to be sure that the 3060 // event was sent. We expect that if our watcher receives the event 3061 // other watchers on the same machine will get is as well. 3062 // When we ask to close the connection, ZK does not close it before 3063 // we receive all the events, so don't have to capture the event, just 3064 // closing the connection should be enough. 3065 ZooKeeper monitor = new ZooKeeper(quorumServers, 3066 1000, new org.apache.zookeeper.Watcher(){ 3067 @Override 3068 public void process(WatchedEvent watchedEvent) { 3069 LOG.info("Monitor ZKW received event="+watchedEvent); 3070 } 3071 } , sessionID, password); 3072 3073 // Making it expire 3074 ZooKeeper newZK = new ZooKeeper(quorumServers, 3075 1000, EmptyWatcher.instance, sessionID, password); 3076 3077 //ensure that we have connection to the server before closing down, otherwise 3078 //the close session event will be eaten out before we start CONNECTING state 3079 long start = System.currentTimeMillis(); 3080 while (newZK.getState() != States.CONNECTED 3081 && System.currentTimeMillis() - start < 1000) { 3082 Thread.sleep(1); 3083 } 3084 newZK.close(); 3085 LOG.info("ZK Closed Session 0x" + Long.toHexString(sessionID)); 3086 3087 // Now closing & waiting to be sure that the clients get it. 3088 monitor.close(); 3089 3090 if (checkStatus) { 3091 getConnection().getTable(TableName.META_TABLE_NAME).close(); 3092 } 3093 } 3094 3095 /** 3096 * Get the Mini HBase cluster. 3097 * 3098 * @return hbase cluster 3099 * @see #getHBaseClusterInterface() 3100 */ 3101 public MiniHBaseCluster getHBaseCluster() { 3102 return getMiniHBaseCluster(); 3103 } 3104 3105 /** 3106 * Returns the HBaseCluster instance. 3107 * <p>Returned object can be any of the subclasses of HBaseCluster, and the 3108 * tests referring this should not assume that the cluster is a mini cluster or a 3109 * distributed one. If the test only works on a mini cluster, then specific 3110 * method {@link #getMiniHBaseCluster()} can be used instead w/o the 3111 * need to type-cast. 3112 */ 3113 public HBaseCluster getHBaseClusterInterface() { 3114 //implementation note: we should rename this method as #getHBaseCluster(), 3115 //but this would require refactoring 90+ calls. 3116 return hbaseCluster; 3117 } 3118 3119 /** 3120 * Get a Connection to the cluster. 3121 * Not thread-safe (This class needs a lot of work to make it thread-safe). 3122 * @return A Connection that can be shared. Don't close. Will be closed on shutdown of cluster. 3123 * @throws IOException 3124 */ 3125 public Connection getConnection() throws IOException { 3126 if (this.connection == null) { 3127 this.connection = ConnectionFactory.createConnection(this.conf); 3128 } 3129 return this.connection; 3130 } 3131 3132 /** 3133 * Returns a Admin instance. 3134 * This instance is shared between HBaseTestingUtility instance users. Closing it has no effect, 3135 * it will be closed automatically when the cluster shutdowns 3136 * 3137 * @return HBaseAdmin instance which is guaranteed to support only {@link Admin} interface. 3138 * Functions in HBaseAdmin not provided by {@link Admin} interface can be changed/deleted 3139 * anytime. 3140 * @deprecated Since 2.0. Will be removed in 3.0. Use {@link #getAdmin()} instead. 3141 */ 3142 @Deprecated 3143 public synchronized HBaseAdmin getHBaseAdmin() 3144 throws IOException { 3145 if (hbaseAdmin == null){ 3146 this.hbaseAdmin = (HBaseAdmin) getConnection().getAdmin(); 3147 } 3148 return hbaseAdmin; 3149 } 3150 3151 /** 3152 * Returns an Admin instance which is shared between HBaseTestingUtility instance users. 3153 * Closing it has no effect, it will be closed automatically when the cluster shutdowns 3154 */ 3155 public synchronized Admin getAdmin() throws IOException { 3156 if (hbaseAdmin == null){ 3157 this.hbaseAdmin = (HBaseAdmin) getConnection().getAdmin(); 3158 } 3159 return hbaseAdmin; 3160 } 3161 3162 private HBaseAdmin hbaseAdmin = null; 3163 3164 /** 3165 * Returns an {@link Hbck} instance. Needs be closed when done. 3166 */ 3167 public Hbck getHbck() throws IOException { 3168 return getConnection().getHbck(); 3169 } 3170 3171 /** 3172 * Unassign the named region. 3173 * 3174 * @param regionName The region to unassign. 3175 */ 3176 public void unassignRegion(String regionName) throws IOException { 3177 unassignRegion(Bytes.toBytes(regionName)); 3178 } 3179 3180 /** 3181 * Unassign the named region. 3182 * 3183 * @param regionName The region to unassign. 3184 */ 3185 public void unassignRegion(byte[] regionName) throws IOException { 3186 getAdmin().unassign(regionName, true); 3187 } 3188 3189 /** 3190 * Closes the region containing the given row. 3191 * 3192 * @param row The row to find the containing region. 3193 * @param table The table to find the region. 3194 */ 3195 public void unassignRegionByRow(String row, RegionLocator table) throws IOException { 3196 unassignRegionByRow(Bytes.toBytes(row), table); 3197 } 3198 3199 /** 3200 * Closes the region containing the given row. 3201 * 3202 * @param row The row to find the containing region. 3203 * @param table The table to find the region. 3204 * @throws IOException 3205 */ 3206 public void unassignRegionByRow(byte[] row, RegionLocator table) throws IOException { 3207 HRegionLocation hrl = table.getRegionLocation(row); 3208 unassignRegion(hrl.getRegionInfo().getRegionName()); 3209 } 3210 3211 /* 3212 * Retrieves a splittable region randomly from tableName 3213 * 3214 * @param tableName name of table 3215 * @param maxAttempts maximum number of attempts, unlimited for value of -1 3216 * @return the HRegion chosen, null if none was found within limit of maxAttempts 3217 */ 3218 public HRegion getSplittableRegion(TableName tableName, int maxAttempts) { 3219 List<HRegion> regions = getHBaseCluster().getRegions(tableName); 3220 int regCount = regions.size(); 3221 Set<Integer> attempted = new HashSet<>(); 3222 int idx; 3223 int attempts = 0; 3224 do { 3225 regions = getHBaseCluster().getRegions(tableName); 3226 if (regCount != regions.size()) { 3227 // if there was region movement, clear attempted Set 3228 attempted.clear(); 3229 } 3230 regCount = regions.size(); 3231 // There are chances that before we get the region for the table from an RS the region may 3232 // be going for CLOSE. This may be because online schema change is enabled 3233 if (regCount > 0) { 3234 idx = random.nextInt(regCount); 3235 // if we have just tried this region, there is no need to try again 3236 if (attempted.contains(idx)) 3237 continue; 3238 try { 3239 regions.get(idx).checkSplit(); 3240 return regions.get(idx); 3241 } catch (Exception ex) { 3242 LOG.warn("Caught exception", ex); 3243 attempted.add(idx); 3244 } 3245 } 3246 attempts++; 3247 } while (maxAttempts == -1 || attempts < maxAttempts); 3248 return null; 3249 } 3250 3251 public MiniDFSCluster getDFSCluster() { 3252 return dfsCluster; 3253 } 3254 3255 public void setDFSCluster(MiniDFSCluster cluster) throws IllegalStateException, IOException { 3256 setDFSCluster(cluster, true); 3257 } 3258 3259 /** 3260 * Set the MiniDFSCluster 3261 * @param cluster cluster to use 3262 * @param requireDown require the that cluster not be "up" (MiniDFSCluster#isClusterUp) before 3263 * it is set. 3264 * @throws IllegalStateException if the passed cluster is up when it is required to be down 3265 * @throws IOException if the FileSystem could not be set from the passed dfs cluster 3266 */ 3267 public void setDFSCluster(MiniDFSCluster cluster, boolean requireDown) 3268 throws IllegalStateException, IOException { 3269 if (dfsCluster != null && requireDown && dfsCluster.isClusterUp()) { 3270 throw new IllegalStateException("DFSCluster is already running! Shut it down first."); 3271 } 3272 this.dfsCluster = cluster; 3273 this.setFs(); 3274 } 3275 3276 public FileSystem getTestFileSystem() throws IOException { 3277 return HFileSystem.get(conf); 3278 } 3279 3280 /** 3281 * Wait until all regions in a table have been assigned. Waits default timeout before giving up 3282 * (30 seconds). 3283 * @param table Table to wait on. 3284 * @throws InterruptedException 3285 * @throws IOException 3286 */ 3287 public void waitTableAvailable(TableName table) 3288 throws InterruptedException, IOException { 3289 waitTableAvailable(table.getName(), 30000); 3290 } 3291 3292 public void waitTableAvailable(TableName table, long timeoutMillis) 3293 throws InterruptedException, IOException { 3294 waitFor(timeoutMillis, predicateTableAvailable(table)); 3295 } 3296 3297 /** 3298 * Wait until all regions in a table have been assigned 3299 * @param table Table to wait on. 3300 * @param timeoutMillis Timeout. 3301 * @throws InterruptedException 3302 * @throws IOException 3303 */ 3304 public void waitTableAvailable(byte[] table, long timeoutMillis) 3305 throws InterruptedException, IOException { 3306 waitFor(timeoutMillis, predicateTableAvailable(TableName.valueOf(table))); 3307 } 3308 3309 public String explainTableAvailability(TableName tableName) throws IOException { 3310 String msg = explainTableState(tableName, TableState.State.ENABLED) + ", "; 3311 if (getHBaseCluster().getMaster().isAlive()) { 3312 Map<RegionInfo, ServerName> assignments = 3313 getHBaseCluster().getMaster().getAssignmentManager().getRegionStates() 3314 .getRegionAssignments(); 3315 final List<Pair<RegionInfo, ServerName>> metaLocations = 3316 MetaTableAccessor.getTableRegionsAndLocations(connection, tableName); 3317 for (Pair<RegionInfo, ServerName> metaLocation : metaLocations) { 3318 RegionInfo hri = metaLocation.getFirst(); 3319 ServerName sn = metaLocation.getSecond(); 3320 if (!assignments.containsKey(hri)) { 3321 msg += ", region " + hri 3322 + " not assigned, but found in meta, it expected to be on " + sn; 3323 3324 } else if (sn == null) { 3325 msg += ", region " + hri 3326 + " assigned, but has no server in meta"; 3327 } else if (!sn.equals(assignments.get(hri))) { 3328 msg += ", region " + hri 3329 + " assigned, but has different servers in meta and AM ( " + 3330 sn + " <> " + assignments.get(hri); 3331 } 3332 } 3333 } 3334 return msg; 3335 } 3336 3337 public String explainTableState(final TableName table, TableState.State state) 3338 throws IOException { 3339 TableState tableState = MetaTableAccessor.getTableState(connection, table); 3340 if (tableState == null) { 3341 return "TableState in META: No table state in META for table " + table 3342 + " last state in meta (including deleted is " + findLastTableState(table) + ")"; 3343 } else if (!tableState.inStates(state)) { 3344 return "TableState in META: Not " + state + " state, but " + tableState; 3345 } else { 3346 return "TableState in META: OK"; 3347 } 3348 } 3349 3350 @Nullable 3351 public TableState findLastTableState(final TableName table) throws IOException { 3352 final AtomicReference<TableState> lastTableState = new AtomicReference<>(null); 3353 MetaTableAccessor.Visitor visitor = new MetaTableAccessor.Visitor() { 3354 @Override 3355 public boolean visit(Result r) throws IOException { 3356 if (!Arrays.equals(r.getRow(), table.getName())) 3357 return false; 3358 TableState state = MetaTableAccessor.getTableState(r); 3359 if (state != null) 3360 lastTableState.set(state); 3361 return true; 3362 } 3363 }; 3364 MetaTableAccessor 3365 .scanMeta(connection, null, null, 3366 MetaTableAccessor.QueryType.TABLE, 3367 Integer.MAX_VALUE, visitor); 3368 return lastTableState.get(); 3369 } 3370 3371 /** 3372 * Waits for a table to be 'enabled'. Enabled means that table is set as 'enabled' and the 3373 * regions have been all assigned. Will timeout after default period (30 seconds) 3374 * Tolerates nonexistent table. 3375 * @param table the table to wait on. 3376 * @throws InterruptedException if interrupted while waiting 3377 * @throws IOException if an IO problem is encountered 3378 */ 3379 public void waitTableEnabled(TableName table) 3380 throws InterruptedException, IOException { 3381 waitTableEnabled(table, 30000); 3382 } 3383 3384 /** 3385 * Waits for a table to be 'enabled'. Enabled means that table is set as 'enabled' and the 3386 * regions have been all assigned. 3387 * @see #waitTableEnabled(TableName, long) 3388 * @param table Table to wait on. 3389 * @param timeoutMillis Time to wait on it being marked enabled. 3390 * @throws InterruptedException 3391 * @throws IOException 3392 */ 3393 public void waitTableEnabled(byte[] table, long timeoutMillis) 3394 throws InterruptedException, IOException { 3395 waitTableEnabled(TableName.valueOf(table), timeoutMillis); 3396 } 3397 3398 public void waitTableEnabled(TableName table, long timeoutMillis) 3399 throws IOException { 3400 waitFor(timeoutMillis, predicateTableEnabled(table)); 3401 } 3402 3403 /** 3404 * Waits for a table to be 'disabled'. Disabled means that table is set as 'disabled' 3405 * Will timeout after default period (30 seconds) 3406 * @param table Table to wait on. 3407 * @throws InterruptedException 3408 * @throws IOException 3409 */ 3410 public void waitTableDisabled(byte[] table) 3411 throws InterruptedException, IOException { 3412 waitTableDisabled(table, 30000); 3413 } 3414 3415 public void waitTableDisabled(TableName table, long millisTimeout) 3416 throws InterruptedException, IOException { 3417 waitFor(millisTimeout, predicateTableDisabled(table)); 3418 } 3419 3420 /** 3421 * Waits for a table to be 'disabled'. Disabled means that table is set as 'disabled' 3422 * @param table Table to wait on. 3423 * @param timeoutMillis Time to wait on it being marked disabled. 3424 * @throws InterruptedException 3425 * @throws IOException 3426 */ 3427 public void waitTableDisabled(byte[] table, long timeoutMillis) 3428 throws InterruptedException, IOException { 3429 waitTableDisabled(TableName.valueOf(table), timeoutMillis); 3430 } 3431 3432 /** 3433 * Make sure that at least the specified number of region servers 3434 * are running 3435 * @param num minimum number of region servers that should be running 3436 * @return true if we started some servers 3437 * @throws IOException 3438 */ 3439 public boolean ensureSomeRegionServersAvailable(final int num) 3440 throws IOException { 3441 boolean startedServer = false; 3442 MiniHBaseCluster hbaseCluster = getMiniHBaseCluster(); 3443 for (int i=hbaseCluster.getLiveRegionServerThreads().size(); i<num; ++i) { 3444 LOG.info("Started new server=" + hbaseCluster.startRegionServer()); 3445 startedServer = true; 3446 } 3447 3448 return startedServer; 3449 } 3450 3451 3452 /** 3453 * Make sure that at least the specified number of region servers 3454 * are running. We don't count the ones that are currently stopping or are 3455 * stopped. 3456 * @param num minimum number of region servers that should be running 3457 * @return true if we started some servers 3458 * @throws IOException 3459 */ 3460 public boolean ensureSomeNonStoppedRegionServersAvailable(final int num) 3461 throws IOException { 3462 boolean startedServer = ensureSomeRegionServersAvailable(num); 3463 3464 int nonStoppedServers = 0; 3465 for (JVMClusterUtil.RegionServerThread rst : 3466 getMiniHBaseCluster().getRegionServerThreads()) { 3467 3468 HRegionServer hrs = rst.getRegionServer(); 3469 if (hrs.isStopping() || hrs.isStopped()) { 3470 LOG.info("A region server is stopped or stopping:"+hrs); 3471 } else { 3472 nonStoppedServers++; 3473 } 3474 } 3475 for (int i=nonStoppedServers; i<num; ++i) { 3476 LOG.info("Started new server=" + getMiniHBaseCluster().startRegionServer()); 3477 startedServer = true; 3478 } 3479 return startedServer; 3480 } 3481 3482 3483 /** 3484 * This method clones the passed <code>c</code> configuration setting a new 3485 * user into the clone. Use it getting new instances of FileSystem. Only 3486 * works for DistributedFileSystem w/o Kerberos. 3487 * @param c Initial configuration 3488 * @param differentiatingSuffix Suffix to differentiate this user from others. 3489 * @return A new configuration instance with a different user set into it. 3490 * @throws IOException 3491 */ 3492 public static User getDifferentUser(final Configuration c, 3493 final String differentiatingSuffix) 3494 throws IOException { 3495 FileSystem currentfs = FileSystem.get(c); 3496 if (!(currentfs instanceof DistributedFileSystem) || User.isHBaseSecurityEnabled(c)) { 3497 return User.getCurrent(); 3498 } 3499 // Else distributed filesystem. Make a new instance per daemon. Below 3500 // code is taken from the AppendTestUtil over in hdfs. 3501 String username = User.getCurrent().getName() + 3502 differentiatingSuffix; 3503 User user = User.createUserForTesting(c, username, 3504 new String[]{"supergroup"}); 3505 return user; 3506 } 3507 3508 public static NavigableSet<String> getAllOnlineRegions(MiniHBaseCluster cluster) 3509 throws IOException { 3510 NavigableSet<String> online = new TreeSet<>(); 3511 for (RegionServerThread rst : cluster.getLiveRegionServerThreads()) { 3512 try { 3513 for (RegionInfo region : 3514 ProtobufUtil.getOnlineRegions(rst.getRegionServer().getRSRpcServices())) { 3515 online.add(region.getRegionNameAsString()); 3516 } 3517 } catch (RegionServerStoppedException e) { 3518 // That's fine. 3519 } 3520 } 3521 for (MasterThread mt : cluster.getLiveMasterThreads()) { 3522 try { 3523 for (RegionInfo region : 3524 ProtobufUtil.getOnlineRegions(mt.getMaster().getRSRpcServices())) { 3525 online.add(region.getRegionNameAsString()); 3526 } 3527 } catch (RegionServerStoppedException e) { 3528 // That's fine. 3529 } catch (ServerNotRunningYetException e) { 3530 // That's fine. 3531 } 3532 } 3533 return online; 3534 } 3535 3536 /** 3537 * Set maxRecoveryErrorCount in DFSClient. In 0.20 pre-append its hard-coded to 5 and 3538 * makes tests linger. Here is the exception you'll see: 3539 * <pre> 3540 * 2010-06-15 11:52:28,511 WARN [DataStreamer for file /hbase/.logs/wal.1276627923013 block 3541 * blk_928005470262850423_1021] hdfs.DFSClient$DFSOutputStream(2657): Error Recovery for block 3542 * blk_928005470262850423_1021 failed because recovery from primary datanode 127.0.0.1:53683 3543 * failed 4 times. Pipeline was 127.0.0.1:53687, 127.0.0.1:53683. Will retry... 3544 * </pre> 3545 * @param stream A DFSClient.DFSOutputStream. 3546 * @param max 3547 * @throws NoSuchFieldException 3548 * @throws SecurityException 3549 * @throws IllegalAccessException 3550 * @throws IllegalArgumentException 3551 */ 3552 public static void setMaxRecoveryErrorCount(final OutputStream stream, 3553 final int max) { 3554 try { 3555 Class<?> [] clazzes = DFSClient.class.getDeclaredClasses(); 3556 for (Class<?> clazz: clazzes) { 3557 String className = clazz.getSimpleName(); 3558 if (className.equals("DFSOutputStream")) { 3559 if (clazz.isInstance(stream)) { 3560 Field maxRecoveryErrorCountField = 3561 stream.getClass().getDeclaredField("maxRecoveryErrorCount"); 3562 maxRecoveryErrorCountField.setAccessible(true); 3563 maxRecoveryErrorCountField.setInt(stream, max); 3564 break; 3565 } 3566 } 3567 } 3568 } catch (Exception e) { 3569 LOG.info("Could not set max recovery field", e); 3570 } 3571 } 3572 3573 /** 3574 * Uses directly the assignment manager to assign the region. and waits until the specified region 3575 * has completed assignment. 3576 * @return true if the region is assigned false otherwise. 3577 */ 3578 public boolean assignRegion(final RegionInfo regionInfo) 3579 throws IOException, InterruptedException { 3580 final AssignmentManager am = getHBaseCluster().getMaster().getAssignmentManager(); 3581 am.assign(regionInfo); 3582 return AssignmentTestingUtil.waitForAssignment(am, regionInfo); 3583 } 3584 3585 /** 3586 * Move region to destination server and wait till region is completely moved and online 3587 * 3588 * @param destRegion region to move 3589 * @param destServer destination server of the region 3590 * @throws InterruptedException 3591 * @throws IOException 3592 */ 3593 public void moveRegionAndWait(RegionInfo destRegion, ServerName destServer) 3594 throws InterruptedException, IOException { 3595 HMaster master = getMiniHBaseCluster().getMaster(); 3596 // TODO: Here we start the move. The move can take a while. 3597 getAdmin().move(destRegion.getEncodedNameAsBytes(), destServer); 3598 while (true) { 3599 ServerName serverName = master.getAssignmentManager().getRegionStates() 3600 .getRegionServerOfRegion(destRegion); 3601 if (serverName != null && serverName.equals(destServer)) { 3602 assertRegionOnServer(destRegion, serverName, 2000); 3603 break; 3604 } 3605 Thread.sleep(10); 3606 } 3607 } 3608 3609 /** 3610 * Wait until all regions for a table in hbase:meta have a non-empty 3611 * info:server, up to a configuable timeout value (default is 60 seconds) 3612 * This means all regions have been deployed, 3613 * master has been informed and updated hbase:meta with the regions deployed 3614 * server. 3615 * @param tableName the table name 3616 * @throws IOException 3617 */ 3618 public void waitUntilAllRegionsAssigned(final TableName tableName) throws IOException { 3619 waitUntilAllRegionsAssigned(tableName, 3620 this.conf.getLong("hbase.client.sync.wait.timeout.msec", 60000)); 3621 } 3622 3623 /** 3624 * Waith until all system table's regions get assigned 3625 * @throws IOException 3626 */ 3627 public void waitUntilAllSystemRegionsAssigned() throws IOException { 3628 waitUntilAllRegionsAssigned(TableName.META_TABLE_NAME); 3629 waitUntilAllRegionsAssigned(TableName.NAMESPACE_TABLE_NAME); 3630 } 3631 3632 /** 3633 * Wait until all regions for a table in hbase:meta have a non-empty 3634 * info:server, or until timeout. This means all regions have been deployed, 3635 * master has been informed and updated hbase:meta with the regions deployed 3636 * server. 3637 * @param tableName the table name 3638 * @param timeout timeout, in milliseconds 3639 * @throws IOException 3640 */ 3641 public void waitUntilAllRegionsAssigned(final TableName tableName, final long timeout) 3642 throws IOException { 3643 if (!TableName.isMetaTableName(tableName)) { 3644 try (final Table meta = getConnection().getTable(TableName.META_TABLE_NAME)) { 3645 LOG.debug("Waiting until all regions of table " + tableName + " get assigned. Timeout = " + 3646 timeout + "ms"); 3647 waitFor(timeout, 200, true, new ExplainingPredicate<IOException>() { 3648 @Override 3649 public String explainFailure() throws IOException { 3650 return explainTableAvailability(tableName); 3651 } 3652 3653 @Override 3654 public boolean evaluate() throws IOException { 3655 Scan scan = new Scan(); 3656 scan.addFamily(HConstants.CATALOG_FAMILY); 3657 boolean tableFound = false; 3658 try (ResultScanner s = meta.getScanner(scan)) { 3659 for (Result r; (r = s.next()) != null;) { 3660 byte[] b = r.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER); 3661 HRegionInfo info = HRegionInfo.parseFromOrNull(b); 3662 if (info != null && info.getTable().equals(tableName)) { 3663 // Get server hosting this region from catalog family. Return false if no server 3664 // hosting this region, or if the server hosting this region was recently killed 3665 // (for fault tolerance testing). 3666 tableFound = true; 3667 byte[] server = 3668 r.getValue(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER); 3669 if (server == null) { 3670 return false; 3671 } else { 3672 byte[] startCode = 3673 r.getValue(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER); 3674 ServerName serverName = 3675 ServerName.valueOf(Bytes.toString(server).replaceFirst(":", ",") + "," + 3676 Bytes.toLong(startCode)); 3677 if (!getHBaseClusterInterface().isDistributedCluster() && 3678 getHBaseCluster().isKilledRS(serverName)) { 3679 return false; 3680 } 3681 } 3682 if (RegionStateStore.getRegionState(r, info) != RegionState.State.OPEN) { 3683 return false; 3684 } 3685 } 3686 } 3687 } 3688 if (!tableFound) { 3689 LOG.warn("Didn't find the entries for table " + tableName + " in meta, already deleted?"); 3690 } 3691 return tableFound; 3692 } 3693 }); 3694 } 3695 } 3696 LOG.info("All regions for table " + tableName + " assigned to meta. Checking AM states."); 3697 // check from the master state if we are using a mini cluster 3698 if (!getHBaseClusterInterface().isDistributedCluster()) { 3699 // So, all regions are in the meta table but make sure master knows of the assignments before 3700 // returning -- sometimes this can lag. 3701 HMaster master = getHBaseCluster().getMaster(); 3702 final RegionStates states = master.getAssignmentManager().getRegionStates(); 3703 waitFor(timeout, 200, new ExplainingPredicate<IOException>() { 3704 @Override 3705 public String explainFailure() throws IOException { 3706 return explainTableAvailability(tableName); 3707 } 3708 3709 @Override 3710 public boolean evaluate() throws IOException { 3711 List<RegionInfo> hris = states.getRegionsOfTable(tableName); 3712 return hris != null && !hris.isEmpty(); 3713 } 3714 }); 3715 } 3716 LOG.info("All regions for table " + tableName + " assigned."); 3717 } 3718 3719 /** 3720 * Do a small get/scan against one store. This is required because store 3721 * has no actual methods of querying itself, and relies on StoreScanner. 3722 */ 3723 public static List<Cell> getFromStoreFile(HStore store, 3724 Get get) throws IOException { 3725 Scan scan = new Scan(get); 3726 InternalScanner scanner = (InternalScanner) store.getScanner(scan, 3727 scan.getFamilyMap().get(store.getColumnFamilyDescriptor().getName()), 3728 // originally MultiVersionConcurrencyControl.resetThreadReadPoint() was called to set 3729 // readpoint 0. 3730 0); 3731 3732 List<Cell> result = new ArrayList<>(); 3733 scanner.next(result); 3734 if (!result.isEmpty()) { 3735 // verify that we are on the row we want: 3736 Cell kv = result.get(0); 3737 if (!CellUtil.matchingRows(kv, get.getRow())) { 3738 result.clear(); 3739 } 3740 } 3741 scanner.close(); 3742 return result; 3743 } 3744 3745 /** 3746 * Create region split keys between startkey and endKey 3747 * 3748 * @param startKey 3749 * @param endKey 3750 * @param numRegions the number of regions to be created. it has to be greater than 3. 3751 * @return resulting split keys 3752 */ 3753 public byte[][] getRegionSplitStartKeys(byte[] startKey, byte[] endKey, int numRegions){ 3754 assertTrue(numRegions>3); 3755 byte [][] tmpSplitKeys = Bytes.split(startKey, endKey, numRegions - 3); 3756 byte [][] result = new byte[tmpSplitKeys.length+1][]; 3757 System.arraycopy(tmpSplitKeys, 0, result, 1, tmpSplitKeys.length); 3758 result[0] = HConstants.EMPTY_BYTE_ARRAY; 3759 return result; 3760 } 3761 3762 /** 3763 * Do a small get/scan against one store. This is required because store 3764 * has no actual methods of querying itself, and relies on StoreScanner. 3765 */ 3766 public static List<Cell> getFromStoreFile(HStore store, 3767 byte [] row, 3768 NavigableSet<byte[]> columns 3769 ) throws IOException { 3770 Get get = new Get(row); 3771 Map<byte[], NavigableSet<byte[]>> s = get.getFamilyMap(); 3772 s.put(store.getColumnFamilyDescriptor().getName(), columns); 3773 3774 return getFromStoreFile(store,get); 3775 } 3776 3777 public static void assertKVListsEqual(String additionalMsg, 3778 final List<? extends Cell> expected, 3779 final List<? extends Cell> actual) { 3780 final int eLen = expected.size(); 3781 final int aLen = actual.size(); 3782 final int minLen = Math.min(eLen, aLen); 3783 3784 int i; 3785 for (i = 0; i < minLen 3786 && CellComparator.getInstance().compare(expected.get(i), actual.get(i)) == 0; 3787 ++i) {} 3788 3789 if (additionalMsg == null) { 3790 additionalMsg = ""; 3791 } 3792 if (!additionalMsg.isEmpty()) { 3793 additionalMsg = ". " + additionalMsg; 3794 } 3795 3796 if (eLen != aLen || i != minLen) { 3797 throw new AssertionError( 3798 "Expected and actual KV arrays differ at position " + i + ": " + 3799 safeGetAsStr(expected, i) + " (length " + eLen +") vs. " + 3800 safeGetAsStr(actual, i) + " (length " + aLen + ")" + additionalMsg); 3801 } 3802 } 3803 3804 public static <T> String safeGetAsStr(List<T> lst, int i) { 3805 if (0 <= i && i < lst.size()) { 3806 return lst.get(i).toString(); 3807 } else { 3808 return "<out_of_range>"; 3809 } 3810 } 3811 3812 public String getClusterKey() { 3813 return conf.get(HConstants.ZOOKEEPER_QUORUM) + ":" 3814 + conf.get(HConstants.ZOOKEEPER_CLIENT_PORT) + ":" 3815 + conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT, 3816 HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT); 3817 } 3818 3819 /** Creates a random table with the given parameters */ 3820 public Table createRandomTable(TableName tableName, 3821 final Collection<String> families, 3822 final int maxVersions, 3823 final int numColsPerRow, 3824 final int numFlushes, 3825 final int numRegions, 3826 final int numRowsPerFlush) 3827 throws IOException, InterruptedException { 3828 3829 LOG.info("\n\nCreating random table " + tableName + " with " + numRegions + 3830 " regions, " + numFlushes + " storefiles per region, " + 3831 numRowsPerFlush + " rows per flush, maxVersions=" + maxVersions + 3832 "\n"); 3833 3834 final Random rand = new Random(tableName.hashCode() * 17L + 12938197137L); 3835 final int numCF = families.size(); 3836 final byte[][] cfBytes = new byte[numCF][]; 3837 { 3838 int cfIndex = 0; 3839 for (String cf : families) { 3840 cfBytes[cfIndex++] = Bytes.toBytes(cf); 3841 } 3842 } 3843 3844 final int actualStartKey = 0; 3845 final int actualEndKey = Integer.MAX_VALUE; 3846 final int keysPerRegion = (actualEndKey - actualStartKey) / numRegions; 3847 final int splitStartKey = actualStartKey + keysPerRegion; 3848 final int splitEndKey = actualEndKey - keysPerRegion; 3849 final String keyFormat = "%08x"; 3850 final Table table = createTable(tableName, cfBytes, 3851 maxVersions, 3852 Bytes.toBytes(String.format(keyFormat, splitStartKey)), 3853 Bytes.toBytes(String.format(keyFormat, splitEndKey)), 3854 numRegions); 3855 3856 if (hbaseCluster != null) { 3857 getMiniHBaseCluster().flushcache(TableName.META_TABLE_NAME); 3858 } 3859 3860 BufferedMutator mutator = getConnection().getBufferedMutator(tableName); 3861 3862 for (int iFlush = 0; iFlush < numFlushes; ++iFlush) { 3863 for (int iRow = 0; iRow < numRowsPerFlush; ++iRow) { 3864 final byte[] row = Bytes.toBytes(String.format(keyFormat, 3865 actualStartKey + rand.nextInt(actualEndKey - actualStartKey))); 3866 3867 Put put = new Put(row); 3868 Delete del = new Delete(row); 3869 for (int iCol = 0; iCol < numColsPerRow; ++iCol) { 3870 final byte[] cf = cfBytes[rand.nextInt(numCF)]; 3871 final long ts = rand.nextInt(); 3872 final byte[] qual = Bytes.toBytes("col" + iCol); 3873 if (rand.nextBoolean()) { 3874 final byte[] value = Bytes.toBytes("value_for_row_" + iRow + 3875 "_cf_" + Bytes.toStringBinary(cf) + "_col_" + iCol + "_ts_" + 3876 ts + "_random_" + rand.nextLong()); 3877 put.addColumn(cf, qual, ts, value); 3878 } else if (rand.nextDouble() < 0.8) { 3879 del.addColumn(cf, qual, ts); 3880 } else { 3881 del.addColumns(cf, qual, ts); 3882 } 3883 } 3884 3885 if (!put.isEmpty()) { 3886 mutator.mutate(put); 3887 } 3888 3889 if (!del.isEmpty()) { 3890 mutator.mutate(del); 3891 } 3892 } 3893 LOG.info("Initiating flush #" + iFlush + " for table " + tableName); 3894 mutator.flush(); 3895 if (hbaseCluster != null) { 3896 getMiniHBaseCluster().flushcache(table.getName()); 3897 } 3898 } 3899 mutator.close(); 3900 3901 return table; 3902 } 3903 3904 private static Random random = new Random(); 3905 3906 private static final PortAllocator portAllocator = new PortAllocator(random); 3907 3908 public static int randomFreePort() { 3909 return portAllocator.randomFreePort(); 3910 } 3911 3912 static class PortAllocator { 3913 private static final int MIN_RANDOM_PORT = 0xc000; 3914 private static final int MAX_RANDOM_PORT = 0xfffe; 3915 3916 /** A set of ports that have been claimed using {@link #randomFreePort()}. */ 3917 private final Set<Integer> takenRandomPorts = new HashSet<>(); 3918 3919 private final Random random; 3920 private final AvailablePortChecker portChecker; 3921 3922 public PortAllocator(Random random) { 3923 this.random = random; 3924 this.portChecker = new AvailablePortChecker() { 3925 @Override 3926 public boolean available(int port) { 3927 try { 3928 ServerSocket sock = new ServerSocket(port); 3929 sock.close(); 3930 return true; 3931 } catch (IOException ex) { 3932 return false; 3933 } 3934 } 3935 }; 3936 } 3937 3938 public PortAllocator(Random random, AvailablePortChecker portChecker) { 3939 this.random = random; 3940 this.portChecker = portChecker; 3941 } 3942 3943 /** 3944 * Returns a random free port and marks that port as taken. Not thread-safe. Expected to be 3945 * called from single-threaded test setup code/ 3946 */ 3947 public int randomFreePort() { 3948 int port = 0; 3949 do { 3950 port = randomPort(); 3951 if (takenRandomPorts.contains(port)) { 3952 port = 0; 3953 continue; 3954 } 3955 takenRandomPorts.add(port); 3956 3957 if (!portChecker.available(port)) { 3958 port = 0; 3959 } 3960 } while (port == 0); 3961 return port; 3962 } 3963 3964 /** 3965 * Returns a random port. These ports cannot be registered with IANA and are 3966 * intended for dynamic allocation (see http://bit.ly/dynports). 3967 */ 3968 private int randomPort() { 3969 return MIN_RANDOM_PORT 3970 + random.nextInt(MAX_RANDOM_PORT - MIN_RANDOM_PORT); 3971 } 3972 3973 interface AvailablePortChecker { 3974 boolean available(int port); 3975 } 3976 } 3977 3978 public static String randomMultiCastAddress() { 3979 return "226.1.1." + random.nextInt(254); 3980 } 3981 3982 public static void waitForHostPort(String host, int port) 3983 throws IOException { 3984 final int maxTimeMs = 10000; 3985 final int maxNumAttempts = maxTimeMs / HConstants.SOCKET_RETRY_WAIT_MS; 3986 IOException savedException = null; 3987 LOG.info("Waiting for server at " + host + ":" + port); 3988 for (int attempt = 0; attempt < maxNumAttempts; ++attempt) { 3989 try { 3990 Socket sock = new Socket(InetAddress.getByName(host), port); 3991 sock.close(); 3992 savedException = null; 3993 LOG.info("Server at " + host + ":" + port + " is available"); 3994 break; 3995 } catch (UnknownHostException e) { 3996 throw new IOException("Failed to look up " + host, e); 3997 } catch (IOException e) { 3998 savedException = e; 3999 } 4000 Threads.sleepWithoutInterrupt(HConstants.SOCKET_RETRY_WAIT_MS); 4001 } 4002 4003 if (savedException != null) { 4004 throw savedException; 4005 } 4006 } 4007 4008 /** 4009 * Creates a pre-split table for load testing. If the table already exists, 4010 * logs a warning and continues. 4011 * @return the number of regions the table was split into 4012 */ 4013 public static int createPreSplitLoadTestTable(Configuration conf, 4014 TableName tableName, byte[] columnFamily, Algorithm compression, 4015 DataBlockEncoding dataBlockEncoding) throws IOException { 4016 return createPreSplitLoadTestTable(conf, tableName, 4017 columnFamily, compression, dataBlockEncoding, DEFAULT_REGIONS_PER_SERVER, 1, 4018 Durability.USE_DEFAULT); 4019 } 4020 /** 4021 * Creates a pre-split table for load testing. If the table already exists, 4022 * logs a warning and continues. 4023 * @return the number of regions the table was split into 4024 */ 4025 public static int createPreSplitLoadTestTable(Configuration conf, 4026 TableName tableName, byte[] columnFamily, Algorithm compression, 4027 DataBlockEncoding dataBlockEncoding, int numRegionsPerServer, int regionReplication, 4028 Durability durability) 4029 throws IOException { 4030 HTableDescriptor desc = new HTableDescriptor(tableName); 4031 desc.setDurability(durability); 4032 desc.setRegionReplication(regionReplication); 4033 HColumnDescriptor hcd = new HColumnDescriptor(columnFamily); 4034 hcd.setDataBlockEncoding(dataBlockEncoding); 4035 hcd.setCompressionType(compression); 4036 return createPreSplitLoadTestTable(conf, desc, hcd, numRegionsPerServer); 4037 } 4038 4039 /** 4040 * Creates a pre-split table for load testing. If the table already exists, 4041 * logs a warning and continues. 4042 * @return the number of regions the table was split into 4043 */ 4044 public static int createPreSplitLoadTestTable(Configuration conf, 4045 TableName tableName, byte[][] columnFamilies, Algorithm compression, 4046 DataBlockEncoding dataBlockEncoding, int numRegionsPerServer, int regionReplication, 4047 Durability durability) 4048 throws IOException { 4049 HTableDescriptor desc = new HTableDescriptor(tableName); 4050 desc.setDurability(durability); 4051 desc.setRegionReplication(regionReplication); 4052 HColumnDescriptor[] hcds = new HColumnDescriptor[columnFamilies.length]; 4053 for (int i = 0; i < columnFamilies.length; i++) { 4054 HColumnDescriptor hcd = new HColumnDescriptor(columnFamilies[i]); 4055 hcd.setDataBlockEncoding(dataBlockEncoding); 4056 hcd.setCompressionType(compression); 4057 hcds[i] = hcd; 4058 } 4059 return createPreSplitLoadTestTable(conf, desc, hcds, numRegionsPerServer); 4060 } 4061 4062 /** 4063 * Creates a pre-split table for load testing. If the table already exists, 4064 * logs a warning and continues. 4065 * @return the number of regions the table was split into 4066 */ 4067 public static int createPreSplitLoadTestTable(Configuration conf, 4068 TableDescriptor desc, ColumnFamilyDescriptor hcd) throws IOException { 4069 return createPreSplitLoadTestTable(conf, desc, hcd, DEFAULT_REGIONS_PER_SERVER); 4070 } 4071 4072 /** 4073 * Creates a pre-split table for load testing. If the table already exists, 4074 * logs a warning and continues. 4075 * @return the number of regions the table was split into 4076 */ 4077 public static int createPreSplitLoadTestTable(Configuration conf, 4078 TableDescriptor desc, ColumnFamilyDescriptor hcd, int numRegionsPerServer) throws IOException { 4079 return createPreSplitLoadTestTable(conf, desc, new ColumnFamilyDescriptor[] {hcd}, 4080 numRegionsPerServer); 4081 } 4082 4083 /** 4084 * Creates a pre-split table for load testing. If the table already exists, 4085 * logs a warning and continues. 4086 * @return the number of regions the table was split into 4087 */ 4088 public static int createPreSplitLoadTestTable(Configuration conf, 4089 TableDescriptor desc, ColumnFamilyDescriptor[] hcds, 4090 int numRegionsPerServer) throws IOException { 4091 return createPreSplitLoadTestTable(conf, desc, hcds, 4092 new RegionSplitter.HexStringSplit(), numRegionsPerServer); 4093 } 4094 4095 /** 4096 * Creates a pre-split table for load testing. If the table already exists, 4097 * logs a warning and continues. 4098 * @return the number of regions the table was split into 4099 */ 4100 public static int createPreSplitLoadTestTable(Configuration conf, 4101 TableDescriptor td, ColumnFamilyDescriptor[] cds, 4102 SplitAlgorithm splitter, int numRegionsPerServer) throws IOException { 4103 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(td); 4104 for (ColumnFamilyDescriptor cd : cds) { 4105 if (!td.hasColumnFamily(cd.getName())) { 4106 builder.setColumnFamily(cd); 4107 } 4108 } 4109 td = builder.build(); 4110 int totalNumberOfRegions = 0; 4111 Connection unmanagedConnection = ConnectionFactory.createConnection(conf); 4112 Admin admin = unmanagedConnection.getAdmin(); 4113 4114 try { 4115 // create a table a pre-splits regions. 4116 // The number of splits is set as: 4117 // region servers * regions per region server). 4118 int numberOfServers = admin.getRegionServers().size(); 4119 if (numberOfServers == 0) { 4120 throw new IllegalStateException("No live regionservers"); 4121 } 4122 4123 totalNumberOfRegions = numberOfServers * numRegionsPerServer; 4124 LOG.info("Number of live regionservers: " + numberOfServers + ", " + 4125 "pre-splitting table into " + totalNumberOfRegions + " regions " + 4126 "(regions per server: " + numRegionsPerServer + ")"); 4127 4128 byte[][] splits = splitter.split( 4129 totalNumberOfRegions); 4130 4131 admin.createTable(td, splits); 4132 } catch (MasterNotRunningException e) { 4133 LOG.error("Master not running", e); 4134 throw new IOException(e); 4135 } catch (TableExistsException e) { 4136 LOG.warn("Table " + td.getTableName() + 4137 " already exists, continuing"); 4138 } finally { 4139 admin.close(); 4140 unmanagedConnection.close(); 4141 } 4142 return totalNumberOfRegions; 4143 } 4144 4145 public static int getMetaRSPort(Connection connection) throws IOException { 4146 try (RegionLocator locator = connection.getRegionLocator(TableName.META_TABLE_NAME)) { 4147 return locator.getRegionLocation(Bytes.toBytes("")).getPort(); 4148 } 4149 } 4150 4151 /** 4152 * Due to async racing issue, a region may not be in 4153 * the online region list of a region server yet, after 4154 * the assignment znode is deleted and the new assignment 4155 * is recorded in master. 4156 */ 4157 public void assertRegionOnServer( 4158 final RegionInfo hri, final ServerName server, 4159 final long timeout) throws IOException, InterruptedException { 4160 long timeoutTime = System.currentTimeMillis() + timeout; 4161 while (true) { 4162 List<RegionInfo> regions = getAdmin().getRegions(server); 4163 if (regions.stream().anyMatch(r -> RegionInfo.COMPARATOR.compare(r, hri) == 0)) return; 4164 long now = System.currentTimeMillis(); 4165 if (now > timeoutTime) break; 4166 Thread.sleep(10); 4167 } 4168 fail("Could not find region " + hri.getRegionNameAsString() 4169 + " on server " + server); 4170 } 4171 4172 /** 4173 * Check to make sure the region is open on the specified 4174 * region server, but not on any other one. 4175 */ 4176 public void assertRegionOnlyOnServer( 4177 final RegionInfo hri, final ServerName server, 4178 final long timeout) throws IOException, InterruptedException { 4179 long timeoutTime = System.currentTimeMillis() + timeout; 4180 while (true) { 4181 List<RegionInfo> regions = getAdmin().getRegions(server); 4182 if (regions.stream().anyMatch(r -> RegionInfo.COMPARATOR.compare(r, hri) == 0)) { 4183 List<JVMClusterUtil.RegionServerThread> rsThreads = 4184 getHBaseCluster().getLiveRegionServerThreads(); 4185 for (JVMClusterUtil.RegionServerThread rsThread: rsThreads) { 4186 HRegionServer rs = rsThread.getRegionServer(); 4187 if (server.equals(rs.getServerName())) { 4188 continue; 4189 } 4190 Collection<HRegion> hrs = rs.getOnlineRegionsLocalContext(); 4191 for (HRegion r: hrs) { 4192 assertTrue("Region should not be double assigned", 4193 r.getRegionInfo().getRegionId() != hri.getRegionId()); 4194 } 4195 } 4196 return; // good, we are happy 4197 } 4198 long now = System.currentTimeMillis(); 4199 if (now > timeoutTime) break; 4200 Thread.sleep(10); 4201 } 4202 fail("Could not find region " + hri.getRegionNameAsString() 4203 + " on server " + server); 4204 } 4205 4206 public HRegion createTestRegion(String tableName, ColumnFamilyDescriptor cd) throws IOException { 4207 TableDescriptor td = 4208 TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName)).setColumnFamily(cd).build(); 4209 RegionInfo info = RegionInfoBuilder.newBuilder(TableName.valueOf(tableName)).build(); 4210 return createRegionAndWAL(info, getDataTestDir(), getConfiguration(), td); 4211 } 4212 4213 public HRegion createTestRegion(String tableName, ColumnFamilyDescriptor cd, 4214 BlockCache blockCache) throws IOException { 4215 TableDescriptor td = 4216 TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName)).setColumnFamily(cd).build(); 4217 RegionInfo info = RegionInfoBuilder.newBuilder(TableName.valueOf(tableName)).build(); 4218 return createRegionAndWAL(info, getDataTestDir(), getConfiguration(), td, blockCache); 4219 } 4220 4221 public void setFileSystemURI(String fsURI) { 4222 FS_URI = fsURI; 4223 } 4224 4225 /** 4226 * Returns a {@link Predicate} for checking that there are no regions in transition in master 4227 */ 4228 public ExplainingPredicate<IOException> predicateNoRegionsInTransition() { 4229 return new ExplainingPredicate<IOException>() { 4230 @Override 4231 public String explainFailure() throws IOException { 4232 final RegionStates regionStates = getMiniHBaseCluster().getMaster() 4233 .getAssignmentManager().getRegionStates(); 4234 return "found in transition: " + regionStates.getRegionsInTransition().toString(); 4235 } 4236 4237 @Override 4238 public boolean evaluate() throws IOException { 4239 HMaster master = getMiniHBaseCluster().getMaster(); 4240 if (master == null) return false; 4241 AssignmentManager am = master.getAssignmentManager(); 4242 if (am == null) return false; 4243 return !am.hasRegionsInTransition(); 4244 } 4245 }; 4246 } 4247 4248 /** 4249 * Returns a {@link Predicate} for checking that table is enabled 4250 */ 4251 public Waiter.Predicate<IOException> predicateTableEnabled(final TableName tableName) { 4252 return new ExplainingPredicate<IOException>() { 4253 @Override 4254 public String explainFailure() throws IOException { 4255 return explainTableState(tableName, TableState.State.ENABLED); 4256 } 4257 4258 @Override 4259 public boolean evaluate() throws IOException { 4260 return getAdmin().tableExists(tableName) && getAdmin().isTableEnabled(tableName); 4261 } 4262 }; 4263 } 4264 4265 /** 4266 * Returns a {@link Predicate} for checking that table is enabled 4267 */ 4268 public Waiter.Predicate<IOException> predicateTableDisabled(final TableName tableName) { 4269 return new ExplainingPredicate<IOException>() { 4270 @Override 4271 public String explainFailure() throws IOException { 4272 return explainTableState(tableName, TableState.State.DISABLED); 4273 } 4274 4275 @Override 4276 public boolean evaluate() throws IOException { 4277 return getAdmin().isTableDisabled(tableName); 4278 } 4279 }; 4280 } 4281 4282 /** 4283 * Returns a {@link Predicate} for checking that table is enabled 4284 */ 4285 public Waiter.Predicate<IOException> predicateTableAvailable(final TableName tableName) { 4286 return new ExplainingPredicate<IOException>() { 4287 @Override 4288 public String explainFailure() throws IOException { 4289 return explainTableAvailability(tableName); 4290 } 4291 4292 @Override 4293 public boolean evaluate() throws IOException { 4294 boolean tableAvailable = getAdmin().isTableAvailable(tableName); 4295 if (tableAvailable) { 4296 try (Table table = getConnection().getTable(tableName)) { 4297 TableDescriptor htd = table.getDescriptor(); 4298 for (HRegionLocation loc : getConnection().getRegionLocator(tableName) 4299 .getAllRegionLocations()) { 4300 Scan scan = new Scan().withStartRow(loc.getRegionInfo().getStartKey()) 4301 .withStopRow(loc.getRegionInfo().getEndKey()).setOneRowLimit() 4302 .setMaxResultsPerColumnFamily(1).setCacheBlocks(false); 4303 for (byte[] family : htd.getColumnFamilyNames()) { 4304 scan.addFamily(family); 4305 } 4306 try (ResultScanner scanner = table.getScanner(scan)) { 4307 scanner.next(); 4308 } 4309 } 4310 } 4311 } 4312 return tableAvailable; 4313 } 4314 }; 4315 } 4316 4317 /** 4318 * Wait until no regions in transition. 4319 * @param timeout How long to wait. 4320 * @throws IOException 4321 */ 4322 public void waitUntilNoRegionsInTransition(final long timeout) throws IOException { 4323 waitFor(timeout, predicateNoRegionsInTransition()); 4324 } 4325 4326 /** 4327 * Wait until no regions in transition. (time limit 15min) 4328 * @throws IOException 4329 */ 4330 public void waitUntilNoRegionsInTransition() throws IOException { 4331 waitUntilNoRegionsInTransition(15 * 60000); 4332 } 4333 4334 /** 4335 * Wait until labels is ready in VisibilityLabelsCache. 4336 * @param timeoutMillis 4337 * @param labels 4338 */ 4339 public void waitLabelAvailable(long timeoutMillis, final String... labels) { 4340 final VisibilityLabelsCache labelsCache = VisibilityLabelsCache.get(); 4341 waitFor(timeoutMillis, new Waiter.ExplainingPredicate<RuntimeException>() { 4342 4343 @Override 4344 public boolean evaluate() { 4345 for (String label : labels) { 4346 if (labelsCache.getLabelOrdinal(label) == 0) { 4347 return false; 4348 } 4349 } 4350 return true; 4351 } 4352 4353 @Override 4354 public String explainFailure() { 4355 for (String label : labels) { 4356 if (labelsCache.getLabelOrdinal(label) == 0) { 4357 return label + " is not available yet"; 4358 } 4359 } 4360 return ""; 4361 } 4362 }); 4363 } 4364 4365 /** 4366 * Create a set of column descriptors with the combination of compression, 4367 * encoding, bloom codecs available. 4368 * @return the list of column descriptors 4369 */ 4370 public static List<HColumnDescriptor> generateColumnDescriptors() { 4371 return generateColumnDescriptors(""); 4372 } 4373 4374 /** 4375 * Create a set of column descriptors with the combination of compression, 4376 * encoding, bloom codecs available. 4377 * @param prefix family names prefix 4378 * @return the list of column descriptors 4379 */ 4380 public static List<HColumnDescriptor> generateColumnDescriptors(final String prefix) { 4381 List<HColumnDescriptor> htds = new ArrayList<>(); 4382 long familyId = 0; 4383 for (Compression.Algorithm compressionType: getSupportedCompressionAlgorithms()) { 4384 for (DataBlockEncoding encodingType: DataBlockEncoding.values()) { 4385 for (BloomType bloomType: BloomType.values()) { 4386 String name = String.format("%s-cf-!@#&-%d!@#", prefix, familyId); 4387 HColumnDescriptor htd = new HColumnDescriptor(name); 4388 htd.setCompressionType(compressionType); 4389 htd.setDataBlockEncoding(encodingType); 4390 htd.setBloomFilterType(bloomType); 4391 htds.add(htd); 4392 familyId++; 4393 } 4394 } 4395 } 4396 return htds; 4397 } 4398 4399 /** 4400 * Get supported compression algorithms. 4401 * @return supported compression algorithms. 4402 */ 4403 public static Compression.Algorithm[] getSupportedCompressionAlgorithms() { 4404 String[] allAlgos = HFile.getSupportedCompressionAlgorithms(); 4405 List<Compression.Algorithm> supportedAlgos = new ArrayList<>(); 4406 for (String algoName : allAlgos) { 4407 try { 4408 Compression.Algorithm algo = Compression.getCompressionAlgorithmByName(algoName); 4409 algo.getCompressor(); 4410 supportedAlgos.add(algo); 4411 } catch (Throwable t) { 4412 // this algo is not available 4413 } 4414 } 4415 return supportedAlgos.toArray(new Algorithm[supportedAlgos.size()]); 4416 } 4417 4418 public Result getClosestRowBefore(Region r, byte[] row, byte[] family) throws IOException { 4419 Scan scan = new Scan(row); 4420 scan.setSmall(true); 4421 scan.setCaching(1); 4422 scan.setReversed(true); 4423 scan.addFamily(family); 4424 try (RegionScanner scanner = r.getScanner(scan)) { 4425 List<Cell> cells = new ArrayList<>(1); 4426 scanner.next(cells); 4427 if (r.getRegionInfo().isMetaRegion() && !isTargetTable(row, cells.get(0))) { 4428 return null; 4429 } 4430 return Result.create(cells); 4431 } 4432 } 4433 4434 private boolean isTargetTable(final byte[] inRow, Cell c) { 4435 String inputRowString = Bytes.toString(inRow); 4436 int i = inputRowString.indexOf(HConstants.DELIMITER); 4437 String outputRowString = Bytes.toString(c.getRowArray(), c.getRowOffset(), c.getRowLength()); 4438 int o = outputRowString.indexOf(HConstants.DELIMITER); 4439 return inputRowString.substring(0, i).equals(outputRowString.substring(0, o)); 4440 } 4441 4442 /** 4443 * Sets up {@link MiniKdc} for testing security. 4444 * Uses {@link HBaseKerberosUtils} to set the given keytab file as 4445 * {@link HBaseKerberosUtils#KRB_KEYTAB_FILE}. 4446 */ 4447 public MiniKdc setupMiniKdc(File keytabFile) throws Exception { 4448 Properties conf = MiniKdc.createConf(); 4449 conf.put(MiniKdc.DEBUG, true); 4450 MiniKdc kdc = null; 4451 File dir = null; 4452 // There is time lag between selecting a port and trying to bind with it. It's possible that 4453 // another service captures the port in between which'll result in BindException. 4454 boolean bindException; 4455 int numTries = 0; 4456 do { 4457 try { 4458 bindException = false; 4459 dir = new File(getDataTestDir("kdc").toUri().getPath()); 4460 kdc = new MiniKdc(conf, dir); 4461 kdc.start(); 4462 } catch (BindException e) { 4463 FileUtils.deleteDirectory(dir); // clean directory 4464 numTries++; 4465 if (numTries == 3) { 4466 LOG.error("Failed setting up MiniKDC. Tried " + numTries + " times."); 4467 throw e; 4468 } 4469 LOG.error("BindException encountered when setting up MiniKdc. Trying again."); 4470 bindException = true; 4471 } 4472 } while (bindException); 4473 HBaseKerberosUtils.setKeytabFileForTesting(keytabFile.getAbsolutePath()); 4474 return kdc; 4475 } 4476 4477 public int getNumHFiles(final TableName tableName, final byte[] family) { 4478 int numHFiles = 0; 4479 for (RegionServerThread regionServerThread : getMiniHBaseCluster().getRegionServerThreads()) { 4480 numHFiles+= getNumHFilesForRS(regionServerThread.getRegionServer(), tableName, 4481 family); 4482 } 4483 return numHFiles; 4484 } 4485 4486 public int getNumHFilesForRS(final HRegionServer rs, final TableName tableName, 4487 final byte[] family) { 4488 int numHFiles = 0; 4489 for (Region region : rs.getRegions(tableName)) { 4490 numHFiles += region.getStore(family).getStorefilesCount(); 4491 } 4492 return numHFiles; 4493 } 4494 4495 public void verifyTableDescriptorIgnoreTableName(TableDescriptor ltd, TableDescriptor rtd) { 4496 assertEquals(ltd.getValues().hashCode(), rtd.getValues().hashCode()); 4497 Collection<ColumnFamilyDescriptor> ltdFamilies = Arrays.asList(ltd.getColumnFamilies()); 4498 Collection<ColumnFamilyDescriptor> rtdFamilies = Arrays.asList(rtd.getColumnFamilies()); 4499 assertEquals(ltdFamilies.size(), rtdFamilies.size()); 4500 for (Iterator<ColumnFamilyDescriptor> it = ltdFamilies.iterator(), it2 = 4501 rtdFamilies.iterator(); it.hasNext();) { 4502 assertEquals(0, 4503 ColumnFamilyDescriptor.COMPARATOR.compare(it.next(), it2.next())); 4504 } 4505 } 4506}