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