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.master.balancer; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.io.FileNotFoundException; 025import java.io.IOException; 026import java.security.SecureRandom; 027import java.util.ArrayList; 028import java.util.Collections; 029import java.util.HashMap; 030import java.util.HashSet; 031import java.util.Iterator; 032import java.util.List; 033import java.util.Map; 034import java.util.Set; 035import java.util.TreeMap; 036import java.util.TreeSet; 037import org.apache.commons.lang3.StringUtils; 038import org.apache.hadoop.conf.Configuration; 039import org.apache.hadoop.hbase.HBaseClassTestRule; 040import org.apache.hadoop.hbase.HBaseConfiguration; 041import org.apache.hadoop.hbase.HTableDescriptor; 042import org.apache.hadoop.hbase.ServerName; 043import org.apache.hadoop.hbase.TableDescriptors; 044import org.apache.hadoop.hbase.TableName; 045import org.apache.hadoop.hbase.client.RegionInfo; 046import org.apache.hadoop.hbase.client.RegionInfoBuilder; 047import org.apache.hadoop.hbase.master.HMaster; 048import org.apache.hadoop.hbase.master.LoadBalancer; 049import org.apache.hadoop.hbase.master.MasterServices; 050import org.apache.hadoop.hbase.master.RegionPlan; 051import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 052import org.apache.hadoop.hbase.master.assignment.RegionStates; 053import org.apache.hadoop.hbase.net.Address; 054import org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer; 055import org.apache.hadoop.hbase.rsgroup.RSGroupInfo; 056import org.apache.hadoop.hbase.rsgroup.RSGroupInfoManager; 057import org.apache.hadoop.hbase.testclassification.SmallTests; 058import org.apache.hadoop.hbase.util.Bytes; 059import org.junit.BeforeClass; 060import org.junit.ClassRule; 061import org.junit.Test; 062import org.junit.experimental.categories.Category; 063import org.mockito.Mockito; 064import org.mockito.invocation.InvocationOnMock; 065import org.mockito.stubbing.Answer; 066import org.slf4j.Logger; 067import org.slf4j.LoggerFactory; 068 069import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap; 070import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 071 072//TODO use stochastic based load balancer instead 073@Category(SmallTests.class) 074public class TestRSGroupBasedLoadBalancer { 075 076 @ClassRule 077 public static final HBaseClassTestRule CLASS_RULE = 078 HBaseClassTestRule.forClass(TestRSGroupBasedLoadBalancer.class); 079 080 private static final Logger LOG = LoggerFactory.getLogger(TestRSGroupBasedLoadBalancer.class); 081 private static RSGroupBasedLoadBalancer loadBalancer; 082 private static SecureRandom rand; 083 084 static String[] groups = new String[] { RSGroupInfo.DEFAULT_GROUP, "dg2", "dg3", "dg4" }; 085 static TableName table0 = TableName.valueOf("dt0"); 086 static TableName[] tables = 087 new TableName[] { TableName.valueOf("dt1"), 088 TableName.valueOf("dt2"), 089 TableName.valueOf("dt3"), 090 TableName.valueOf("dt4")}; 091 static List<ServerName> servers; 092 static Map<String, RSGroupInfo> groupMap; 093 static Map<TableName, String> tableMap; 094 static List<HTableDescriptor> tableDescs; 095 int[] regionAssignment = new int[] { 2, 5, 7, 10, 4, 3, 1 }; 096 static int regionId = 0; 097 098 @BeforeClass 099 public static void beforeAllTests() throws Exception { 100 rand = new SecureRandom(); 101 servers = generateServers(7); 102 groupMap = constructGroupInfo(servers, groups); 103 tableMap = new HashMap<>(); 104 tableDescs = constructTableDesc(); 105 Configuration conf = HBaseConfiguration.create(); 106 conf.set("hbase.regions.slop", "0"); 107 conf.set("hbase.rsgroup.grouploadbalancer.class", SimpleLoadBalancer.class.getCanonicalName()); 108 loadBalancer = new RSGroupBasedLoadBalancer(); 109 loadBalancer.setRsGroupInfoManager(getMockedGroupInfoManager()); 110 loadBalancer.setMasterServices(getMockedMaster()); 111 loadBalancer.setConf(conf); 112 loadBalancer.initialize(); 113 } 114 115 /** 116 * Test the load balancing algorithm. 117 * 118 * Invariant is that all servers of the group should be hosting either floor(average) or 119 * ceiling(average) 120 */ 121 @Test 122 public void testBalanceCluster() throws Exception { 123 Map<ServerName, List<RegionInfo>> servers = mockClusterServers(); 124 ArrayListMultimap<String, ServerAndLoad> list = convertToGroupBasedMap(servers); 125 LOG.info("Mock Cluster : " + printStats(list)); 126 List<RegionPlan> plans = loadBalancer.balanceCluster(servers); 127 ArrayListMultimap<String, ServerAndLoad> balancedCluster = reconcile( 128 list, plans); 129 LOG.info("Mock Balance : " + printStats(balancedCluster)); 130 assertClusterAsBalanced(balancedCluster); 131 } 132 133 /** 134 * Invariant is that all servers of a group have load between floor(avg) and 135 * ceiling(avg) number of regions. 136 */ 137 private void assertClusterAsBalanced( 138 ArrayListMultimap<String, ServerAndLoad> groupLoadMap) { 139 for (String gName : groupLoadMap.keySet()) { 140 List<ServerAndLoad> groupLoad = groupLoadMap.get(gName); 141 int numServers = groupLoad.size(); 142 int numRegions = 0; 143 int maxRegions = 0; 144 int minRegions = Integer.MAX_VALUE; 145 for (ServerAndLoad server : groupLoad) { 146 int nr = server.getLoad(); 147 if (nr > maxRegions) { 148 maxRegions = nr; 149 } 150 if (nr < minRegions) { 151 minRegions = nr; 152 } 153 numRegions += nr; 154 } 155 if (maxRegions - minRegions < 2) { 156 // less than 2 between max and min, can't balance 157 return; 158 } 159 int min = numRegions / numServers; 160 int max = numRegions % numServers == 0 ? min : min + 1; 161 162 for (ServerAndLoad server : groupLoad) { 163 assertTrue(server.getLoad() <= max); 164 assertTrue(server.getLoad() >= min); 165 } 166 } 167 } 168 169 /** 170 * All regions have an assignment. 171 */ 172 private void assertImmediateAssignment(List<RegionInfo> regions, 173 List<ServerName> servers, 174 Map<RegionInfo, ServerName> assignments) 175 throws IOException { 176 for (RegionInfo region : regions) { 177 assertTrue(assignments.containsKey(region)); 178 ServerName server = assignments.get(region); 179 TableName tableName = region.getTable(); 180 181 String groupName = getMockedGroupInfoManager().getRSGroupOfTable(tableName); 182 assertTrue(StringUtils.isNotEmpty(groupName)); 183 RSGroupInfo gInfo = getMockedGroupInfoManager().getRSGroup(groupName); 184 assertTrue("Region is not correctly assigned to group servers.", 185 gInfo.containsServer(server.getAddress())); 186 } 187 } 188 189 /** 190 * Tests the bulk assignment used during cluster startup. 191 * 192 * Round-robin. Should yield a balanced cluster so same invariant as the 193 * load balancer holds, all servers holding either floor(avg) or 194 * ceiling(avg). 195 */ 196 @Test 197 public void testBulkAssignment() throws Exception { 198 List<RegionInfo> regions = randomRegions(25); 199 Map<ServerName, List<RegionInfo>> assignments = loadBalancer 200 .roundRobinAssignment(regions, servers); 201 //test empty region/servers scenario 202 //this should not throw an NPE 203 loadBalancer.roundRobinAssignment(regions, 204 Collections.EMPTY_LIST); 205 //test regular scenario 206 assertTrue(assignments.keySet().size() == servers.size()); 207 for (ServerName sn : assignments.keySet()) { 208 List<RegionInfo> regionAssigned = assignments.get(sn); 209 for (RegionInfo region : regionAssigned) { 210 TableName tableName = region.getTable(); 211 String groupName = 212 getMockedGroupInfoManager().getRSGroupOfTable(tableName); 213 assertTrue(StringUtils.isNotEmpty(groupName)); 214 RSGroupInfo gInfo = getMockedGroupInfoManager().getRSGroup( 215 groupName); 216 assertTrue( 217 "Region is not correctly assigned to group servers.", 218 gInfo.containsServer(sn.getAddress())); 219 } 220 } 221 ArrayListMultimap<String, ServerAndLoad> loadMap = convertToGroupBasedMap(assignments); 222 assertClusterAsBalanced(loadMap); 223 } 224 225 @Test 226 public void testGetMisplacedRegions() throws Exception { 227 // Test case where region is not considered misplaced if RSGroupInfo cannot be determined 228 Map<RegionInfo, ServerName> inputForTest = new HashMap<>(); 229 RegionInfo ri = RegionInfoBuilder.newBuilder(table0) 230 .setStartKey(new byte[16]) 231 .setEndKey(new byte[16]) 232 .setSplit(false) 233 .setRegionId(regionId++) 234 .build(); 235 inputForTest.put(ri, servers.iterator().next()); 236 Set<RegionInfo> misplacedRegions = loadBalancer.getMisplacedRegions(inputForTest); 237 assertFalse(misplacedRegions.contains(ri)); 238 } 239 /** 240 * Test the cluster startup bulk assignment which attempts to retain assignment info. 241 */ 242 @Test 243 public void testRetainAssignment() throws Exception { 244 // Test simple case where all same servers are there 245 Map<ServerName, List<RegionInfo>> currentAssignments = mockClusterServers(); 246 Map<RegionInfo, ServerName> inputForTest = new HashMap<>(); 247 for (ServerName sn : currentAssignments.keySet()) { 248 for (RegionInfo region : currentAssignments.get(sn)) { 249 inputForTest.put(region, sn); 250 } 251 } 252 //verify region->null server assignment is handled 253 inputForTest.put(randomRegions(1).get(0), null); 254 Map<ServerName, List<RegionInfo>> newAssignment = loadBalancer 255 .retainAssignment(inputForTest, servers); 256 assertRetainedAssignment(inputForTest, servers, newAssignment); 257 } 258 259 /** 260 * Test BOGUS_SERVER_NAME among groups do not overwrite each other. 261 */ 262 @Test 263 public void testRoundRobinAssignment() throws Exception { 264 List<ServerName> onlineServers = new ArrayList<ServerName>(servers.size()); 265 onlineServers.addAll(servers); 266 List<RegionInfo> regions = randomRegions(25); 267 int bogusRegion = 0; 268 for(RegionInfo region : regions){ 269 String group = tableMap.get(region.getTable()); 270 if("dg3".equals(group) || "dg4".equals(group)){ 271 bogusRegion++; 272 } 273 } 274 Set<Address> offlineServers = new HashSet<Address>(); 275 offlineServers.addAll(groupMap.get("dg3").getServers()); 276 offlineServers.addAll(groupMap.get("dg4").getServers()); 277 for(Iterator<ServerName> it = onlineServers.iterator(); it.hasNext();){ 278 ServerName server = it.next(); 279 Address address = server.getAddress(); 280 if(offlineServers.contains(address)){ 281 it.remove(); 282 } 283 } 284 Map<ServerName, List<RegionInfo>> assignments = loadBalancer 285 .roundRobinAssignment(regions, onlineServers); 286 assertEquals(bogusRegion, assignments.get(LoadBalancer.BOGUS_SERVER_NAME).size()); 287 } 288 289 /** 290 * Asserts a valid retained assignment plan. 291 * <p> 292 * Must meet the following conditions: 293 * <ul> 294 * <li>Every input region has an assignment, and to an online server 295 * <li>If a region had an existing assignment to a server with the same 296 * address a a currently online server, it will be assigned to it 297 * </ul> 298 */ 299 private void assertRetainedAssignment( 300 Map<RegionInfo, ServerName> existing, List<ServerName> servers, 301 Map<ServerName, List<RegionInfo>> assignment) 302 throws FileNotFoundException, IOException { 303 // Verify condition 1, every region assigned, and to online server 304 Set<ServerName> onlineServerSet = new TreeSet<>(servers); 305 Set<RegionInfo> assignedRegions = new TreeSet<>(RegionInfo.COMPARATOR); 306 for (Map.Entry<ServerName, List<RegionInfo>> a : assignment.entrySet()) { 307 assertTrue( 308 "Region assigned to server that was not listed as online", 309 onlineServerSet.contains(a.getKey())); 310 for (RegionInfo r : a.getValue()) { 311 assignedRegions.add(r); 312 } 313 } 314 assertEquals(existing.size(), assignedRegions.size()); 315 316 // Verify condition 2, every region must be assigned to correct server. 317 Set<String> onlineHostNames = new TreeSet<>(); 318 for (ServerName s : servers) { 319 onlineHostNames.add(s.getHostname()); 320 } 321 322 for (Map.Entry<ServerName, List<RegionInfo>> a : assignment.entrySet()) { 323 ServerName currentServer = a.getKey(); 324 for (RegionInfo r : a.getValue()) { 325 ServerName oldAssignedServer = existing.get(r); 326 TableName tableName = r.getTable(); 327 String groupName = 328 getMockedGroupInfoManager().getRSGroupOfTable(tableName); 329 assertTrue(StringUtils.isNotEmpty(groupName)); 330 RSGroupInfo gInfo = getMockedGroupInfoManager().getRSGroup( 331 groupName); 332 assertTrue( 333 "Region is not correctly assigned to group servers.", 334 gInfo.containsServer(currentServer.getAddress())); 335 if (oldAssignedServer != null 336 && onlineHostNames.contains(oldAssignedServer 337 .getHostname())) { 338 // this region was previously assigned somewhere, and that 339 // host is still around, then the host must have been is a 340 // different group. 341 if (!oldAssignedServer.getAddress().equals(currentServer.getAddress())) { 342 assertFalse(gInfo.containsServer(oldAssignedServer.getAddress())); 343 } 344 } 345 } 346 } 347 } 348 349 private String printStats( 350 ArrayListMultimap<String, ServerAndLoad> groupBasedLoad) { 351 StringBuffer sb = new StringBuffer(); 352 sb.append("\n"); 353 for (String groupName : groupBasedLoad.keySet()) { 354 sb.append("Stats for group: " + groupName); 355 sb.append("\n"); 356 sb.append(groupMap.get(groupName).getServers()); 357 sb.append("\n"); 358 List<ServerAndLoad> groupLoad = groupBasedLoad.get(groupName); 359 int numServers = groupLoad.size(); 360 int totalRegions = 0; 361 sb.append("Per Server Load: \n"); 362 for (ServerAndLoad sLoad : groupLoad) { 363 sb.append("Server :" + sLoad.getServerName() + " Load : " 364 + sLoad.getLoad() + "\n"); 365 totalRegions += sLoad.getLoad(); 366 } 367 sb.append(" Group Statistics : \n"); 368 float average = (float) totalRegions / numServers; 369 int max = (int) Math.ceil(average); 370 int min = (int) Math.floor(average); 371 sb.append("[srvr=" + numServers + " rgns=" + totalRegions + " avg=" 372 + average + " max=" + max + " min=" + min + "]"); 373 sb.append("\n"); 374 sb.append("==============================="); 375 sb.append("\n"); 376 } 377 return sb.toString(); 378 } 379 380 private ArrayListMultimap<String, ServerAndLoad> convertToGroupBasedMap( 381 final Map<ServerName, List<RegionInfo>> serversMap) throws IOException { 382 ArrayListMultimap<String, ServerAndLoad> loadMap = ArrayListMultimap 383 .create(); 384 for (RSGroupInfo gInfo : getMockedGroupInfoManager().listRSGroups()) { 385 Set<Address> groupServers = gInfo.getServers(); 386 for (Address hostPort : groupServers) { 387 ServerName actual = null; 388 for(ServerName entry: servers) { 389 if(entry.getAddress().equals(hostPort)) { 390 actual = entry; 391 break; 392 } 393 } 394 List<RegionInfo> regions = serversMap.get(actual); 395 assertTrue("No load for " + actual, regions != null); 396 loadMap.put(gInfo.getName(), 397 new ServerAndLoad(actual, regions.size())); 398 } 399 } 400 return loadMap; 401 } 402 403 private ArrayListMultimap<String, ServerAndLoad> reconcile( 404 ArrayListMultimap<String, ServerAndLoad> previousLoad, 405 List<RegionPlan> plans) { 406 ArrayListMultimap<String, ServerAndLoad> result = ArrayListMultimap 407 .create(); 408 result.putAll(previousLoad); 409 if (plans != null) { 410 for (RegionPlan plan : plans) { 411 ServerName source = plan.getSource(); 412 updateLoad(result, source, -1); 413 ServerName destination = plan.getDestination(); 414 updateLoad(result, destination, +1); 415 } 416 } 417 return result; 418 } 419 420 private void updateLoad( 421 ArrayListMultimap<String, ServerAndLoad> previousLoad, 422 final ServerName sn, final int diff) { 423 for (String groupName : previousLoad.keySet()) { 424 ServerAndLoad newSAL = null; 425 ServerAndLoad oldSAL = null; 426 for (ServerAndLoad sal : previousLoad.get(groupName)) { 427 if (ServerName.isSameAddress(sn, sal.getServerName())) { 428 oldSAL = sal; 429 newSAL = new ServerAndLoad(sn, sal.getLoad() + diff); 430 break; 431 } 432 } 433 if (newSAL != null) { 434 previousLoad.remove(groupName, oldSAL); 435 previousLoad.put(groupName, newSAL); 436 break; 437 } 438 } 439 } 440 441 private Map<ServerName, List<RegionInfo>> mockClusterServers() throws IOException { 442 assertTrue(servers.size() == regionAssignment.length); 443 Map<ServerName, List<RegionInfo>> assignment = new TreeMap<>(); 444 for (int i = 0; i < servers.size(); i++) { 445 int numRegions = regionAssignment[i]; 446 List<RegionInfo> regions = assignedRegions(numRegions, servers.get(i)); 447 assignment.put(servers.get(i), regions); 448 } 449 return assignment; 450 } 451 452 /** 453 * Generate a list of regions evenly distributed between the tables. 454 * 455 * @param numRegions The number of regions to be generated. 456 * @return List of RegionInfo. 457 */ 458 private List<RegionInfo> randomRegions(int numRegions) { 459 List<RegionInfo> regions = new ArrayList<>(numRegions); 460 byte[] start = new byte[16]; 461 byte[] end = new byte[16]; 462 rand.nextBytes(start); 463 rand.nextBytes(end); 464 int regionIdx = rand.nextInt(tables.length); 465 for (int i = 0; i < numRegions; i++) { 466 Bytes.putInt(start, 0, numRegions << 1); 467 Bytes.putInt(end, 0, (numRegions << 1) + 1); 468 int tableIndex = (i + regionIdx) % tables.length; 469 regions.add(RegionInfoBuilder.newBuilder(tables[tableIndex]) 470 .setStartKey(start) 471 .setEndKey(end) 472 .setSplit(false) 473 .setRegionId(regionId++) 474 .build()); 475 } 476 return regions; 477 } 478 479 /** 480 * Generate assigned regions to a given server using group information. 481 * 482 * @param numRegions the num regions to generate 483 * @param sn the servername 484 * @return the list of regions 485 * @throws java.io.IOException Signals that an I/O exception has occurred. 486 */ 487 private List<RegionInfo> assignedRegions(int numRegions, ServerName sn) throws IOException { 488 List<RegionInfo> regions = new ArrayList<>(numRegions); 489 byte[] start = new byte[16]; 490 byte[] end = new byte[16]; 491 Bytes.putInt(start, 0, numRegions << 1); 492 Bytes.putInt(end, 0, (numRegions << 1) + 1); 493 for (int i = 0; i < numRegions; i++) { 494 TableName tableName = getTableName(sn); 495 regions.add(RegionInfoBuilder.newBuilder(tableName) 496 .setStartKey(start) 497 .setEndKey(end) 498 .setSplit(false) 499 .setRegionId(regionId++) 500 .build()); 501 } 502 return regions; 503 } 504 505 private static List<ServerName> generateServers(int numServers) { 506 List<ServerName> servers = new ArrayList<>(numServers); 507 for (int i = 0; i < numServers; i++) { 508 String host = "server" + rand.nextInt(100000); 509 int port = rand.nextInt(60000); 510 servers.add(ServerName.valueOf(host, port, -1)); 511 } 512 return servers; 513 } 514 515 /** 516 * Construct group info, with each group having at least one server. 517 * 518 * @param servers the servers 519 * @param groups the groups 520 * @return the map 521 */ 522 private static Map<String, RSGroupInfo> constructGroupInfo( 523 List<ServerName> servers, String[] groups) { 524 assertTrue(servers != null); 525 assertTrue(servers.size() >= groups.length); 526 int index = 0; 527 Map<String, RSGroupInfo> groupMap = new HashMap<>(); 528 for (String grpName : groups) { 529 RSGroupInfo RSGroupInfo = new RSGroupInfo(grpName); 530 RSGroupInfo.addServer(servers.get(index).getAddress()); 531 groupMap.put(grpName, RSGroupInfo); 532 index++; 533 } 534 while (index < servers.size()) { 535 int grpIndex = rand.nextInt(groups.length); 536 groupMap.get(groups[grpIndex]).addServer( 537 servers.get(index).getAddress()); 538 index++; 539 } 540 return groupMap; 541 } 542 543 /** 544 * Construct table descriptors evenly distributed between the groups. 545 * 546 * @return the list 547 */ 548 private static List<HTableDescriptor> constructTableDesc() { 549 List<HTableDescriptor> tds = Lists.newArrayList(); 550 int index = rand.nextInt(groups.length); 551 for (int i = 0; i < tables.length; i++) { 552 HTableDescriptor htd = new HTableDescriptor(tables[i]); 553 int grpIndex = (i + index) % groups.length ; 554 String groupName = groups[grpIndex]; 555 tableMap.put(tables[i], groupName); 556 tds.add(htd); 557 } 558 tableMap.put(table0, ""); 559 tds.add(new HTableDescriptor(table0)); 560 return tds; 561 } 562 563 private static MasterServices getMockedMaster() throws IOException { 564 TableDescriptors tds = Mockito.mock(TableDescriptors.class); 565 Mockito.when(tds.get(tables[0])).thenReturn(tableDescs.get(0)); 566 Mockito.when(tds.get(tables[1])).thenReturn(tableDescs.get(1)); 567 Mockito.when(tds.get(tables[2])).thenReturn(tableDescs.get(2)); 568 Mockito.when(tds.get(tables[3])).thenReturn(tableDescs.get(3)); 569 MasterServices services = Mockito.mock(HMaster.class); 570 Mockito.when(services.getTableDescriptors()).thenReturn(tds); 571 AssignmentManager am = Mockito.mock(AssignmentManager.class); 572 Mockito.when(services.getAssignmentManager()).thenReturn(am); 573 RegionStates rss = Mockito.mock(RegionStates.class); 574 Mockito.when(am.getRegionStates()).thenReturn(rss); 575 return services; 576 } 577 578 private static RSGroupInfoManager getMockedGroupInfoManager() throws IOException { 579 RSGroupInfoManager gm = Mockito.mock(RSGroupInfoManager.class); 580 Mockito.when(gm.getRSGroup(groups[0])).thenReturn( 581 groupMap.get(groups[0])); 582 Mockito.when(gm.getRSGroup(groups[1])).thenReturn( 583 groupMap.get(groups[1])); 584 Mockito.when(gm.getRSGroup(groups[2])).thenReturn( 585 groupMap.get(groups[2])); 586 Mockito.when(gm.getRSGroup(groups[3])).thenReturn( 587 groupMap.get(groups[3])); 588 Mockito.when(gm.listRSGroups()).thenReturn( 589 Lists.newLinkedList(groupMap.values())); 590 Mockito.when(gm.isOnline()).thenReturn(true); 591 Mockito.when(gm.getRSGroupOfTable(Mockito.any())) 592 .thenAnswer(new Answer<String>() { 593 @Override 594 public String answer(InvocationOnMock invocation) throws Throwable { 595 return tableMap.get(invocation.getArgument(0)); 596 } 597 }); 598 return gm; 599 } 600 601 private TableName getTableName(ServerName sn) throws IOException { 602 TableName tableName = null; 603 RSGroupInfoManager gm = getMockedGroupInfoManager(); 604 RSGroupInfo groupOfServer = null; 605 for(RSGroupInfo gInfo : gm.listRSGroups()){ 606 if(gInfo.containsServer(sn.getAddress())){ 607 groupOfServer = gInfo; 608 break; 609 } 610 } 611 612 for(HTableDescriptor desc : tableDescs){ 613 if(gm.getRSGroupOfTable(desc.getTableName()).endsWith(groupOfServer.getName())){ 614 tableName = desc.getTableName(); 615 } 616 } 617 return tableName; 618 } 619}