View Javadoc

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