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 19 package org.apache.hadoop.hbase; 20 21 import java.io.IOException; 22 import java.util.concurrent.CountDownLatch; 23 import java.util.concurrent.TimeUnit; 24 25 import org.apache.commons.logging.Log; 26 import org.apache.commons.logging.LogFactory; 27 import org.apache.hadoop.hbase.client.Admin; 28 import org.apache.hadoop.hbase.testclassification.IntegrationTests; 29 import org.apache.hadoop.hbase.util.RegionSplitter; 30 import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm; 31 import org.junit.After; 32 import org.junit.Before; 33 import org.junit.Test; 34 import org.junit.experimental.categories.Category; 35 36 import static org.junit.Assert.assertTrue; 37 import static org.junit.Assert.fail; 38 39 /** 40 * An integration test to detect regressions in HBASE-7220. Create 41 * a table with many regions and verify it completes within a 42 * reasonable amount of time. 43 * @see <a href="https://issues.apache.org/jira/browse/HBASE-7220">HBASE-7220</a> 44 */ 45 @Category(IntegrationTests.class) 46 public class IntegrationTestManyRegions { 47 48 private static final String CLASS_NAME 49 = IntegrationTestManyRegions.class.getSimpleName(); 50 51 protected static final Log LOG 52 = LogFactory.getLog(IntegrationTestManyRegions.class); 53 protected static final TableName TABLE_NAME = TableName.valueOf(CLASS_NAME); 54 protected static final String COLUMN_NAME = "f"; 55 protected static final String REGION_COUNT_KEY 56 = String.format("hbase.%s.regions", CLASS_NAME); 57 protected static final String REGIONSERVER_COUNT_KEY 58 = String.format("hbase.%s.regionServers", CLASS_NAME); 59 protected static final String TIMEOUT_MINUTES_KEY 60 = String.format("hbase.%s.timeoutMinutes", CLASS_NAME); 61 62 protected static final int DEFAULT_REGION_COUNT = 1000; 63 protected static final int DEFAULT_REGIONSERVER_COUNT = 1; 64 // running this test on my laptop consistently takes about 2.5 65 // minutes. A timeout of 4 minutes should be reasonably safe. 66 protected static final int DEFAULT_TIMEOUT_MINUTES = 4; 67 protected static final IntegrationTestingUtility util 68 = new IntegrationTestingUtility(); 69 70 protected static final int REGION_COUNT = util.getConfiguration() 71 .getInt(REGION_COUNT_KEY, DEFAULT_REGION_COUNT); 72 protected static final int REGION_SERVER_COUNT = util.getConfiguration() 73 .getInt(REGIONSERVER_COUNT_KEY, DEFAULT_REGIONSERVER_COUNT); 74 protected static final int TIMEOUT_MINUTES = util.getConfiguration() 75 .getInt(TIMEOUT_MINUTES_KEY, DEFAULT_TIMEOUT_MINUTES); 76 77 @Before setUp()78 public void setUp() throws Exception { 79 LOG.info(String.format("Initializing cluster with %d region servers.", 80 REGION_SERVER_COUNT)); 81 util.initializeCluster(REGION_SERVER_COUNT); 82 LOG.info("Cluster initialized"); 83 84 Admin admin = util.getHBaseAdmin(); 85 if (admin.tableExists(TABLE_NAME)) { 86 LOG.info(String.format("Deleting existing table %s.", TABLE_NAME)); 87 if (admin.isTableEnabled(TABLE_NAME)) admin.disableTable(TABLE_NAME); 88 admin.deleteTable(TABLE_NAME); 89 LOG.info(String.format("Existing table %s deleted.", TABLE_NAME)); 90 } 91 LOG.info("Cluster ready"); 92 } 93 94 @After tearDown()95 public void tearDown() throws IOException { 96 LOG.info("Cleaning up after test."); 97 Admin admin = util.getHBaseAdmin(); 98 if (admin.tableExists(TABLE_NAME)) { 99 if (admin.isTableEnabled(TABLE_NAME)) admin.disableTable(TABLE_NAME); 100 admin.deleteTable(TABLE_NAME); 101 } 102 LOG.info("Restoring cluster."); 103 util.restoreCluster(); 104 LOG.info("Cluster restored."); 105 } 106 107 @Test testCreateTableWithRegions()108 public void testCreateTableWithRegions() throws Exception { 109 CountDownLatch doneSignal = new CountDownLatch(1); 110 Worker worker = new Worker(doneSignal, util.getHBaseAdmin()); 111 Thread t = new Thread(worker); 112 113 LOG.info("Launching worker thread to create the table."); 114 t.start(); 115 boolean workerComplete = false; 116 workerComplete = doneSignal.await(TIMEOUT_MINUTES, TimeUnit.MINUTES); 117 if (!workerComplete) { 118 t.interrupt(); 119 fail("Timeout limit expired."); 120 } 121 assertTrue("Table creation failed.", worker.isSuccess()); 122 } 123 124 private static class Worker implements Runnable { 125 private final CountDownLatch doneSignal; 126 private final Admin admin; 127 private boolean success = false; 128 Worker(final CountDownLatch doneSignal, final Admin admin)129 public Worker(final CountDownLatch doneSignal, final Admin admin) { 130 this.doneSignal = doneSignal; 131 this.admin = admin; 132 } 133 isSuccess()134 public boolean isSuccess() { 135 return this.success; 136 } 137 138 @Override run()139 public void run() { 140 long startTime, endTime; 141 HTableDescriptor desc = new HTableDescriptor(TABLE_NAME); 142 desc.addFamily(new HColumnDescriptor(COLUMN_NAME)); 143 SplitAlgorithm algo = new RegionSplitter.HexStringSplit(); 144 byte[][] splits = algo.split(REGION_COUNT); 145 146 LOG.info(String.format("Creating table %s with %d splits.", 147 TABLE_NAME, REGION_COUNT)); 148 startTime = System.currentTimeMillis(); 149 try { 150 admin.createTable(desc, splits); 151 endTime = System.currentTimeMillis(); 152 success = true; 153 LOG.info(String.format("Pre-split table created successfully in %dms.", 154 (endTime - startTime))); 155 } catch (IOException e) { 156 LOG.error("Failed to create table", e); 157 } finally { 158 doneSignal.countDown(); 159 } 160 } 161 } 162 } 163