http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/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 new file mode 100644 index 0000000..0db0fea --- /dev/null +++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java @@ -0,0 +1,815 @@ +/** + * Copyright The Apache Software Foundation + * + * 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 com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.ClusterStatus; +import org.apache.hadoop.hbase.HBaseCluster; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.RegionLoad; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.Waiter; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.constraint.ConstraintException; +import org.apache.hadoop.hbase.net.Address; +import org.apache.hadoop.hbase.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.protobuf.generated.AdminProtos; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.IOException; +import java.security.SecureRandom; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +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; + +public abstract class TestRSGroupsBase { + protected static final Log LOG = LogFactory.getLog(TestRSGroupsBase.class); + + //shared + protected final static String groupPrefix = "Group"; + protected final static String tablePrefix = "Group"; + protected final static SecureRandom rand = new SecureRandom(); + + //shared, cluster type specific + protected static HBaseTestingUtility TEST_UTIL; + protected static HBaseAdmin admin; + protected static HBaseCluster cluster; + protected static RSGroupAdmin rsGroupAdmin; + + public final static long WAIT_TIMEOUT = 60000*5; + public final static int NUM_SLAVES_BASE = 4; //number of slaves for the smallest cluster + + + + protected RSGroupInfo addGroup(RSGroupAdmin gAdmin, String groupName, + int serverCount) throws IOException, InterruptedException { + RSGroupInfo defaultInfo = gAdmin + .getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP); + assertTrue(defaultInfo != null); + assertTrue(defaultInfo.getServers().size() >= serverCount); + gAdmin.addRSGroup(groupName); + + Set<Address> set = new HashSet<Address>(); + for(Address server: defaultInfo.getServers()) { + if(set.size() == serverCount) { + break; + } + set.add(server); + } + gAdmin.moveServers(set, groupName); + RSGroupInfo result = gAdmin.getRSGroupInfo(groupName); + assertTrue(result.getServers().size() >= serverCount); + return result; + } + + static void removeGroup(RSGroupAdminClient groupAdmin, String groupName) throws IOException { + RSGroupInfo info = groupAdmin.getRSGroupInfo(groupName); + groupAdmin.moveTables(info.getTables(), RSGroupInfo.DEFAULT_GROUP); + groupAdmin.moveServers(info.getServers(), RSGroupInfo.DEFAULT_GROUP); + groupAdmin.removeRSGroup(groupName); + } + + protected void deleteTableIfNecessary() throws IOException { + for (HTableDescriptor desc : TEST_UTIL.getHBaseAdmin().listTables(tablePrefix+".*")) { + TEST_UTIL.deleteTable(desc.getTableName()); + } + } + + protected void deleteNamespaceIfNecessary() throws IOException { + for (NamespaceDescriptor desc : TEST_UTIL.getHBaseAdmin().listNamespaceDescriptors()) { + if(desc.getName().startsWith(tablePrefix)) { + admin.deleteNamespace(desc.getName()); + } + } + } + + protected void deleteGroups() throws IOException { + RSGroupAdmin groupAdmin = new RSGroupAdminClient(TEST_UTIL.getConnection()); + for(RSGroupInfo group: groupAdmin.listRSGroups()) { + if(!group.getName().equals(RSGroupInfo.DEFAULT_GROUP)) { + groupAdmin.moveTables(group.getTables(), RSGroupInfo.DEFAULT_GROUP); + groupAdmin.moveServers(group.getServers(), RSGroupInfo.DEFAULT_GROUP); + groupAdmin.removeRSGroup(group.getName()); + } + } + } + + public Map<TableName, List<String>> getTableRegionMap() throws IOException { + Map<TableName, List<String>> map = Maps.newTreeMap(); + Map<TableName, Map<ServerName, List<String>>> tableServerRegionMap + = getTableServerRegionMap(); + for(TableName tableName : tableServerRegionMap.keySet()) { + if(!map.containsKey(tableName)) { + map.put(tableName, new LinkedList<String>()); + } + for(List<String> subset: tableServerRegionMap.get(tableName).values()) { + map.get(tableName).addAll(subset); + } + } + return map; + } + + public Map<TableName, Map<ServerName, List<String>>> getTableServerRegionMap() + throws IOException { + Map<TableName, Map<ServerName, List<String>>> map = Maps.newTreeMap(); + ClusterStatus status = TEST_UTIL.getHBaseClusterInterface().getClusterStatus(); + for(ServerName serverName : status.getServers()) { + for(RegionLoad rl : status.getLoad(serverName).getRegionsLoad().values()) { + TableName tableName = null; + try { + tableName = HRegionInfo.getTable(rl.getName()); + } catch (IllegalArgumentException e) { + LOG.warn("Failed parse a table name from regionname=" + + Bytes.toStringBinary(rl.getName())); + continue; + } + if(!map.containsKey(tableName)) { + map.put(tableName, new TreeMap<ServerName, List<String>>()); + } + if(!map.get(tableName).containsKey(serverName)) { + map.get(tableName).put(serverName, new LinkedList<String>()); + } + map.get(tableName).get(serverName).add(rl.getNameAsString()); + } + } + return map; + } + + @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 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 { + rsGroupAdmin.balanceRSGroup("bogus"); + fail("Expected move with bogus group to fail"); + } catch(ConstraintException ex) { + //expected + } + } + + @Test + public void testCreateMultiRegion() throws IOException { + LOG.info("testCreateMultiRegion"); + TableName tableName = TableName.valueOf(tablePrefix + "_testCreateMultiRegion"); + 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 testCreateAndDrop() throws Exception { + LOG.info("testCreateAndDrop"); + + final TableName tableName = TableName.valueOf(tablePrefix + "_testCreateAndDrop"); + 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 testSimpleRegionServerMove() throws IOException, + InterruptedException { + LOG.info("testSimpleRegionServerMove"); + + int initNumGroups = rsGroupAdmin.listRSGroups().size(); + RSGroupInfo appInfo = addGroup(rsGroupAdmin, getGroupName("testSimpleRegionServerMove"), 1); + RSGroupInfo adminInfo = addGroup(rsGroupAdmin, getGroupName("testSimpleRegionServerMove"), 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); + } + + // return the real number of region servers, excluding the master embedded region server in 2.0+ + public int getNumServers() throws IOException { + ClusterStatus status = admin.getClusterStatus(); + ServerName master = status.getMaster(); + int count = 0; + for (ServerName sn : status.getServers()) { + if (!sn.equals(master)) { + count++; + } + } + return count; + } + + @Test + public void testMoveServers() throws Exception { + LOG.info("testMoveServers"); + + //create groups and assign servers + addGroup(rsGroupAdmin, "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 = "Server foo:9999 does not have a group."; + 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 testTableMoveTruncateAndDrop() throws Exception { + LOG.info("testTableMove"); + + final TableName tableName = TableName.valueOf(tablePrefix + "_testTableMoveAndDrop"); + final byte[] familyNameBytes = Bytes.toBytes("f"); + String newGroupName = getGroupName("testTableMove"); + final RSGroupInfo newGroup = addGroup(rsGroupAdmin, 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()); + } + + @Test + public void testGroupBalance() throws Exception { + LOG.info("testGroupBalance"); + String newGroupName = getGroupName("testGroupBalance"); + final RSGroupInfo newGroup = addGroup(rsGroupAdmin, newGroupName, 3); + + final TableName tableName = TableName.valueOf(tablePrefix+"_ns", "testGroupBalance"); + 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(HRegionInfo region: admin.getTableRegions(tableName)) { + if(!assignMap.get(first).contains(region)) { + 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 + rsGroupAdmin.balanceRSGroup(RSGroupInfo.DEFAULT_GROUP); + assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size()); + + 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; + } + }); + } + + @Test + public void testRegionMove() throws Exception { + LOG.info("testRegionMove"); + + final RSGroupInfo newGroup = addGroup(rsGroupAdmin, getGroupName("testRegionMove"), 1); + final TableName tableName = TableName.valueOf(tablePrefix + rand.nextInt()); + 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.getClusterStatus().getServers()) { + if(!newGroup.containsServer(server.getAddress())) { + targetServer = server; + break; + } + } + + final AdminProtos.AdminService.BlockingInterface targetRS = + 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.getHBaseAdmin().move(Bytes.toBytes(HRegionInfo.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.getClusterStatus().getRegionsInTransition().size() < 1; + } + }); + + //verify that targetServer didn't open it + assertFalse(ProtobufUtil.getOnlineRegions(targetRS).contains(targetRegion)); + } + + @Test + public void testFailRemoveGroup() throws IOException, InterruptedException { + LOG.info("testFailRemoveGroup"); + + int initNumGroups = rsGroupAdmin.listRSGroups().size(); + addGroup(rsGroupAdmin, "bar", 3); + TableName tableName = TableName.valueOf(tablePrefix+"_my_table"); + 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 testKillRS() throws Exception { + LOG.info("testKillRS"); + RSGroupInfo appInfo = addGroup(rsGroupAdmin, "appInfo", 1); + + final TableName tableName = TableName.valueOf(tablePrefix+"_ns", "_testKillRS"); + 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 = + admin.getConnection().getAdmin(targetServer); + HRegionInfo 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.getClusterStatus().getServers().contains(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.getClusterStatus().getRegionsInTransition().size() == 0; + } + }); + 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.getClusterStatus().getRegionsInTransition().size() == 0; + } + }); + + targetServer = ServerName.parseServerName( + newServers.iterator().next().toString()); + targetRS = + admin.getConnection().getAdmin(targetServer); + Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(targetRS).size()); + Assert.assertEquals(tableName, + ProtobufUtil.getOnlineRegions(targetRS).get(0).getTable()); + } + + @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); + } + } + + private String getGroupName(String baseName) { + return groupPrefix+"_"+baseName+"_"+rand.nextInt(Integer.MAX_VALUE); + } + + @Test + public void testMultiTableMove() throws Exception { + LOG.info("testMultiTableMove"); + + final TableName tableNameA = TableName.valueOf(tablePrefix + "_testMultiTableMoveA"); + final TableName tableNameB = TableName.valueOf(tablePrefix + "_testMultiTableMoveB"); + final byte[] familyNameBytes = Bytes.toBytes("f"); + String newGroupName = getGroupName("testMultiTableMove"); + final RSGroupInfo newGroup = addGroup(rsGroupAdmin, 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 testMoveServersAndTables() throws Exception { + final TableName tableName = TableName.valueOf(tablePrefix + "_testMoveServersAndTables"); + final RSGroupInfo newGroup = addGroup(rsGroupAdmin, getGroupName("testMoveServersAndTables"), 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.getClusterStatus().getServers()) { + 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) { + } + + //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) { + } + + //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 + admin.move(Bytes.toBytes(HRegionInfo.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.getClusterStatus().getRegionsInTransition().size() < 1; + } + }); + + //verify that all region move to targetServer + Assert.assertNotNull(getTableServerRegionMap().get(tableName)); + Assert.assertNotNull(getTableServerRegionMap().get(tableName).get(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)); + } +}
http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java ---------------------------------------------------------------------- diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java new file mode 100644 index 0000000..360f9ef --- /dev/null +++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java @@ -0,0 +1,187 @@ +/** + * Copyright The Apache Software Foundation + * + * 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 com.google.common.collect.Sets; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.HBaseCluster; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.Waiter; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; +import org.apache.hadoop.hbase.master.HMaster; +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; +import org.junit.Test; +import org.junit.experimental.categories.Category; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + + +//This tests that GroupBasedBalancer will use data in zk +//to do balancing during master startup +//This does not test retain assignment +@Category(MediumTests.class) +public class TestRSGroupsOfflineMode { + private static final org.apache.commons.logging.Log LOG = + LogFactory.getLog(TestRSGroupsOfflineMode.class); + private static HMaster master; + private static HBaseAdmin hbaseAdmin; + private static HBaseTestingUtility TEST_UTIL; + private static HBaseCluster cluster; + private static RSGroupAdminEndpoint RSGroupAdminEndpoint; + public final static long WAIT_TIMEOUT = 60000*5; + + @BeforeClass + public static void setUp() throws Exception { + TEST_UTIL = new HBaseTestingUtility(); + TEST_UTIL.getConfiguration().set( + HConstants.HBASE_MASTER_LOADBALANCER_CLASS, + RSGroupBasedLoadBalancer.class.getName()); + TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, + RSGroupAdminEndpoint.class.getName()); + TEST_UTIL.getConfiguration().set( + ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, + "1"); + TEST_UTIL.startMiniCluster(2, 3); + cluster = TEST_UTIL.getHBaseCluster(); + master = ((MiniHBaseCluster)cluster).getMaster(); + master.balanceSwitch(false); + hbaseAdmin = TEST_UTIL.getHBaseAdmin(); + //wait till the balancer is in online mode + TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { + @Override + public boolean evaluate() throws Exception { + return master.isInitialized() && + ((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline() && + master.getServerManager().getOnlineServersList().size() >= 3; + } + }); + RSGroupAdminEndpoint = + master.getMasterCoprocessorHost().findCoprocessors(RSGroupAdminEndpoint.class).get(0); + } + + @AfterClass + public static void tearDown() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test + public void testOffline() throws Exception, InterruptedException { + //table should be after group table name + //so it gets assigned later + final TableName failoverTable = TableName.valueOf("testOffline"); + TEST_UTIL.createTable(failoverTable, Bytes.toBytes("f")); + + RSGroupAdmin groupAdmin = new RSGroupAdminClient(TEST_UTIL.getConnection()); + + final HRegionServer killRS = ((MiniHBaseCluster)cluster).getRegionServer(0); + final HRegionServer groupRS = ((MiniHBaseCluster)cluster).getRegionServer(1); + final HRegionServer failoverRS = ((MiniHBaseCluster)cluster).getRegionServer(2); + + String newGroup = "my_group"; + groupAdmin.addRSGroup(newGroup); + if(master.getAssignmentManager().getRegionStates().getRegionAssignments() + .containsValue(failoverRS.getServerName())) { + for(HRegionInfo regionInfo: hbaseAdmin.getOnlineRegions(failoverRS.getServerName())) { + hbaseAdmin.move(regionInfo.getEncodedNameAsBytes(), + Bytes.toBytes(failoverRS.getServerName().getServerName())); + } + LOG.info("Waiting for region unassignments on failover RS..."); + TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { + @Override + public boolean evaluate() throws Exception { + return master.getServerManager().getLoad(failoverRS.getServerName()) + .getRegionsLoad().size() > 0; + } + }); + } + + //move server to group and make sure all tables are assigned + groupAdmin.moveServers(Sets.newHashSet(groupRS.getServerName().getAddress()), newGroup); + TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { + @Override + public boolean evaluate() throws Exception { + return groupRS.getNumberOfOnlineRegions() < 1 && + master.getAssignmentManager().getRegionStates().getRegionsInTransition().size() < 1; + } + }); + //move table to group and wait + groupAdmin.moveTables(Sets.newHashSet(RSGroupInfoManager.RSGROUP_TABLE_NAME), newGroup); + LOG.info("Waiting for move table..."); + TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { + @Override + public boolean evaluate() throws Exception { + return groupRS.getNumberOfOnlineRegions() == 1; + } + }); + + groupRS.stop("die"); + //race condition here + TEST_UTIL.getHBaseCluster().getMaster().stopMaster(); + LOG.info("Waiting for offline mode..."); + TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { + @Override + public boolean evaluate() throws Exception { + return TEST_UTIL.getHBaseCluster().getMaster() != null && + TEST_UTIL.getHBaseCluster().getMaster().isActiveMaster() && + TEST_UTIL.getHBaseCluster().getMaster().isInitialized() && + TEST_UTIL.getHBaseCluster().getMaster().getServerManager().getOnlineServers().size() + <= 3; + } + }); + + + RSGroupInfoManager groupMgr = RSGroupAdminEndpoint.getGroupInfoManager(); + //make sure balancer is in offline mode, since this is what we're testing + assertFalse(groupMgr.isOnline()); + //verify the group affiliation that's loaded from ZK instead of tables + assertEquals(newGroup, + groupMgr.getRSGroupOfTable(RSGroupInfoManager.RSGROUP_TABLE_NAME)); + assertEquals(RSGroupInfo.DEFAULT_GROUP, groupMgr.getRSGroupOfTable(failoverTable)); + + //kill final regionserver to see the failover happens for all tables + //except GROUP table since it's group does not have any online RS + killRS.stop("die"); + master = TEST_UTIL.getHBaseCluster().getMaster(); + LOG.info("Waiting for new table assignment..."); + TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { + @Override + public boolean evaluate() throws Exception { + return failoverRS.getOnlineRegions(failoverTable).size() >= 1; + } + }); + Assert.assertEquals(0, failoverRS.getOnlineRegions(RSGroupInfoManager.RSGROUP_TABLE_NAME).size()); + + //need this for minicluster to shutdown cleanly + master.stopMaster(); + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java ---------------------------------------------------------------------- diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java new file mode 100644 index 0000000..f5d02f0 --- /dev/null +++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java @@ -0,0 +1,155 @@ +/** + * Copyright The Apache Software Foundation + * + * 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 com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.exceptions.DeserializationException; +import org.apache.hadoop.hbase.net.Address; +import org.apache.hadoop.hbase.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.protobuf.generated.RSGroupProtos; +import org.apache.hadoop.hbase.zookeeper.ZKUtil; +import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; +import org.apache.zookeeper.KeeperException; +import org.junit.Assert; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class VerifyingRSGroupAdminClient implements RSGroupAdmin { + private Table table; + private ZooKeeperWatcher zkw; + private RSGroupAdmin wrapped; + + public VerifyingRSGroupAdminClient(RSGroupAdmin RSGroupAdmin, Configuration conf) + throws IOException { + wrapped = RSGroupAdmin; + table = ConnectionFactory.createConnection(conf).getTable(RSGroupInfoManager.RSGROUP_TABLE_NAME); + zkw = new ZooKeeperWatcher(conf, this.getClass().getSimpleName(), null); + } + + @Override + public void addRSGroup(String groupName) throws IOException { + wrapped.addRSGroup(groupName); + verify(); + } + + @Override + public RSGroupInfo getRSGroupInfo(String groupName) throws IOException { + return wrapped.getRSGroupInfo(groupName); + } + + @Override + public RSGroupInfo getRSGroupInfoOfTable(TableName tableName) throws IOException { + return wrapped.getRSGroupInfoOfTable(tableName); + } + + @Override + public void moveServers(Set<Address> servers, String targetGroup) throws IOException { + wrapped.moveServers(servers, targetGroup); + verify(); + } + + @Override + public void moveTables(Set<TableName> tables, String targetGroup) throws IOException { + wrapped.moveTables(tables, targetGroup); + verify(); + } + + @Override + public void removeRSGroup(String name) throws IOException { + wrapped.removeRSGroup(name); + verify(); + } + + @Override + public boolean balanceRSGroup(String name) throws IOException { + return wrapped.balanceRSGroup(name); + } + + @Override + public List<RSGroupInfo> listRSGroups() throws IOException { + return wrapped.listRSGroups(); + } + + @Override + public RSGroupInfo getRSGroupOfServer(Address server) throws IOException { + return wrapped.getRSGroupOfServer(server); + } + + public void verify() throws IOException { + Map<String, RSGroupInfo> groupMap = Maps.newHashMap(); + Set<RSGroupInfo> zList = Sets.newHashSet(); + + for (Result result : table.getScanner(new Scan())) { + RSGroupProtos.RSGroupInfo proto = + RSGroupProtos.RSGroupInfo.parseFrom( + result.getValue( + RSGroupInfoManager.META_FAMILY_BYTES, + RSGroupInfoManager.META_QUALIFIER_BYTES)); + groupMap.put(proto.getName(), RSGroupProtobufUtil.toGroupInfo(proto)); + } + Assert.assertEquals(Sets.newHashSet(groupMap.values()), + Sets.newHashSet(wrapped.listRSGroups())); + try { + String groupBasePath = ZKUtil.joinZNode(zkw.baseZNode, "rsgroup"); + for(String znode: ZKUtil.listChildrenNoWatch(zkw, groupBasePath)) { + byte[] data = ZKUtil.getData(zkw, ZKUtil.joinZNode(groupBasePath, znode)); + if(data.length > 0) { + ProtobufUtil.expectPBMagicPrefix(data); + ByteArrayInputStream bis = new ByteArrayInputStream( + data, ProtobufUtil.lengthOfPBMagic(), data.length); + zList.add(RSGroupProtobufUtil.toGroupInfo(RSGroupProtos.RSGroupInfo.parseFrom(bis))); + } + } + Assert.assertEquals(zList.size(), groupMap.size()); + for(RSGroupInfo RSGroupInfo : zList) { + Assert.assertTrue(groupMap.get(RSGroupInfo.getName()).equals(RSGroupInfo)); + } + } catch (KeeperException e) { + throw new IOException("ZK verification failed", e); + } catch (DeserializationException e) { + throw new IOException("ZK verification failed", e); + } catch (InterruptedException e) { + throw new IOException("ZK verification failed", e); + } + } + + @Override + public void moveServersAndTables(Set<Address> servers, Set<TableName> tables, + String targetGroup) throws IOException { + wrapped.moveServersAndTables(servers, tables, targetGroup); + verify(); + } + + @Override + public void close() throws IOException { + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon index 0ecc131..7467baa 100644 --- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon +++ b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon @@ -395,6 +395,8 @@ AssignmentManager assignmentManager = master.getAssignmentManager(); } else if (tableName.equals(QuotaUtil.QUOTA_TABLE_NAME)){ description = "The hbase:quota table holds quota information about number" + " or size of requests in a given time frame."; + } else if (tableName.equals(TableName.valueOf("hbase:rsgroup"))){ + description = "The hbase:rsgroup table holds information about regionserver groups"; } </%java> <td><% description %></td> http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/LocalHBaseCluster.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/LocalHBaseCluster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/LocalHBaseCluster.java index 42484e7..9f8b3c1 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/LocalHBaseCluster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/LocalHBaseCluster.java @@ -147,6 +147,9 @@ public class LocalHBaseCluster { if (conf.getInt(HConstants.REGIONSERVER_INFO_PORT, 0) != -1) { conf.set(HConstants.REGIONSERVER_INFO_PORT, "0"); } + if (conf.getInt(HConstants.MASTER_INFO_PORT, 0) != -1) { + conf.set(HConstants.MASTER_INFO_PORT, "0"); + } this.masterClass = (Class<? extends HMaster>) conf.getClass(HConstants.MASTER_IMPL, masterClass); http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java index eab9f97..9ad8453 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java @@ -33,12 +33,14 @@ import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.master.RegionPlan; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; +import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription; import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas; import java.io.IOException; import java.util.List; +import java.util.Set; @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC) @InterfaceStability.Evolving @@ -601,4 +603,64 @@ public class BaseMasterAndRegionObserver extends BaseRegionObserver public void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx, final String namespace, final Quotas quotas) throws IOException { } + + @Override + public void postAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void postBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, + String groupName, boolean balancerRan) throws IOException { + } + + @Override + public void postMoveServers(ObserverContext<MasterCoprocessorEnvironment> ctx, Set<Address> + servers, String targetGroup) throws IOException { + } + + @Override + public void postMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx, Set<TableName> + tables, String targetGroup) throws IOException { + } + + @Override + public void preMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void postMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void postRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void preAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void preBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String groupName) + throws IOException { + } + + @Override + public void preMoveServers(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, String targetGroup) throws IOException { + } + + @Override + public void preMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void preRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } } http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java index 373e5d5..ca2bd53 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java @@ -33,12 +33,14 @@ import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.master.RegionPlan; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; +import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription; import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas; import java.io.IOException; import java.util.List; +import java.util.Set; @InterfaceAudience.LimitedPrivate({HBaseInterfaceAudience.COPROC, HBaseInterfaceAudience.CONFIG}) @InterfaceStability.Evolving @@ -600,4 +602,65 @@ public class BaseMasterObserver implements MasterObserver { public void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx, final String namespace, final Quotas quotas) throws IOException { } + + @Override + public void preMoveServers(ObserverContext<MasterCoprocessorEnvironment> ctx, Set<Address> + servers, String targetGroup) throws IOException { + } + + @Override + public void postMoveServers(ObserverContext<MasterCoprocessorEnvironment> ctx, Set<Address> + servers, String targetGroup) throws IOException { + } + + @Override + public void preMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx, Set<TableName> + tables, String targetGroup) throws IOException { + } + + @Override + public void postMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void preMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void postMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void preAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void postAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void preRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + + } + + @Override + public void postRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void preBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String groupName) + throws IOException { + } + + @Override + public void postBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, + String groupName, boolean balancerRan) throws IOException { + } } http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java index 4ec02f4..03d5123 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java @@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.coprocessor; import java.io.IOException; import java.util.List; +import java.util.Set; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceStability; @@ -36,6 +37,7 @@ import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.master.RegionPlan; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; +import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription; import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas; @@ -1065,4 +1067,115 @@ public interface MasterObserver extends Coprocessor { */ void postClearDeadServers(ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException; + /** + * Called before servers are moved to target region server group + * @param ctx the environment to interact with the framework and master + * @param servers set of servers to move + * @param targetGroup destination group + */ + void preMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, String targetGroup) throws IOException; + + /** + * Called after servers are moved to target region server group + * @param ctx the environment to interact with the framework and master + * @param servers set of servers to move + * @param targetGroup name of group + * @throws IOException on failure + */ + void postMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, String targetGroup) throws IOException; + + /** + * Called before tables are moved to target region server group + * @param ctx the environment to interact with the framework and master + * @param tables set of tables to move + * @param targetGroup name of group + * @throws IOException on failure + */ + void preMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<TableName> tables, String targetGroup) throws IOException; + + /** + * Called after servers are moved to target region server group + * @param ctx the environment to interact with the framework and master + * @param tables set of tables to move + * @param targetGroup name of group + * @throws IOException on failure + */ + void postMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<TableName> tables, String targetGroup) throws IOException; + + /** + * Called before servers are moved to target region server group + * @param ctx the environment to interact with the framework and master + * @param servers set of servers to move + * @param targetGroup destination group + * @throws IOException on failure + */ + void preMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException; + + /** + * Called after servers are moved to target region server group + * @param ctx the environment to interact with the framework and master + * @param servers set of servers to move + * @param targetGroup name of group + */ + void postMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException; + + /** + * Called before a new region server group is added + * @param ctx the environment to interact with the framework and master + * @param name group name + * @throws IOException on failure + */ + void preAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx, + String name) throws IOException; + + /** + * Called after a new region server group is added + * @param ctx the environment to interact with the framework and master + * @param name group name + * @throws IOException on failure + */ + void postAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx, + String name) throws IOException; + + /** + * Called before a region server group is removed + * @param ctx the environment to interact with the framework and master + * @param name group name + * @throws IOException on failure + */ + void preRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx, + String name) throws IOException; + + /** + * Called after a region server group is removed + * @param ctx the environment to interact with the framework and master + * @param name group name + * @throws IOException on failure + */ + void postRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx, + String name) throws IOException; + + /** + * Called before a region server group is removed + * @param ctx the environment to interact with the framework and master + * @param groupName group name + * @throws IOException on failure + */ + void preBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx, + String groupName) throws IOException; + + /** + * Called after a region server group is removed + * @param ctx the environment to interact with the framework and master + * @param groupName group name + * @throws IOException on failure + */ + void postBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx, + String groupName, boolean balancerRan) throws IOException; } http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java index 7c145dd..809b980 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java @@ -2226,7 +2226,7 @@ public class AssignmentManager extends ZooKeeperListener { } } LOG.info("Assigning " + region.getRegionNameAsString() + - " to " + plan.getDestination().toString()); + " to " + plan.getDestination()); // Transition RegionState to PENDING_OPEN currentState = regionStates.updateRegionState(region, State.PENDING_OPEN, plan.getDestination()); @@ -2954,6 +2954,8 @@ public class AssignmentManager extends ZooKeeperListener { throw new IOException("Unable to determine a plan to assign region(s)"); } + processBogusAssignments(bulkPlan); + assign(regions.size(), servers.size(), "retainAssignment=true", bulkPlan); } @@ -2983,6 +2985,8 @@ public class AssignmentManager extends ZooKeeperListener { throw new IOException("Unable to determine a plan to assign region(s)"); } + processBogusAssignments(bulkPlan); + processFavoredNodes(regions); assign(regions.size(), servers.size(), "round-robin=true", bulkPlan); } @@ -4665,6 +4669,16 @@ public class AssignmentManager extends ZooKeeperListener { return errorMsg; } + private void processBogusAssignments(Map<ServerName, List<HRegionInfo>> bulkPlan) { + if (bulkPlan.containsKey(LoadBalancer.BOGUS_SERVER_NAME)) { + // Found no plan for some regions, put those regions in RIT + for (HRegionInfo hri : bulkPlan.get(LoadBalancer.BOGUS_SERVER_NAME)) { + regionStates.updateRegionState(hri, State.FAILED_OPEN); + } + bulkPlan.remove(LoadBalancer.BOGUS_SERVER_NAME); + } + } + /** * @return Instance of load balancer */ http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 8a3bbd6..9b41bbf 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -3217,4 +3217,9 @@ public class HMaster extends HRegionServer implements MasterServices, Server { public SplitOrMergeTracker getSplitOrMergeTracker() { return splitOrMergeTracker; } + + @Override + public LoadBalancer getLoadBalancer() { + return balancer; + } } http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java index c581b08..937b32f 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java @@ -52,6 +52,9 @@ import org.apache.hadoop.hbase.TableName; @InterfaceAudience.Private public interface LoadBalancer extends Configurable, Stoppable, ConfigurationObserver { + //used to signal to the caller that the region(s) cannot be assigned + ServerName BOGUS_SERVER_NAME = ServerName.parseServerName("localhost,1,1"); + /** * Set the current cluster status. This allows a LoadBalancer to map host name to a server * @param st http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index 9edc60e..78c7925 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.master; import java.io.IOException; import java.util.List; +import java.util.Set; import org.apache.commons.lang.ClassUtils; import org.apache.commons.logging.Log; @@ -44,6 +45,7 @@ import org.apache.hadoop.hbase.coprocessor.MetricsCoprocessor; import org.apache.hadoop.hbase.coprocessor.ObserverContext; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; import org.apache.hadoop.hbase.metrics.MetricRegistry; +import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription; import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas; @@ -67,6 +69,7 @@ public class MasterCoprocessorHost implements MasterCoprocessorEnvironment { private final MasterServices masterServices; private final MetricRegistry metricRegistry; + private final boolean supportGroupCPs; public MasterEnvironment(final Class<?> implClass, final Coprocessor impl, final int priority, final int seq, final Configuration conf, @@ -75,6 +78,8 @@ public class MasterCoprocessorHost this.masterServices = services; this.metricRegistry = MetricsCoprocessor.createRegistryForMasterCoprocessor(implClass.getName()); + supportGroupCPs = !useLegacyMethod(impl.getClass(), + "preBalanceRSGroup", ObserverContext.class, String.class); } @Override @@ -1212,6 +1217,161 @@ public class MasterCoprocessorHost }); } + public void preMoveServers(final Set<Address> servers, final String targetGroup) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preMoveServers(ctx, servers, targetGroup); + } + } + }); + } + + public void postMoveServers(final Set<Address> servers, final String targetGroup) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postMoveServers(ctx, servers, targetGroup); + } + } + }); + } + + public void preMoveTables(final Set<TableName> tables, final String targetGroup) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preMoveTables(ctx, tables, targetGroup); + } + } + }); + } + + public void postMoveTables(final Set<TableName> tables, final String targetGroup) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postMoveTables(ctx, tables, targetGroup); + } + } + }); + } + + public void preMoveServersAndTables(final Set<Address> servers, final Set<TableName> tables, + final String targetGroup) throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preMoveServersAndTables(ctx, servers, tables, targetGroup); + } + } + }); + } + + public void postMoveServersAndTables(final Set<Address> servers, final Set<TableName> tables, + final String targetGroup) throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postMoveServersAndTables(ctx, servers, tables, targetGroup); + } + } + }); + } + + public void preAddRSGroup(final String name) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preAddRSGroup(ctx, name); + } + } + }); + } + + public void postAddRSGroup(final String name) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if (((MasterEnvironment) ctx.getEnvironment()).supportGroupCPs) { + oserver.postAddRSGroup(ctx, name); + } + } + }); + } + + public void preRemoveRSGroup(final String name) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preRemoveRSGroup(ctx, name); + } + } + }); + } + + public void postRemoveRSGroup(final String name) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postRemoveRSGroup(ctx, name); + } + } + }); + } + + public void preBalanceRSGroup(final String name) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preBalanceRSGroup(ctx, name); + } + } + }); + } + + public void postBalanceRSGroup(final String name, final boolean balanceRan) + throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, + ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postBalanceRSGroup(ctx, name, balanceRan); + } + } + }); + } private static abstract class CoprocessorOperation extends ObserverContext<MasterCoprocessorEnvironment> { http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java index 0403316..7d58070 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java @@ -411,4 +411,9 @@ public interface MasterServices extends Server { public String getRegionServerVersion(final ServerName sn); public void checkIfShouldMoveSystemRegionAsync(); + + /** + * @return load balancer + */ + public LoadBalancer getLoadBalancer(); } http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java index e727753..550b98e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java @@ -85,6 +85,7 @@ import org.apache.hadoop.hbase.io.hfile.HFile; import org.apache.hadoop.hbase.ipc.RpcServer; import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; +import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.ResponseConverter; @@ -2705,4 +2706,40 @@ public class AccessController extends BaseMasterAndRegionObserver final String namespace, final Quotas quotas) throws IOException { requirePermission("setNamespaceQuota", Action.ADMIN); } + + @Override + public void preMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException { + requirePermission("moveServersAndTables", Action.ADMIN); + } + + @Override + public void preMoveServers(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, String targetGroup) throws IOException { + requirePermission("moveServers", Action.ADMIN); + } + + @Override + public void preMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<TableName> tables, String targetGroup) throws IOException { + requirePermission("moveTables", Action.ADMIN); + } + + @Override + public void preAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, + String name) throws IOException { + requirePermission("addRSGroup", Action.ADMIN); + } + + @Override + public void preRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, + String name) throws IOException { + requirePermission("removeRSGroup", Action.ADMIN); + } + + @Override + public void preBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, + String groupName) throws IOException { + requirePermission("balanceRSGroup", Action.ADMIN); + } } http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java index 452b2a2..b20d7bc 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java @@ -56,6 +56,7 @@ import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.master.MasterCoprocessorHost; import org.apache.hadoop.hbase.master.RegionPlan; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; +import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.RequestConverter; @@ -1278,6 +1279,66 @@ public class TestMasterObserver { public void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx, final String namespace, final Quotas quotas) throws IOException { } + + @Override + public void preMoveServers(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, String targetGroup) throws IOException { + } + + @Override + public void postMoveServers(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, String targetGroup) throws IOException { + } + + @Override + public void preMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void postMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void preMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void postMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx, + Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException { + } + + @Override + public void preAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void postAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void preRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void postRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, String name) + throws IOException { + } + + @Override + public void preBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, + String groupName) throws IOException { + } + + @Override + public void postBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx, + String groupName, boolean balancerRan) throws IOException { + } } private static HBaseTestingUtility UTIL = new HBaseTestingUtility(); http://git-wip-us.apache.org/repos/asf/hbase/blob/c3200076/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java index f955ac0..1b12cf0 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java @@ -302,4 +302,9 @@ public class MockNoopMasterServices implements MasterServices, Server { public boolean isStopped() { return false; } + + @Override + public LoadBalancer getLoadBalancer() { + return null; + } } \ No newline at end of file