HBASE-20104 Fix infinite loop of RIT when creating table on a rsgroup that has no online servers

This commit is contained in:
haxiaolin 2018-03-01 08:34:31 -08:00 committed by tedyu
parent 776eb5d9cb
commit ee1f26c4bb
2 changed files with 76 additions and 0 deletions

View File

@ -31,6 +31,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.HBaseIOException;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
@ -352,6 +353,27 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver {
}
}
boolean rsgroupHasServersOnline(TableDescriptor desc) throws IOException {
String groupName =
master.getClusterSchema().getNamespace(desc.getTableName().getNamespaceAsString())
.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
if (groupName == null) {
groupName = RSGroupInfo.DEFAULT_GROUP;
}
RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName);
if (rsGroupInfo == null) {
throw new ConstraintException(
"Default RSGroup (" + groupName + ") for this table's " + "namespace does not exist.");
}
for (ServerName onlineServer : master.getServerManager().createDestinationServersList()) {
if (rsGroupInfo.getServers().contains(onlineServer.getAddress())) {
return true;
}
}
return false;
}
void assignTableToGroup(TableDescriptor desc) throws IOException {
String groupName =
master.getClusterSchema().getNamespace(desc.getTableName().getNamespaceAsString())
@ -374,6 +396,17 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver {
// MasterObserver overrides
/////////////////////////////////////////////////////////////////////////////
@Override
public void preCreateTableAction(
final ObserverContext<MasterCoprocessorEnvironment> ctx,
final TableDescriptor desc,
final RegionInfo[] regions) throws IOException {
if (!desc.getTableName().isSystemTable() && !rsgroupHasServersOnline(desc)) {
throw new HBaseIOException("No online servers in the rsgroup, which table " +
desc.getTableName().getNameAsString() + " belongs to");
}
}
// Assign table to default RSGroup.
@Override
public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> ctx,

View File

@ -999,4 +999,47 @@ public abstract class TestRSGroupsBase {
assertFalse(newGroupServers.contains(targetServer.getAddress()));
assertEquals(2, newGroupServers.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;
}
});
}
}