/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.MiniHBaseCluster;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.Region;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.JVMClusterUtil;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;
import java.io.IOException;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@Category({MediumTests.class, ClientTests.class})
public class TestSplitOrMergeStatus {
private static final Log LOG = LogFactory.getLog(TestSplitOrMergeStatus.class);
private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
private static byte [] FAMILY = Bytes.toBytes("testFamily");
@Rule
public TestName name = new TestName();
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
TEST_UTIL.startMiniCluster(2);
}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
TEST_UTIL.shutdownMiniCluster();
}
@Test
public void testSplitSwitch() throws Exception {
final TableName tableName = TableName.valueOf(name.getMethodName());
Table t = TEST_UTIL.createTable(tableName, FAMILY);
TEST_UTIL.loadTable(t, FAMILY, false);
RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(t.getName());
int orignalCount = locator.getAllRegionLocations().size();
Admin admin = TEST_UTIL.getAdmin();
initSwitchStatus(admin);
boolean[] results = admin.setSplitOrMergeEnabled(false, false, MasterSwitchType.SPLIT);
assertEquals(results.length, 1);
assertTrue(results[0]);
admin.split(t.getName());
int count = waitOnSplitOrMerge(t).size();
assertTrue(orignalCount == count);
results = admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.SPLIT);
assertEquals(results.length, 1);
assertFalse(results[0]);
admin.split(t.getName());
count = waitOnSplitOrMerge(t).size();
assertTrue(orignalCount<count);
admin.close();
}
@Test
public void testMergeSwitch() throws Exception {
final TableName tableName = TableName.valueOf(name.getMethodName());
Table t = TEST_UTIL.createTable(tableName, FAMILY);
TEST_UTIL.loadTable(t, FAMILY, false);
RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(t.getName());
Admin admin = TEST_UTIL.getAdmin();
initSwitchStatus(admin);
admin.split(t.getName());
waitOnSplitOrMerge(t); //Split the table to ensure we have two regions at least.
waitForMergable(admin, tableName);
int orignalCount = locator.getAllRegionLocations().size();
boolean[] results = admin.setSplitOrMergeEnabled(false, false, MasterSwitchType.MERGE);
assertEquals(results.length, 1);
assertTrue(results[0]);
List<HRegionInfo> regions = admin.getTableRegions(t.getName());
assertTrue(regions.size() > 1);
admin.mergeRegionsAsync(regions.get(0).getEncodedNameAsBytes(),
regions.get(1).getEncodedNameAsBytes(), true);
int count = waitOnSplitOrMerge(t).size();
assertTrue(orignalCount == count);
waitForMergable(admin, tableName);
results = admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.MERGE);
assertEquals(results.length, 1);
assertFalse(results[0]);
admin.mergeRegionsAsync(regions.get(0).getEncodedNameAsBytes(),
regions.get(1).getEncodedNameAsBytes(), true);
count = waitOnSplitOrMerge(t).size();
assertTrue(orignalCount>count);
admin.close();
}
@Test
public void testMultiSwitches() throws IOException {
Admin admin = TEST_UTIL.getAdmin();
boolean[] switches = admin.setSplitOrMergeEnabled(false, false,
MasterSwitchType.SPLIT, MasterSwitchType.MERGE);
for (boolean s : switches){
assertTrue(s);
}
assertFalse(admin.isSplitOrMergeEnabled(MasterSwitchType.SPLIT));
assertFalse(admin.isSplitOrMergeEnabled(MasterSwitchType.MERGE));
admin.close();
}
private void initSwitchStatus(Admin admin) throws IOException {
if (!admin.isSplitOrMergeEnabled(MasterSwitchType.SPLIT)) {
admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.SPLIT);
}
if (!admin.isSplitOrMergeEnabled(MasterSwitchType.MERGE)) {
admin.setSplitOrMergeEnabled(true, false, MasterSwitchType.MERGE);
}
assertTrue(admin.isSplitOrMergeEnabled(MasterSwitchType.SPLIT));
assertTrue(admin.isSplitOrMergeEnabled(MasterSwitchType.MERGE));
}
private void waitForMergable(Admin admin, TableName t) throws InterruptedException, IOException {
// Wait for the Regions to be mergeable
MiniHBaseCluster miniCluster = TEST_UTIL.getMiniHBaseCluster();
int mergeable = 0;
while (mergeable < 2) {
Thread.sleep(100);
admin.majorCompact(t);
mergeable = 0;
for (JVMClusterUtil.RegionServerThread regionThread: miniCluster.getRegionServerThreads()) {
for (Region region: regionThread.getRegionServer().getOnlineRegions(t)) {
mergeable += ((HRegion)region).isMergeable() ? 1 : 0;
}
}
}
}
/*
* Wait on table split. May return because we waited long enough on the split
* and it didn't happen. Caller should check.
* @param t
* @return Map of table regions; caller needs to check table actually split.
*/
private List<HRegionLocation> waitOnSplitOrMerge(final Table t)
throws IOException {
try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(t.getName())) {
List<HRegionLocation> regions = locator.getAllRegionLocations();
int originalCount = regions.size();
for (int i = 0; i < TEST_UTIL.getConfiguration().getInt("hbase.test.retries", 10); i++) {
Thread.currentThread();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
regions = locator.getAllRegionLocations();
if (regions.size() != originalCount)
break;
}
return regions;
}
}
}