001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.rsgroup; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.util.List; 025import java.util.Map; 026import org.apache.hadoop.hbase.HBaseClassTestRule; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.hadoop.hbase.NamespaceDescriptor; 029import org.apache.hadoop.hbase.ServerName; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.Waiter; 032import org.apache.hadoop.hbase.Waiter.Predicate; 033import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 034import org.apache.hadoop.hbase.client.RegionInfo; 035import org.apache.hadoop.hbase.client.TableDescriptor; 036import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 037import org.apache.hadoop.hbase.master.HMaster; 038import org.apache.hadoop.hbase.testclassification.MediumTests; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.junit.After; 041import org.junit.AfterClass; 042import org.junit.Before; 043import org.junit.BeforeClass; 044import org.junit.ClassRule; 045import org.junit.Test; 046import org.junit.experimental.categories.Category; 047import org.slf4j.Logger; 048import org.slf4j.LoggerFactory; 049 050import org.apache.hbase.thirdparty.com.google.common.collect.Sets; 051 052@Category({ MediumTests.class }) 053public class TestRSGroupsBalance extends TestRSGroupsBase { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestRSGroupsBalance.class); 058 059 protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsBalance.class); 060 061 @BeforeClass 062 public static void setUp() throws Exception { 063 setUpTestBeforeClass(); 064 } 065 066 @AfterClass 067 public static void tearDown() throws Exception { 068 tearDownAfterClass(); 069 } 070 071 @Before 072 public void beforeMethod() throws Exception { 073 setUpBeforeMethod(); 074 } 075 076 @After 077 public void afterMethod() throws Exception { 078 tearDownAfterMethod(); 079 } 080 081 @Test 082 public void testGroupBalance() throws Exception { 083 LOG.info(name.getMethodName()); 084 String newGroupName = getGroupName(name.getMethodName()); 085 addGroup(newGroupName, 3); 086 087 final TableName tableName = TableName.valueOf(tablePrefix + "_ns", name.getMethodName()); 088 admin.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString()) 089 .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, newGroupName).build()); 090 final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName) 091 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f")).build(); 092 byte[] startKey = Bytes.toBytes("aaaaa"); 093 byte[] endKey = Bytes.toBytes("zzzzz"); 094 admin.createTable(desc, startKey, endKey, 6); 095 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { 096 @Override 097 public boolean evaluate() throws Exception { 098 List<String> regions = getTableRegionMap().get(tableName); 099 if (regions == null) { 100 return false; 101 } 102 return regions.size() >= 6; 103 } 104 }); 105 106 // make assignment uneven, move all regions to one server 107 Map<ServerName, List<String>> assignMap = getTableServerRegionMap().get(tableName); 108 final ServerName first = assignMap.entrySet().iterator().next().getKey(); 109 for (RegionInfo region : admin.getRegions(tableName)) { 110 if (!assignMap.get(first).contains(region.getRegionNameAsString())) { 111 admin.move(region.getEncodedNameAsBytes(), first); 112 } 113 } 114 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { 115 @Override 116 public boolean evaluate() throws Exception { 117 Map<ServerName, List<String>> map = getTableServerRegionMap().get(tableName); 118 if (map == null) { 119 return true; 120 } 121 List<String> regions = map.get(first); 122 if (regions == null) { 123 return true; 124 } 125 return regions.size() >= 6; 126 } 127 }); 128 129 // balance the other group and make sure it doesn't affect the new group 130 admin.balancerSwitch(true, true); 131 rsGroupAdmin.balanceRSGroup(RSGroupInfo.DEFAULT_GROUP); 132 assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size()); 133 134 // disable balance, balancer will not be run and return false 135 admin.balancerSwitch(false, true); 136 assertFalse(rsGroupAdmin.balanceRSGroup(newGroupName)); 137 assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size()); 138 139 // enable balance 140 admin.balancerSwitch(true, true); 141 rsGroupAdmin.balanceRSGroup(newGroupName); 142 TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { 143 @Override 144 public boolean evaluate() throws Exception { 145 for (List<String> regions : getTableServerRegionMap().get(tableName).values()) { 146 if (2 != regions.size()) { 147 return false; 148 } 149 } 150 return true; 151 } 152 }); 153 admin.balancerSwitch(false, true); 154 } 155 156 @Test 157 public void testMisplacedRegions() throws Exception { 158 final TableName tableName = TableName.valueOf(tablePrefix + "_testMisplacedRegions"); 159 LOG.info("testMisplacedRegions"); 160 161 final RSGroupInfo RSGroupInfo = addGroup("testMisplacedRegions", 1); 162 163 TEST_UTIL.createMultiRegionTable(tableName, new byte[] { 'f' }, 15); 164 TEST_UTIL.waitUntilAllRegionsAssigned(tableName); 165 166 rsGroupAdminEndpoint.getGroupInfoManager().moveTables(Sets.newHashSet(tableName), 167 RSGroupInfo.getName()); 168 169 admin.balancerSwitch(true, true); 170 assertTrue(rsGroupAdmin.balanceRSGroup(RSGroupInfo.getName())); 171 admin.balancerSwitch(false, true); 172 assertTrue(observer.preBalanceRSGroupCalled); 173 assertTrue(observer.postBalanceRSGroupCalled); 174 175 TEST_UTIL.waitFor(60000, new Predicate<Exception>() { 176 @Override 177 public boolean evaluate() throws Exception { 178 ServerName serverName = 179 ServerName.valueOf(RSGroupInfo.getServers().iterator().next().toString(), 1); 180 return admin.getConnection().getAdmin().getRegions(serverName).size() == 15; 181 } 182 }); 183 } 184 185 @Test 186 public void testGetRSGroupAssignmentsByTable() throws Exception { 187 final TableName tableName = TableName.valueOf(name.getMethodName()); 188 TEST_UTIL.createMultiRegionTable(tableName, HConstants.CATALOG_FAMILY, 10); 189 // disable table 190 final TableName disableTableName = TableName.valueOf("testDisableTable"); 191 TEST_UTIL.createMultiRegionTable(disableTableName, HConstants.CATALOG_FAMILY, 10); 192 TEST_UTIL.getAdmin().disableTable(disableTableName); 193 194 HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster(); 195 Map<TableName, Map<ServerName, List<RegionInfo>>> assignments = 196 rsGroupAdminEndpoint.getGroupAdminServer() 197 .getRSGroupAssignmentsByTable(master.getTableStateManager(), RSGroupInfo.DEFAULT_GROUP); 198 assertFalse(assignments.containsKey(disableTableName)); 199 assertTrue(assignments.containsKey(tableName)); 200 } 201}