HBASE-21265 Split up TestRSGroups

Signed-off-by: Ted Yu <tyu@apache.org>

Conflicts:
	hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroups.java
        hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsAdmin1.java
	hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
This commit is contained in:
Andrew Purtell 2018-10-03 16:13:09 -07:00
parent 9e3f3fdc1f
commit 24d19e87e0
No known key found for this signature in database
GPG Key ID: 8597754DD5365CCD
10 changed files with 1832 additions and 1488 deletions

View File

@ -40,13 +40,13 @@ import org.slf4j.LoggerFactory;
* Test enable RSGroup
*/
@Category({ MediumTests.class })
public class TestEnableRSGroup {
public class TestEnableRSGroups {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestEnableRSGroup.class);
HBaseClassTestRule.forClass(TestEnableRSGroups.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestEnableRSGroup.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestEnableRSGroups.class);
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
@ -71,7 +71,8 @@ public class TestEnableRSGroup {
LOG.info("stopped master...");
final Configuration conf = TEST_UTIL.getMiniHBaseCluster().getConfiguration();
conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, RSGroupAdminEndpoint.class.getName());
conf.set(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, RSGroupBasedLoadBalancer.class.getName());
conf.set(HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
RSGroupBasedLoadBalancer.class.getName());
TEST_UTIL.getMiniHBaseCluster().startMaster();
TEST_UTIL.getMiniHBaseCluster().waitForActiveAndReadyMaster(60000);

View File

@ -1,547 +0,0 @@
/**
* 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.rsgroup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MiniHBaseCluster;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.Waiter.Predicate;
import org.apache.hadoop.hbase.client.ClusterConnection;
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor;
import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.MasterObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.master.TableNamespaceManager;
import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
import org.apache.hadoop.hbase.quotas.QuotaUtil;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
@Category({MediumTests.class})
public class TestRSGroups extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRSGroups.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroups.class);
private static boolean INIT = false;
private static RSGroupAdminEndpoint rsGroupAdminEndpoint;
private static CPMasterObserver observer;
@BeforeClass
public static void setUp() throws Exception {
TEST_UTIL = new HBaseTestingUtility();
TEST_UTIL.getConfiguration().setFloat(
"hbase.master.balancer.stochastic.tableSkewCost", 6000);
TEST_UTIL.getConfiguration().set(
HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
RSGroupBasedLoadBalancer.class.getName());
TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
RSGroupAdminEndpoint.class.getName() + "," + CPMasterObserver.class.getName());
TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setInt(
ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
initialize();
}
private static void initialize() throws Exception {
admin = TEST_UTIL.getAdmin();
cluster = TEST_UTIL.getHBaseCluster();
master = ((MiniHBaseCluster)cluster).getMaster();
//wait for balancer to come online
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return master.isInitialized() &&
((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline();
}
});
admin.setBalancerRunning(false,true);
rsGroupAdmin = new VerifyingRSGroupAdminClient(
new RSGroupAdminClient(TEST_UTIL.getConnection()), TEST_UTIL.getConfiguration());
MasterCoprocessorHost host = master.getMasterCoprocessorHost();
observer = (CPMasterObserver) host.findCoprocessor(CPMasterObserver.class.getName());
rsGroupAdminEndpoint = (RSGroupAdminEndpoint)
host.findCoprocessor(RSGroupAdminEndpoint.class.getName());
}
@AfterClass
public static void tearDown() throws Exception {
TEST_UTIL.shutdownMiniCluster();
}
@Before
public void beforeMethod() throws Exception {
if (!INIT) {
INIT = true;
afterMethod();
}
observer.resetFlags();
}
@After
public void afterMethod() throws Exception {
deleteTableIfNecessary();
deleteNamespaceIfNecessary();
deleteGroups();
for(ServerName sn : admin.listDecommissionedRegionServers()){
admin.recommissionRegionServer(sn, null);
}
assertTrue(admin.listDecommissionedRegionServers().isEmpty());
int missing = NUM_SLAVES_BASE - getNumServers();
LOG.info("Restoring servers: "+missing);
for(int i=0; i<missing; i++) {
((MiniHBaseCluster)cluster).startRegionServer();
}
rsGroupAdmin.addRSGroup("master");
ServerName masterServerName =
((MiniHBaseCluster)cluster).getMaster().getServerName();
try {
rsGroupAdmin.moveServers(Sets.newHashSet(masterServerName.getAddress()), "master");
} catch (Exception ex) {
LOG.warn("Got this on setup, FYI", ex);
}
assertTrue(observer.preMoveServersCalled);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
LOG.info("Waiting for cleanup to finish " + rsGroupAdmin.listRSGroups());
//Might be greater since moving servers back to default
//is after starting a server
return rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size()
== NUM_SLAVES_BASE;
}
});
}
@Test
public void testBasicStartUp() throws IOException {
RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
assertEquals(4, defaultInfo.getServers().size());
// Assignment of root and meta regions.
int count = master.getAssignmentManager().getRegionStates().getRegionAssignments().size();
//3 meta,namespace, group
assertEquals(3, count);
}
@Test
public void testNamespaceCreateAndAssign() throws Exception {
LOG.info("testNamespaceCreateAndAssign");
String nsName = tablePrefix+"_foo";
final TableName tableName = TableName.valueOf(nsName, tablePrefix + "_testCreateAndAssign");
RSGroupInfo appInfo = addGroup("appInfo", 1);
admin.createNamespace(NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "appInfo").build());
final HTableDescriptor desc = new HTableDescriptor(tableName);
desc.addFamily(new HColumnDescriptor("f"));
admin.createTable(desc);
//wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getTableRegionMap().get(desc.getTableName()) != null;
}
});
ServerName targetServer =
ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
AdminProtos.AdminService.BlockingInterface rs =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
//verify it was assigned to the right group
Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(rs).size());
}
@Test
public void testDefaultNamespaceCreateAndAssign() throws Exception {
LOG.info("testDefaultNamespaceCreateAndAssign");
String tableName = tablePrefix + "_testCreateAndAssign";
admin.modifyNamespace(NamespaceDescriptor.create("default")
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "default").build());
final HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
desc.addFamily(new HColumnDescriptor("f"));
admin.createTable(desc);
//wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getTableRegionMap().get(desc.getTableName()) != null;
}
});
}
@Test
public void testNamespaceConstraint() throws Exception {
String nsName = tablePrefix+"_foo";
String groupName = tablePrefix+"_foo";
LOG.info("testNamespaceConstraint");
rsGroupAdmin.addRSGroup(groupName);
assertTrue(observer.preAddRSGroupCalled);
assertTrue(observer.postAddRSGroupCalled);
admin.createNamespace(NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
.build());
//test removing a referenced group
try {
rsGroupAdmin.removeRSGroup(groupName);
fail("Expected a constraint exception");
} catch (IOException ex) {
}
//test modify group
//changing with the same name is fine
admin.modifyNamespace(
NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
.build());
String anotherGroup = tablePrefix+"_anotherGroup";
rsGroupAdmin.addRSGroup(anotherGroup);
//test add non-existent group
admin.deleteNamespace(nsName);
rsGroupAdmin.removeRSGroup(groupName);
assertTrue(observer.preRemoveRSGroupCalled);
assertTrue(observer.postRemoveRSGroupCalled);
try {
admin.createNamespace(NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "foo")
.build());
fail("Expected a constraint exception");
} catch (IOException ex) {
}
}
@Test
public void testGroupInfoMultiAccessing() throws Exception {
RSGroupInfoManager manager = rsGroupAdminEndpoint.getGroupInfoManager();
RSGroupInfo defaultGroup = manager.getRSGroup("default");
// getRSGroup updates default group's server list
// this process must not affect other threads iterating the list
Iterator<Address> it = defaultGroup.getServers().iterator();
manager.getRSGroup("default");
it.next();
}
public static class CPMasterObserver implements MasterCoprocessor, MasterObserver {
boolean preBalanceRSGroupCalled = false;
boolean postBalanceRSGroupCalled = false;
boolean preMoveServersCalled = false;
boolean postMoveServersCalled = false;
boolean preMoveTablesCalled = false;
boolean postMoveTablesCalled = false;
boolean preAddRSGroupCalled = false;
boolean postAddRSGroupCalled = false;
boolean preRemoveRSGroupCalled = false;
boolean postRemoveRSGroupCalled = false;
boolean preRemoveServersCalled = false;
boolean postRemoveServersCalled = false;
boolean preMoveServersAndTables = false;
boolean postMoveServersAndTables = false;
void resetFlags() {
preBalanceRSGroupCalled = false;
postBalanceRSGroupCalled = false;
preMoveServersCalled = false;
postMoveServersCalled = false;
preMoveTablesCalled = false;
postMoveTablesCalled = false;
preAddRSGroupCalled = false;
postAddRSGroupCalled = false;
preRemoveRSGroupCalled = false;
postRemoveRSGroupCalled = false;
preRemoveServersCalled = false;
postRemoveServersCalled = false;
preMoveServersAndTables = false;
postMoveServersAndTables = false;
}
@Override
public Optional<MasterObserver> getMasterObserver() {
return Optional.of(this);
}
@Override
public void preMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException {
preMoveServersAndTables = true;
}
@Override
public void postMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException {
postMoveServersAndTables = true;
}
@Override
public void preRemoveServers(
final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers) throws IOException {
preRemoveServersCalled = true;
}
@Override
public void postRemoveServers(
final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers) throws IOException {
postRemoveServersCalled = true;
}
@Override
public void preRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
String name) throws IOException {
preRemoveRSGroupCalled = true;
}
@Override
public void postRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
String name) throws IOException {
postRemoveRSGroupCalled = true;
}
@Override
public void preAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
String name) throws IOException {
preAddRSGroupCalled = true;
}
@Override
public void postAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
String name) throws IOException {
postAddRSGroupCalled = true;
}
@Override
public void preMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<TableName> tables, String targetGroup) throws IOException {
preMoveTablesCalled = true;
}
@Override
public void postMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<TableName> tables, String targetGroup) throws IOException {
postMoveTablesCalled = true;
}
@Override
public void preMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers, String targetGroup) throws IOException {
preMoveServersCalled = true;
}
@Override
public void postMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers, String targetGroup) throws IOException {
postMoveServersCalled = true;
}
@Override
public void preBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
String groupName) throws IOException {
preBalanceRSGroupCalled = true;
}
@Override
public void postBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
String groupName, boolean balancerRan) throws IOException {
postBalanceRSGroupCalled = true;
}
}
@Test
public void testMoveServersAndTables() throws Exception {
super.testMoveServersAndTables();
assertTrue(observer.preMoveServersAndTables);
assertTrue(observer.postMoveServersAndTables);
}
@Test
public void testTableMoveTruncateAndDrop() throws Exception {
super.testTableMoveTruncateAndDrop();
assertTrue(observer.preMoveTablesCalled);
assertTrue(observer.postMoveTablesCalled);
}
@Test
public void testRemoveServers() throws Exception {
super.testRemoveServers();
assertTrue(observer.preRemoveServersCalled);
assertTrue(observer.postRemoveServersCalled);
}
@Test
public void testMisplacedRegions() throws Exception {
final TableName tableName = TableName.valueOf(tablePrefix+"_testMisplacedRegions");
LOG.info("testMisplacedRegions");
final RSGroupInfo RSGroupInfo = addGroup("testMisplacedRegions", 1);
TEST_UTIL.createMultiRegionTable(tableName, new byte[]{'f'}, 15);
TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
rsGroupAdminEndpoint.getGroupInfoManager()
.moveTables(Sets.newHashSet(tableName), RSGroupInfo.getName());
admin.setBalancerRunning(true,true);
assertTrue(rsGroupAdmin.balanceRSGroup(RSGroupInfo.getName()));
admin.setBalancerRunning(false,true);
assertTrue(observer.preBalanceRSGroupCalled);
assertTrue(observer.postBalanceRSGroupCalled);
TEST_UTIL.waitFor(60000, new Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
ServerName serverName =
ServerName.valueOf(RSGroupInfo.getServers().iterator().next().toString(), 1);
return admin.getConnection().getAdmin()
.getOnlineRegions(serverName).size() == 15;
}
});
}
@Test
public void testCloneSnapshot() throws Exception {
byte[] FAMILY = Bytes.toBytes("test");
String snapshotName = tableName.getNameAsString() + "_snap";
TableName clonedTableName = TableName.valueOf(tableName.getNameAsString() + "_clone");
// create base table
TEST_UTIL.createTable(tableName, FAMILY);
// create snapshot
admin.snapshot(snapshotName, tableName);
// clone
admin.cloneSnapshot(snapshotName, clonedTableName);
}
@Test
public void testRSGroupsWithHBaseQuota() throws Exception {
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
restartHBaseCluster();
try {
TEST_UTIL.waitFor(90000, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return admin.isTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
}
});
} finally {
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, false);
restartHBaseCluster();
}
}
@Test
public void testRSGroupListDoesNotContainFailedTableCreation() throws Exception {
toggleQuotaCheckAndRestartMiniCluster(true);
String nsp = "np1";
NamespaceDescriptor nspDesc =
NamespaceDescriptor.create(nsp).addConfiguration(TableNamespaceManager.KEY_MAX_REGIONS, "5")
.addConfiguration(TableNamespaceManager.KEY_MAX_TABLES, "2").build();
admin.createNamespace(nspDesc);
assertEquals(3, admin.listNamespaceDescriptors().length);
HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
HTableDescriptor tableDescOne =
new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"));
tableDescOne.addFamily(fam1);
admin.createTable(tableDescOne);
HTableDescriptor tableDescTwo =
new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2"));
tableDescTwo.addFamily(fam1);
boolean constraintViolated = false;
try {
admin.createTable(tableDescTwo, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"),
6);
Assert.fail("Creation table should fail because of quota violation.");
} catch (Exception exp) {
assertTrue(exp instanceof IOException);
constraintViolated = true;
} finally {
assertTrue("Constraint not violated for table " + tableDescTwo.getTableName(),
constraintViolated);
}
List<RSGroupInfo> rsGroupInfoList = rsGroupAdmin.listRSGroups();
boolean foundTable2 = false;
boolean foundTable1 = false;
for(int i = 0; i < rsGroupInfoList.size(); i++){
if(rsGroupInfoList.get(i).getTables().contains(tableDescTwo.getTableName())){
foundTable2 = true;
}
if(rsGroupInfoList.get(i).getTables().contains(tableDescOne.getTableName())){
foundTable1 = true;
}
}
assertFalse("Found table2 in rsgroup list.", foundTable2);
assertTrue("Did not find table1 in rsgroup list", foundTable1);
TEST_UTIL.deleteTable(tableDescOne.getTableName());
admin.deleteNamespace(nspDesc.getName());
toggleQuotaCheckAndRestartMiniCluster(false);
}
private void toggleQuotaCheckAndRestartMiniCluster(boolean enable) throws Exception{
TEST_UTIL.shutdownMiniCluster();
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, enable);
TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setInt(
ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
initialize();
}
private void restartHBaseCluster() throws Exception {
LOG.info("\n\nShutting down cluster");
TEST_UTIL.shutdownMiniHBaseCluster();
LOG.info("\n\nSleeping a bit");
Thread.sleep(2000);
TEST_UTIL.restartHBaseCluster(NUM_SLAVES_BASE - 1);
initialize();
}
}

View File

@ -0,0 +1,441 @@
/**
* 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.rsgroup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.constraint.ConstraintException;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.master.TableNamespaceManager;
import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaUtil;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
@Category({MediumTests.class})
public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRSGroupsAdmin1.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsAdmin1.class);
@BeforeClass
public static void setUp() throws Exception {
setUpTestBeforeClass();
}
@AfterClass
public static void tearDown() throws Exception {
tearDownAfterClass();
}
@Before
public void beforeMethod() throws Exception {
setUpBeforeMethod();
}
@After
public void afterMethod() throws Exception {
tearDownAfterMethod();
}
@Test
public void testValidGroupNames() throws IOException {
String[] badNames = {"foo*","foo@","-"};
String[] goodNames = {"foo_123"};
for(String entry: badNames) {
try {
rsGroupAdmin.addRSGroup(entry);
fail("Expected a constraint exception for: "+entry);
} catch(ConstraintException ex) {
//expected
}
}
for(String entry: goodNames) {
rsGroupAdmin.addRSGroup(entry);
}
}
@Test
public void testBogusArgs() throws Exception {
assertNull(rsGroupAdmin.getRSGroupInfoOfTable(TableName.valueOf("nonexistent")));
assertNull(rsGroupAdmin.getRSGroupOfServer(Address.fromParts("bogus",123)));
assertNull(rsGroupAdmin.getRSGroupInfo("bogus"));
try {
rsGroupAdmin.removeRSGroup("bogus");
fail("Expected removing bogus group to fail");
} catch(ConstraintException ex) {
//expected
}
try {
rsGroupAdmin.moveTables(Sets.newHashSet(TableName.valueOf("bogustable")), "bogus");
fail("Expected move with bogus group to fail");
} catch(ConstraintException|TableNotFoundException ex) {
//expected
}
try {
rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromParts("bogus",123)), "bogus");
fail("Expected move with bogus group to fail");
} catch(ConstraintException ex) {
//expected
}
try {
admin.setBalancerRunning(true,true);
rsGroupAdmin.balanceRSGroup("bogus");
admin.setBalancerRunning(false,true);
fail("Expected move with bogus group to fail");
} catch(ConstraintException ex) {
//expected
}
}
@Test
public void testNamespaceConstraint() throws Exception {
String nsName = tablePrefix+"_foo";
String groupName = tablePrefix+"_foo";
LOG.info("testNamespaceConstraint");
rsGroupAdmin.addRSGroup(groupName);
assertTrue(observer.preAddRSGroupCalled);
assertTrue(observer.postAddRSGroupCalled);
admin.createNamespace(NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
.build());
//test removing a referenced group
try {
rsGroupAdmin.removeRSGroup(groupName);
fail("Expected a constraint exception");
} catch (IOException ex) {
}
//test modify group
//changing with the same name is fine
admin.modifyNamespace(
NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName)
.build());
String anotherGroup = tablePrefix+"_anotherGroup";
rsGroupAdmin.addRSGroup(anotherGroup);
//test add non-existent group
admin.deleteNamespace(nsName);
rsGroupAdmin.removeRSGroup(groupName);
assertTrue(observer.preRemoveRSGroupCalled);
assertTrue(observer.postRemoveRSGroupCalled);
try {
admin.createNamespace(NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "foo")
.build());
fail("Expected a constraint exception");
} catch (IOException ex) {
}
}
@Test
public void testGroupInfoMultiAccessing() throws Exception {
RSGroupInfoManager manager = rsGroupAdminEndpoint.getGroupInfoManager();
RSGroupInfo defaultGroup = manager.getRSGroup("default");
// getRSGroup updates default group's server list
// this process must not affect other threads iterating the list
Iterator<Address> it = defaultGroup.getServers().iterator();
manager.getRSGroup("default");
it.next();
}
@Test
public void testFailRemoveGroup() throws IOException, InterruptedException {
int initNumGroups = rsGroupAdmin.listRSGroups().size();
addGroup("bar", 3);
TEST_UTIL.createTable(tableName, Bytes.toBytes("f"));
rsGroupAdmin.moveTables(Sets.newHashSet(tableName), "bar");
RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
//group is not empty therefore it should fail
try {
rsGroupAdmin.removeRSGroup(barGroup.getName());
fail("Expected remove group to fail");
} catch(IOException e) {
}
//group cannot lose all it's servers therefore it should fail
try {
rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
fail("Expected move servers to fail");
} catch(IOException e) {
}
rsGroupAdmin.moveTables(barGroup.getTables(), RSGroupInfo.DEFAULT_GROUP);
try {
rsGroupAdmin.removeRSGroup(barGroup.getName());
fail("Expected move servers to fail");
} catch(IOException e) {
}
rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(barGroup.getName());
Assert.assertEquals(initNumGroups, rsGroupAdmin.listRSGroups().size());
}
@Test
public void testMultiTableMove() throws Exception {
final TableName tableNameA = TableName.valueOf(tablePrefix + name.getMethodName() + "A");
final TableName tableNameB = TableName.valueOf(tablePrefix + name.getMethodName() + "B");
final byte[] familyNameBytes = Bytes.toBytes("f");
String newGroupName = getGroupName(name.getMethodName());
final RSGroupInfo newGroup = addGroup(newGroupName, 1);
TEST_UTIL.createTable(tableNameA, familyNameBytes);
TEST_UTIL.createTable(tableNameB, familyNameBytes);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
List<String> regionsA = getTableRegionMap().get(tableNameA);
if (regionsA == null) {
return false;
}
List<String> regionsB = getTableRegionMap().get(tableNameB);
if (regionsB == null) {
return false;
}
return getTableRegionMap().get(tableNameA).size() >= 1
&& getTableRegionMap().get(tableNameB).size() >= 1;
}
});
RSGroupInfo tableGrpA = rsGroupAdmin.getRSGroupInfoOfTable(tableNameA);
assertTrue(tableGrpA.getName().equals(RSGroupInfo.DEFAULT_GROUP));
RSGroupInfo tableGrpB = rsGroupAdmin.getRSGroupInfoOfTable(tableNameB);
assertTrue(tableGrpB.getName().equals(RSGroupInfo.DEFAULT_GROUP));
//change table's group
LOG.info("Moving table [" + tableNameA + "," + tableNameB + "] to " + newGroup.getName());
rsGroupAdmin.moveTables(Sets.newHashSet(tableNameA, tableNameB), newGroup.getName());
//verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableNameA).getName());
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableNameB).getName());
//verify tables' not exist in old group
Set<TableName> DefaultTables =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables();
assertFalse(DefaultTables.contains(tableNameA));
assertFalse(DefaultTables.contains(tableNameB));
//verify tables' exist in new group
Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroupName).getTables();
assertTrue(newGroupTables.contains(tableNameA));
assertTrue(newGroupTables.contains(tableNameB));
}
@Test
public void testTableMoveTruncateAndDrop() throws Exception {
final byte[] familyNameBytes = Bytes.toBytes("f");
String newGroupName = getGroupName(name.getMethodName());
final RSGroupInfo newGroup = addGroup(newGroupName, 2);
TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
List<String> regions = getTableRegionMap().get(tableName);
if (regions == null) {
return false;
}
return getTableRegionMap().get(tableName).size() >= 5;
}
});
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
//change table's group
LOG.info("Moving table "+tableName+" to "+newGroup.getName());
rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
//verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
Map<ServerName, List<String>> serverMap = getTableServerRegionMap().get(tableName);
int count = 0;
if (serverMap != null) {
for (ServerName rs : serverMap.keySet()) {
if (newGroup.containsServer(rs.getAddress())) {
count += serverMap.get(rs).size();
}
}
}
return count == 5;
}
});
//test truncate
admin.disableTable(tableName);
admin.truncateTable(tableName, true);
Assert.assertEquals(1, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
Assert.assertEquals(tableName, rsGroupAdmin.getRSGroupInfo(
newGroup.getName()).getTables().first());
//verify removed table is removed from group
TEST_UTIL.deleteTable(tableName);
Assert.assertEquals(0, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
assertTrue(observer.preMoveTablesCalled);
assertTrue(observer.postMoveTablesCalled);
}
@Test
public void testDisabledTableMove() throws Exception {
final byte[] familyNameBytes = Bytes.toBytes("f");
String newGroupName = getGroupName(name.getMethodName());
final RSGroupInfo newGroup = addGroup(newGroupName, 2);
TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
List<String> regions = getTableRegionMap().get(tableName);
if (regions == null) {
return false;
}
return getTableRegionMap().get(tableName).size() >= 5;
}
});
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
//test disable table
admin.disableTable(tableName);
//change table's group
LOG.info("Moving table "+ tableName + " to " + newGroup.getName());
rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
//verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
}
@Test
public void testRSGroupListDoesNotContainFailedTableCreation() throws Exception {
toggleQuotaCheckAndRestartMiniCluster(true);
String nsp = "np1";
NamespaceDescriptor nspDesc =
NamespaceDescriptor.create(nsp)
.addConfiguration(TableNamespaceManager.KEY_MAX_REGIONS, "5")
.addConfiguration(TableNamespaceManager.KEY_MAX_TABLES, "2").build();
admin.createNamespace(nspDesc);
assertEquals(3, admin.listNamespaceDescriptors().length);
HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
HTableDescriptor tableDescOne =
new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"));
tableDescOne.addFamily(fam1);
admin.createTable(tableDescOne);
HTableDescriptor tableDescTwo =
new HTableDescriptor(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2"));
tableDescTwo.addFamily(fam1);
boolean constraintViolated = false;
try {
admin.createTable(tableDescTwo, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"),
6);
Assert.fail("Creation table should fail because of quota violation.");
} catch (Exception exp) {
assertTrue(exp instanceof IOException);
constraintViolated = true;
} finally {
assertTrue("Constraint not violated for table " + tableDescTwo.getTableName(),
constraintViolated);
}
List<RSGroupInfo> rsGroupInfoList = rsGroupAdmin.listRSGroups();
boolean foundTable2 = false;
boolean foundTable1 = false;
for(int i = 0; i < rsGroupInfoList.size(); i++){
if(rsGroupInfoList.get(i).getTables().contains(tableDescTwo.getTableName())){
foundTable2 = true;
}
if(rsGroupInfoList.get(i).getTables().contains(tableDescOne.getTableName())){
foundTable1 = true;
}
}
assertFalse("Found table2 in rsgroup list.", foundTable2);
assertTrue("Did not find table1 in rsgroup list", foundTable1);
TEST_UTIL.deleteTable(tableDescOne.getTableName());
admin.deleteNamespace(nspDesc.getName());
toggleQuotaCheckAndRestartMiniCluster(false);
}
private void toggleQuotaCheckAndRestartMiniCluster(boolean enable) throws Exception{
TEST_UTIL.shutdownMiniCluster();
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, enable);
TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setInt(
ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
initialize();
}
}

View File

@ -0,0 +1,487 @@
/**
* 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.rsgroup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hbase.ClusterMetrics.Option;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.client.ClusterConnection;
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.constraint.ConstraintException;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.GetServerInfoRequest;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
@Category({MediumTests.class})
public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRSGroupsAdmin2.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsAdmin2.class);
@BeforeClass
public static void setUp() throws Exception {
setUpTestBeforeClass();
}
@AfterClass
public static void tearDown() throws Exception {
tearDownAfterClass();
}
@Before
public void beforeMethod() throws Exception {
setUpBeforeMethod();
}
@After
public void afterMethod() throws Exception {
tearDownAfterMethod();
}
@Test
public void testRegionMove() throws Exception {
final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 1);
final byte[] familyNameBytes = Bytes.toBytes("f");
// All the regions created below will be assigned to the default group.
TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 6);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
List<String> regions = getTableRegionMap().get(tableName);
if (regions == null) {
return false;
}
return getTableRegionMap().get(tableName).size() >= 6;
}
});
//get target region to move
Map<ServerName,List<String>> assignMap =
getTableServerRegionMap().get(tableName);
String targetRegion = null;
for(ServerName server : assignMap.keySet()) {
targetRegion = assignMap.get(server).size() > 0 ? assignMap.get(server).get(0) : null;
if(targetRegion != null) {
break;
}
}
//get server which is not a member of new group
ServerName targetServer = null;
for (ServerName server : admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
.getLiveServerMetrics().keySet()) {
if (!newGroup.containsServer(server.getAddress())) {
targetServer = server;
break;
}
}
final AdminProtos.AdminService.BlockingInterface targetRS =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
//move target server to group
rsGroupAdmin.moveServers(Sets.newHashSet(targetServer.getAddress()),
newGroup.getName());
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return ProtobufUtil.getOnlineRegions(targetRS).size() <= 0;
}
});
// Lets move this region to the new group.
TEST_UTIL.getAdmin().move(Bytes.toBytes(RegionInfo.encodeRegionName(
Bytes.toBytes(targetRegion))), Bytes.toBytes(targetServer.getServerName()));
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return
getTableRegionMap().get(tableName) != null &&
getTableRegionMap().get(tableName).size() == 6 &&
admin.getClusterMetrics(EnumSet.of(Option.REGIONS_IN_TRANSITION))
.getRegionStatesInTransition().size() < 1;
}
});
//verify that targetServer didn't open it
for (RegionInfo region: ProtobufUtil.getOnlineRegions(targetRS)) {
if (targetRegion.equals(region.getRegionNameAsString())) {
fail("Target server opened region");
}
}
}
@Test
public void testRegionServerMove() throws IOException,
InterruptedException {
int initNumGroups = rsGroupAdmin.listRSGroups().size();
RSGroupInfo appInfo = addGroup(getGroupName(name.getMethodName()), 1);
RSGroupInfo adminInfo = addGroup(getGroupName(name.getMethodName()), 1);
RSGroupInfo dInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
Assert.assertEquals(initNumGroups + 2, rsGroupAdmin.listRSGroups().size());
assertEquals(1, adminInfo.getServers().size());
assertEquals(1, appInfo.getServers().size());
assertEquals(getNumServers() - 2, dInfo.getServers().size());
rsGroupAdmin.moveServers(appInfo.getServers(),
RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(appInfo.getName());
rsGroupAdmin.moveServers(adminInfo.getServers(),
RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(adminInfo.getName());
Assert.assertEquals(rsGroupAdmin.listRSGroups().size(), initNumGroups);
}
@Test
public void testMoveServers() throws Exception {
//create groups and assign servers
addGroup("bar", 3);
rsGroupAdmin.addRSGroup("foo");
RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
RSGroupInfo fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
assertEquals(3, barGroup.getServers().size());
assertEquals(0, fooGroup.getServers().size());
//test fail bogus server move
try {
rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromString("foo:9999")),"foo");
fail("Bogus servers shouldn't have been successfully moved.");
} catch(IOException ex) {
String exp = "Source RSGroup for server foo:9999 does not exist.";
String msg = "Expected '"+exp+"' in exception message: ";
assertTrue(msg+" "+ex.getMessage(), ex.getMessage().contains(exp));
}
//test success case
LOG.info("moving servers "+barGroup.getServers()+" to group foo");
rsGroupAdmin.moveServers(barGroup.getServers(), fooGroup.getName());
barGroup = rsGroupAdmin.getRSGroupInfo("bar");
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
assertEquals(0,barGroup.getServers().size());
assertEquals(3,fooGroup.getServers().size());
LOG.info("moving servers "+fooGroup.getServers()+" to group default");
rsGroupAdmin.moveServers(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getNumServers() ==
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
}
});
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
assertEquals(0,fooGroup.getServers().size());
//test group removal
LOG.info("Remove group "+barGroup.getName());
rsGroupAdmin.removeRSGroup(barGroup.getName());
Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(barGroup.getName()));
LOG.info("Remove group "+fooGroup.getName());
rsGroupAdmin.removeRSGroup(fooGroup.getName());
Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(fooGroup.getName()));
}
@Test
public void testRemoveServers() throws Exception {
LOG.info("testRemoveServers");
final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 3);
Iterator<Address> iterator = newGroup.getServers().iterator();
ServerName targetServer = ServerName.parseServerName(iterator.next().toString());
// remove online servers
try {
rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
fail("Online servers shouldn't have been successfully removed.");
} catch(IOException ex) {
String exp = "Server " + targetServer.getAddress()
+ " is an online server, not allowed to remove.";
String msg = "Expected '" + exp + "' in exception message: ";
assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
}
assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
// remove dead servers
NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
AdminProtos.AdminService.BlockingInterface targetRS =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
try {
targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
//stopping may cause an exception
//due to the connection loss
LOG.info("stopping server " + targetServer.getServerName());
targetRS.stopServer(null,
AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
NUM_DEAD_SERVERS ++;
} catch(Exception e) {
}
//wait for stopped regionserver to dead server list
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return !master.getServerManager().areDeadServersInProgress()
&& cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
}
});
try {
rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
fail("Dead servers shouldn't have been successfully removed.");
} catch(IOException ex) {
String exp = "Server " + targetServer.getAddress() + " is on the dead servers list,"
+ " Maybe it will come back again, not allowed to remove.";
String msg = "Expected '" + exp + "' in exception message: ";
assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
}
assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
// remove decommissioned servers
List<ServerName> serversToDecommission = new ArrayList<>();
targetServer = ServerName.parseServerName(iterator.next().toString());
targetRS = ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
assertTrue(master.getServerManager().getOnlineServers().containsKey(targetServer));
serversToDecommission.add(targetServer);
admin.decommissionRegionServers(serversToDecommission, true);
assertEquals(1, admin.listDecommissionedRegionServers().size());
assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
assertFalse(newGroupServers.contains(targetServer.getAddress()));
assertEquals(2, newGroupServers.size());
assertTrue(observer.preRemoveServersCalled);
assertTrue(observer.postRemoveServersCalled);
}
@Test
public void testMoveServersAndTables() throws Exception {
LOG.info("testMoveServersAndTables");
final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 1);
//create table
final byte[] familyNameBytes = Bytes.toBytes("f");
TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
List<String> regions = getTableRegionMap().get(tableName);
if (regions == null) {
return false;
}
return getTableRegionMap().get(tableName).size() >= 5;
}
});
//get server which is not a member of new group
ServerName targetServer = null;
for(ServerName server : admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
.getLiveServerMetrics().keySet()) {
if(!newGroup.containsServer(server.getAddress()) &&
!rsGroupAdmin.getRSGroupInfo("master").containsServer(server.getAddress())) {
targetServer = server;
break;
}
}
LOG.debug("Print group info : " + rsGroupAdmin.listRSGroups());
int oldDefaultGroupServerSize =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
int oldDefaultGroupTableSize =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size();
//test fail bogus server move
try {
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(Address.fromString("foo:9999")),
Sets.newHashSet(tableName), newGroup.getName());
fail("Bogus servers shouldn't have been successfully moved.");
} catch(IOException ex) {
String exp = "Source RSGroup for server foo:9999 does not exist.";
String msg = "Expected '" + exp + "' in exception message: ";
assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
}
//test fail server move
try {
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
fail("servers shouldn't have been successfully moved.");
} catch(IOException ex) {
String exp = "Target RSGroup " + RSGroupInfo.DEFAULT_GROUP +
" is same as source " + RSGroupInfo.DEFAULT_GROUP + " RSGroup.";
String msg = "Expected '" + exp + "' in exception message: ";
assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
}
//verify default group info
Assert.assertEquals(oldDefaultGroupServerSize,
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size());
Assert.assertEquals(oldDefaultGroupTableSize,
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size());
//verify new group info
Assert.assertEquals(1,
rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers().size());
Assert.assertEquals(0,
rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
//get all region to move targetServer
List<String> regionList = getTableRegionMap().get(tableName);
for(String region : regionList) {
// Lets move this region to the targetServer
TEST_UTIL.getAdmin().move(Bytes.toBytes(RegionInfo.encodeRegionName(Bytes.toBytes(region))),
Bytes.toBytes(targetServer.getServerName()));
}
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getTableRegionMap().get(tableName) != null &&
getTableRegionMap().get(tableName).size() == 5 &&
getTableServerRegionMap().get(tableName).size() == 1 &&
admin.getClusterMetrics(EnumSet.of(Option.REGIONS_IN_TRANSITION))
.getRegionStatesInTransition().size() < 1;
}
});
//verify that all region move to targetServer
Assert.assertEquals(5, getTableServerRegionMap().get(tableName).get(targetServer).size());
//move targetServer and table to newGroup
LOG.info("moving server and table to newGroup");
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
Sets.newHashSet(tableName), newGroup.getName());
//verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
//verify servers' not exist in old group
Set<Address> defaultServers = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP)
.getServers();
assertFalse(defaultServers.contains(targetServer.getAddress()));
//verify servers' exist in new group
Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
assertTrue(newGroupServers.contains(targetServer.getAddress()));
//verify tables' not exist in old group
Set<TableName> defaultTables = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP)
.getTables();
assertFalse(defaultTables.contains(tableName));
//verify tables' exist in new group
Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables();
assertTrue(newGroupTables.contains(tableName));
//verify that all region still assgin on targetServer
Assert.assertEquals(5, getTableServerRegionMap().get(tableName).get(targetServer).size());
assertTrue(observer.preMoveServersAndTables);
assertTrue(observer.postMoveServersAndTables);
}
@Test
public void testMoveServersFromDefaultGroup() throws Exception {
//create groups and assign servers
rsGroupAdmin.addRSGroup("foo");
RSGroupInfo fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
assertEquals(0, fooGroup.getServers().size());
RSGroupInfo defaultGroup = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
//test remove all servers from default
try {
rsGroupAdmin.moveServers(defaultGroup.getServers(), fooGroup.getName());
fail(RSGroupAdminServer.KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE);
} catch (ConstraintException ex) {
assertTrue(ex.getMessage().contains(RSGroupAdminServer
.KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE));
}
//test success case, remove one server from default ,keep at least one server
if (defaultGroup.getServers().size() > 1) {
Address serverInDefaultGroup = defaultGroup.getServers().iterator().next();
LOG.info("moving server " + serverInDefaultGroup + " from group default to group " +
fooGroup.getName());
rsGroupAdmin.moveServers(Sets.newHashSet(serverInDefaultGroup), fooGroup.getName());
}
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
LOG.info("moving servers " + fooGroup.getServers() + " to group default");
rsGroupAdmin.moveServers(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getNumServers() ==
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
}
});
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
assertEquals(0, fooGroup.getServers().size());
//test group removal
LOG.info("Remove group " + fooGroup.getName());
rsGroupAdmin.removeRSGroup(fooGroup.getName());
Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(fooGroup.getName()));
}
}

View File

@ -0,0 +1,188 @@
/**
* 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.rsgroup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.Waiter.Predicate;
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
@Category({MediumTests.class})
public class TestRSGroupsBalance extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRSGroupsBalance.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsBalance.class);
@BeforeClass
public static void setUp() throws Exception {
setUpTestBeforeClass();
}
@AfterClass
public static void tearDown() throws Exception {
tearDownAfterClass();
}
@Before
public void beforeMethod() throws Exception {
setUpBeforeMethod();
}
@After
public void afterMethod() throws Exception {
tearDownAfterMethod();
}
@Test
public void testGroupBalance() throws Exception {
LOG.info(name.getMethodName());
String newGroupName = getGroupName(name.getMethodName());
final RSGroupInfo newGroup = addGroup(newGroupName, 3);
final TableName tableName = TableName.valueOf(tablePrefix+"_ns", name.getMethodName());
admin.createNamespace(
NamespaceDescriptor.create(tableName.getNamespaceAsString())
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, newGroupName).build());
final byte[] familyNameBytes = Bytes.toBytes("f");
final HTableDescriptor desc = new HTableDescriptor(tableName);
desc.addFamily(new HColumnDescriptor("f"));
byte [] startKey = Bytes.toBytes("aaaaa");
byte [] endKey = Bytes.toBytes("zzzzz");
admin.createTable(desc, startKey, endKey, 6);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
List<String> regions = getTableRegionMap().get(tableName);
if (regions == null) {
return false;
}
return regions.size() >= 6;
}
});
//make assignment uneven, move all regions to one server
Map<ServerName,List<String>> assignMap =
getTableServerRegionMap().get(tableName);
final ServerName first = assignMap.entrySet().iterator().next().getKey();
for(RegionInfo region: admin.getTableRegions(tableName)) {
if(!assignMap.get(first).contains(region.getRegionNameAsString())) {
admin.move(region.getEncodedNameAsBytes(), Bytes.toBytes(first.getServerName()));
}
}
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
Map<ServerName, List<String>> map = getTableServerRegionMap().get(tableName);
if (map == null) {
return true;
}
List<String> regions = map.get(first);
if (regions == null) {
return true;
}
return regions.size() >= 6;
}
});
//balance the other group and make sure it doesn't affect the new group
admin.setBalancerRunning(true,true);
rsGroupAdmin.balanceRSGroup(RSGroupInfo.DEFAULT_GROUP);
assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
//disable balance, balancer will not be run and return false
admin.setBalancerRunning(false,true);
assertFalse(rsGroupAdmin.balanceRSGroup(newGroupName));
assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
//enable balance
admin.setBalancerRunning(true,true);
rsGroupAdmin.balanceRSGroup(newGroupName);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
for (List<String> regions : getTableServerRegionMap().get(tableName).values()) {
if (2 != regions.size()) {
return false;
}
}
return true;
}
});
admin.setBalancerRunning(false,true);
}
@Test
public void testMisplacedRegions() throws Exception {
final TableName tableName = TableName.valueOf(tablePrefix+"_testMisplacedRegions");
LOG.info("testMisplacedRegions");
final RSGroupInfo RSGroupInfo = addGroup("testMisplacedRegions", 1);
TEST_UTIL.createMultiRegionTable(tableName, new byte[]{'f'}, 15);
TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
rsGroupAdminEndpoint.getGroupInfoManager()
.moveTables(Sets.newHashSet(tableName), RSGroupInfo.getName());
admin.setBalancerRunning(true,true);
assertTrue(rsGroupAdmin.balanceRSGroup(RSGroupInfo.getName()));
admin.setBalancerRunning(false,true);
assertTrue(observer.preBalanceRSGroupCalled);
assertTrue(observer.postBalanceRSGroupCalled);
TEST_UTIL.waitFor(60000, new Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
ServerName serverName =
ServerName.valueOf(RSGroupInfo.getServers().iterator().next().toString(), 1);
return admin.getConnection().getAdmin()
.getOnlineRegions(serverName).size() == 15;
}
});
}
}

View File

@ -0,0 +1,320 @@
/**
* 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.rsgroup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.client.ClusterConnection;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
import org.apache.hadoop.hbase.quotas.QuotaUtil;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.GetServerInfoRequest;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
@Category({MediumTests.class})
public class TestRSGroupsBasics extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRSGroupsBasics.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsBasics.class);
@BeforeClass
public static void setUp() throws Exception {
setUpTestBeforeClass();
}
@AfterClass
public static void tearDown() throws Exception {
tearDownAfterClass();
}
@Before
public void beforeMethod() throws Exception {
setUpBeforeMethod();
}
@After
public void afterMethod() throws Exception {
tearDownAfterMethod();
}
@Test
public void testBasicStartUp() throws IOException {
RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
assertEquals(4, defaultInfo.getServers().size());
// Assignment of root and meta regions.
int count = master.getAssignmentManager().getRegionStates().getRegionAssignments().size();
//3 meta,namespace, group
assertEquals(3, count);
}
@Test
public void testCreateAndDrop() throws Exception {
TEST_UTIL.createTable(tableName, Bytes.toBytes("cf"));
//wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getTableRegionMap().get(tableName) != null;
}
});
TEST_UTIL.deleteTable(tableName);
}
@Test
public void testCreateMultiRegion() throws IOException {
byte[] end = {1,3,5,7,9};
byte[] start = {0,2,4,6,8};
byte[][] f = {Bytes.toBytes("f")};
TEST_UTIL.createTable(tableName, f,1,start,end,10);
}
@Test
public void testNamespaceCreateAndAssign() throws Exception {
LOG.info("testNamespaceCreateAndAssign");
String nsName = tablePrefix+"_foo";
final TableName tableName = TableName.valueOf(nsName, tablePrefix + "_testCreateAndAssign");
RSGroupInfo appInfo = addGroup("appInfo", 1);
admin.createNamespace(NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "appInfo").build());
final HTableDescriptor desc = new HTableDescriptor(tableName);
desc.addFamily(new HColumnDescriptor("f"));
admin.createTable(desc);
//wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getTableRegionMap().get(desc.getTableName()) != null;
}
});
ServerName targetServer =
ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
AdminProtos.AdminService.BlockingInterface rs =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
//verify it was assigned to the right group
Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(rs).size());
}
@Test
public void testCreateWhenRsgroupNoOnlineServers() throws Exception {
LOG.info("testCreateWhenRsgroupNoOnlineServers");
// set rsgroup has no online servers and test create table
final RSGroupInfo appInfo = addGroup("appInfo", 1);
Iterator<Address> iterator = appInfo.getServers().iterator();
List<ServerName> serversToDecommission = new ArrayList<>();
ServerName targetServer = ServerName.parseServerName(iterator.next().toString());
AdminProtos.AdminService.BlockingInterface targetRS =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
targetServer = ProtobufUtil.toServerName(
targetRS.getServerInfo(null, GetServerInfoRequest.newBuilder().build()).getServerInfo()
.getServerName());
assertTrue(master.getServerManager().getOnlineServers().containsKey(targetServer));
serversToDecommission.add(targetServer);
admin.decommissionRegionServers(serversToDecommission, true);
assertEquals(1, admin.listDecommissionedRegionServers().size());
final TableName tableName = TableName.valueOf(tablePrefix + "_ns", name.getMethodName());
admin.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString())
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
final HTableDescriptor desc = new HTableDescriptor(tableName);
desc.addFamily(new HColumnDescriptor("f"));
try {
admin.createTable(desc);
fail("Shouldn't create table successfully!");
} catch (Exception e) {
LOG.debug("create table error", e);
}
// recommission and test create table
admin.recommissionRegionServer(targetServer, null);
assertEquals(0, admin.listDecommissionedRegionServers().size());
admin.createTable(desc);
// wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override public boolean evaluate() throws Exception {
return getTableRegionMap().get(desc.getTableName()) != null;
}
});
}
@Test
public void testDefaultNamespaceCreateAndAssign() throws Exception {
LOG.info("testDefaultNamespaceCreateAndAssign");
String tableName = tablePrefix + "_testCreateAndAssign";
admin.modifyNamespace(NamespaceDescriptor.create("default")
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "default").build());
final HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
desc.addFamily(new HColumnDescriptor("f"));
admin.createTable(desc);
//wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getTableRegionMap().get(desc.getTableName()) != null;
}
});
}
@Test
public void testCloneSnapshot() throws Exception {
byte[] FAMILY = Bytes.toBytes("test");
String snapshotName = tableName.getNameAsString() + "_snap";
TableName clonedTableName = TableName.valueOf(tableName.getNameAsString() + "_clone");
// create base table
TEST_UTIL.createTable(tableName, FAMILY);
// create snapshot
admin.snapshot(snapshotName, tableName);
// clone
admin.cloneSnapshot(snapshotName, clonedTableName);
}
@Test
public void testClearDeadServers() throws Exception {
LOG.info("testClearDeadServers");
final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 3);
NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
ServerName targetServer = ServerName.parseServerName(
newGroup.getServers().iterator().next().toString());
AdminProtos.AdminService.BlockingInterface targetRS =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
try {
targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
//stopping may cause an exception
//due to the connection loss
targetRS.stopServer(null,
AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
NUM_DEAD_SERVERS ++;
} catch(Exception e) {
}
//wait for stopped regionserver to dead server list
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return !master.getServerManager().areDeadServersInProgress()
&& cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
}
});
assertFalse(cluster.getClusterMetrics().getLiveServerMetrics().containsKey(targetServer));
assertTrue(cluster.getClusterMetrics().getDeadServerNames().contains(targetServer));
assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
//clear dead servers list
List<ServerName> notClearedServers = admin.clearDeadServers(Lists.newArrayList(targetServer));
assertEquals(0, notClearedServers.size());
Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
assertFalse(newGroupServers.contains(targetServer.getAddress()));
assertEquals(2, newGroupServers.size());
}
@Test
public void testClearNotProcessedDeadServer() throws Exception {
LOG.info("testClearNotProcessedDeadServer");
NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
RSGroupInfo appInfo = addGroup("deadServerGroup", 1);
ServerName targetServer =
ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
AdminProtos.AdminService.BlockingInterface targetRS =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
try {
targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
AdminProtos.GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
//stopping may cause an exception
//due to the connection loss
targetRS.stopServer(null,
AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
NUM_DEAD_SERVERS ++;
} catch(Exception e) {
}
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
}
});
List<ServerName> notClearedServers =
admin.clearDeadServers(Lists.newArrayList(targetServer));
assertEquals(1, notClearedServers.size());
}
@Test
public void testRSGroupsWithHBaseQuota() throws Exception {
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
restartHBaseCluster();
try {
TEST_UTIL.waitFor(90000, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return admin.isTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
}
});
} finally {
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, false);
restartHBaseCluster();
}
}
private void restartHBaseCluster() throws Exception {
LOG.info("\n\nShutting down cluster");
TEST_UTIL.shutdownMiniHBaseCluster();
LOG.info("\n\nSleeping a bit");
Thread.sleep(2000);
TEST_UTIL.restartHBaseCluster(NUM_SLAVES_BASE - 1);
initialize();
}
}

View File

@ -0,0 +1,149 @@
/**
* 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.rsgroup;
import static org.junit.Assert.assertFalse;
import java.util.Set;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.client.ClusterConnection;
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.net.Address;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
@Category({MediumTests.class})
public class TestRSGroupsKillRS extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestRSGroupsKillRS.class);
protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsKillRS.class);
@BeforeClass
public static void setUp() throws Exception {
setUpTestBeforeClass();
}
@AfterClass
public static void tearDown() throws Exception {
tearDownAfterClass();
}
@Before
public void beforeMethod() throws Exception {
setUpBeforeMethod();
}
@After
public void afterMethod() throws Exception {
tearDownAfterMethod();
}
@Test
public void testKillRS() throws Exception {
RSGroupInfo appInfo = addGroup("appInfo", 1);
final TableName tableName = TableName.valueOf(tablePrefix+"_ns", name.getMethodName());
admin.createNamespace(
NamespaceDescriptor.create(tableName.getNamespaceAsString())
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
final HTableDescriptor desc = new HTableDescriptor(tableName);
desc.addFamily(new HColumnDescriptor("f"));
admin.createTable(desc);
//wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getTableRegionMap().get(desc.getTableName()) != null;
}
});
ServerName targetServer = ServerName.parseServerName(
appInfo.getServers().iterator().next().toString());
AdminProtos.AdminService.BlockingInterface targetRS =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
RegionInfo targetRegion = ProtobufUtil.getOnlineRegions(targetRS).get(0);
Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(targetRS).size());
try {
//stopping may cause an exception
//due to the connection loss
targetRS.stopServer(null,
AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
} catch(Exception e) {
}
assertFalse(cluster.getClusterMetrics().getLiveServerMetrics().containsKey(targetServer));
//wait for created table to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return cluster.getClusterMetrics().getRegionStatesInTransition().isEmpty();
}
});
Set<Address> newServers = Sets.newHashSet();
newServers.add(
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().iterator().next());
rsGroupAdmin.moveServers(newServers, appInfo.getName());
//Make sure all the table's regions get reassigned
//disabling the table guarantees no conflicting assign/unassign (ie SSH) happens
admin.disableTable(tableName);
admin.enableTable(tableName);
//wait for region to be assigned
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return cluster.getClusterMetrics().getRegionStatesInTransition().isEmpty();
}
});
targetServer = ServerName.parseServerName(
newServers.iterator().next().toString());
targetRS =
((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(targetRS).size());
Assert.assertEquals(tableName,
ProtobufUtil.getOnlineRegions(targetRS).get(0).getTable());
}
}

View File

@ -36,6 +36,7 @@ import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;

View File

@ -41,6 +41,7 @@ import org.apache.hadoop.hbase.security.access.TableAuthManager;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.SecurityTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@ -177,9 +178,10 @@ public class TestRSGroupsWithACL extends SecureTestUtil{
try {
assertEquals(4, AccessControlClient.getUserPermissions(systemUserConnection,
TEST_TABLE.toString()).size());
} catch (AssertionError e) {
fail(e.getMessage());
} catch (Throwable e) {
LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
fail("error during call of AccessControlClient.getUserPermissions.");
}
}