HBASE-20104 Fix infinite loop of RIT when creating table on a rsgroup that has no online servers
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/ee1f26c4 Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/ee1f26c4 Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/ee1f26c4 Branch: refs/heads/HBASE-19064 Commit: ee1f26c4bbb5490e257eee63933fd3943f102a7d Parents: 776eb5d Author: haxiaolin <haxiao...@xiaomi.com> Authored: Thu Mar 1 08:34:31 2018 -0800 Committer: tedyu <yuzhih...@gmail.com> Committed: Thu Mar 1 08:34:31 2018 -0800 ---------------------------------------------------------------------- .../hbase/rsgroup/RSGroupAdminEndpoint.java | 33 +++++++++++++++ .../hadoop/hbase/rsgroup/TestRSGroupsBase.java | 43 ++++++++++++++++++++ 2 files changed, 76 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/ee1f26c4/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java ---------------------------------------------------------------------- diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java index 7fec32d..624aa44 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java @@ -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, http://git-wip-us.apache.org/repos/asf/hbase/blob/ee1f26c4/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java ---------------------------------------------------------------------- diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java index 76bcd20..fef3a5e 100644 --- a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java +++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java @@ -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; + } + }); + } }