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; 019 020import static org.junit.Assert.assertTrue; 021 022import java.util.ArrayList; 023import java.util.Collection; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseIOException; 030import org.apache.hadoop.hbase.HBaseTestingUtility; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.ServerName; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.RegionInfo; 035import org.apache.hadoop.hbase.client.RegionInfoBuilder; 036import org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper; 037import org.apache.hadoop.hbase.favored.FavoredNodeLoadBalancer; 038import org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position; 039import org.apache.hadoop.hbase.master.balancer.LoadBalancerFactory; 040import org.apache.hadoop.hbase.testclassification.MasterTests; 041import org.apache.hadoop.hbase.testclassification.MediumTests; 042import org.junit.AfterClass; 043import org.junit.BeforeClass; 044import org.junit.ClassRule; 045import org.junit.Rule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048import org.junit.rules.TestName; 049import org.slf4j.Logger; 050import org.slf4j.LoggerFactory; 051 052@Category({MasterTests.class, MediumTests.class}) 053public class TestRegionPlacement2 { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestRegionPlacement2.class); 058 059 private static final Logger LOG = LoggerFactory.getLogger(TestRegionPlacement2.class); 060 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 061 private final static int SLAVES = 7; 062 private final static int PRIMARY = Position.PRIMARY.ordinal(); 063 private final static int SECONDARY = Position.SECONDARY.ordinal(); 064 private final static int TERTIARY = Position.TERTIARY.ordinal(); 065 066 @Rule 067 public TestName name = new TestName(); 068 069 @BeforeClass 070 public static void setupBeforeClass() throws Exception { 071 Configuration conf = TEST_UTIL.getConfiguration(); 072 // Enable the favored nodes based load balancer 073 conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, 074 FavoredNodeLoadBalancer.class, LoadBalancer.class); 075 conf.setBoolean("hbase.tests.use.shortcircuit.reads", false); 076 TEST_UTIL.startMiniCluster(SLAVES); 077 } 078 079 @AfterClass 080 public static void tearDownAfterClass() throws Exception { 081 TEST_UTIL.shutdownMiniCluster(); 082 } 083 084 @Test 085 public void testFavoredNodesPresentForRoundRobinAssignment() throws HBaseIOException { 086 LoadBalancer balancer = LoadBalancerFactory.getLoadBalancer(TEST_UTIL.getConfiguration()); 087 balancer.setMasterServices(TEST_UTIL.getMiniHBaseCluster().getMaster()); 088 balancer.initialize(); 089 List<ServerName> servers = new ArrayList<>(); 090 for (int i = 0; i < SLAVES; i++) { 091 ServerName server = TEST_UTIL.getMiniHBaseCluster().getRegionServer(i).getServerName(); 092 servers.add(server); 093 } 094 List<RegionInfo> regions = new ArrayList<>(1); 095 RegionInfo region = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())).build(); 096 regions.add(region); 097 Map<ServerName,List<RegionInfo>> assignmentMap = balancer.roundRobinAssignment(regions, 098 servers); 099 Set<ServerName> serverBefore = assignmentMap.keySet(); 100 List<ServerName> favoredNodesBefore = 101 ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region); 102 assertTrue(favoredNodesBefore.size() == FavoredNodeAssignmentHelper.FAVORED_NODES_NUM); 103 // the primary RS should be the one that the balancer's assignment returns 104 assertTrue(ServerName.isSameAddress(serverBefore.iterator().next(), 105 favoredNodesBefore.get(PRIMARY))); 106 // now remove the primary from the list of available servers 107 List<ServerName> removedServers = removeMatchingServers(serverBefore, servers); 108 // call roundRobinAssignment with the modified servers list 109 assignmentMap = balancer.roundRobinAssignment(regions, servers); 110 List<ServerName> favoredNodesAfter = 111 ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region); 112 assertTrue(favoredNodesAfter.size() == FavoredNodeAssignmentHelper.FAVORED_NODES_NUM); 113 // We don't expect the favored nodes assignments to change in multiple calls 114 // to the roundRobinAssignment method in the balancer (relevant for AssignmentManager.assign 115 // failures) 116 assertTrue(favoredNodesAfter.containsAll(favoredNodesBefore)); 117 Set<ServerName> serverAfter = assignmentMap.keySet(); 118 // We expect the new RegionServer assignee to be one of the favored nodes 119 // chosen earlier. 120 assertTrue(ServerName.isSameAddress(serverAfter.iterator().next(), 121 favoredNodesBefore.get(SECONDARY)) || 122 ServerName.isSameAddress(serverAfter.iterator().next(), 123 favoredNodesBefore.get(TERTIARY))); 124 125 // put back the primary in the list of available servers 126 servers.addAll(removedServers); 127 // now roundRobinAssignment with the modified servers list should return the primary 128 // as the regionserver assignee 129 assignmentMap = balancer.roundRobinAssignment(regions, servers); 130 Set<ServerName> serverWithPrimary = assignmentMap.keySet(); 131 assertTrue(serverBefore.containsAll(serverWithPrimary)); 132 133 // Make all the favored nodes unavailable for assignment 134 removeMatchingServers(favoredNodesAfter, servers); 135 // call roundRobinAssignment with the modified servers list 136 assignmentMap = balancer.roundRobinAssignment(regions, servers); 137 List<ServerName> favoredNodesNow = 138 ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region); 139 assertTrue(favoredNodesNow.size() == FavoredNodeAssignmentHelper.FAVORED_NODES_NUM); 140 assertTrue(!favoredNodesNow.contains(favoredNodesAfter.get(PRIMARY)) && 141 !favoredNodesNow.contains(favoredNodesAfter.get(SECONDARY)) && 142 !favoredNodesNow.contains(favoredNodesAfter.get(TERTIARY))); 143 } 144 145 @Test 146 public void testFavoredNodesPresentForRandomAssignment() throws HBaseIOException { 147 LoadBalancer balancer = LoadBalancerFactory.getLoadBalancer(TEST_UTIL.getConfiguration()); 148 balancer.setMasterServices(TEST_UTIL.getMiniHBaseCluster().getMaster()); 149 balancer.initialize(); 150 List<ServerName> servers = new ArrayList<>(); 151 for (int i = 0; i < SLAVES; i++) { 152 ServerName server = TEST_UTIL.getMiniHBaseCluster().getRegionServer(i).getServerName(); 153 servers.add(server); 154 } 155 List<RegionInfo> regions = new ArrayList<>(1); 156 RegionInfo region = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())).build(); 157 regions.add(region); 158 ServerName serverBefore = balancer.randomAssignment(region, servers); 159 List<ServerName> favoredNodesBefore = 160 ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region); 161 assertTrue(favoredNodesBefore.size() == FavoredNodeAssignmentHelper.FAVORED_NODES_NUM); 162 // the primary RS should be the one that the balancer's assignment returns 163 assertTrue(ServerName.isSameAddress(serverBefore,favoredNodesBefore.get(PRIMARY))); 164 // now remove the primary from the list of servers 165 removeMatchingServers(serverBefore, servers); 166 // call randomAssignment with the modified servers list 167 ServerName serverAfter = balancer.randomAssignment(region, servers); 168 List<ServerName> favoredNodesAfter = 169 ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region); 170 assertTrue(favoredNodesAfter.size() == FavoredNodeAssignmentHelper.FAVORED_NODES_NUM); 171 // We don't expect the favored nodes assignments to change in multiple calls 172 // to the randomAssignment method in the balancer (relevant for AssignmentManager.assign 173 // failures) 174 assertTrue(favoredNodesAfter.containsAll(favoredNodesBefore)); 175 // We expect the new RegionServer assignee to be one of the favored nodes 176 // chosen earlier. 177 assertTrue(ServerName.isSameAddress(serverAfter, favoredNodesBefore.get(SECONDARY)) || 178 ServerName.isSameAddress(serverAfter, favoredNodesBefore.get(TERTIARY))); 179 // Make all the favored nodes unavailable for assignment 180 removeMatchingServers(favoredNodesAfter, servers); 181 // call randomAssignment with the modified servers list 182 balancer.randomAssignment(region, servers); 183 List<ServerName> favoredNodesNow = 184 ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region); 185 assertTrue(favoredNodesNow.size() == FavoredNodeAssignmentHelper.FAVORED_NODES_NUM); 186 assertTrue(!favoredNodesNow.contains(favoredNodesAfter.get(PRIMARY)) && 187 !favoredNodesNow.contains(favoredNodesAfter.get(SECONDARY)) && 188 !favoredNodesNow.contains(favoredNodesAfter.get(TERTIARY))); 189 } 190 191 private List<ServerName> removeMatchingServers(Collection<ServerName> serversWithoutStartCode, 192 List<ServerName> servers) { 193 List<ServerName> serversToRemove = new ArrayList<>(); 194 for (ServerName s : serversWithoutStartCode) { 195 serversToRemove.addAll(removeMatchingServers(s, servers)); 196 } 197 return serversToRemove; 198 } 199 200 private List<ServerName> removeMatchingServers(ServerName serverWithoutStartCode, 201 List<ServerName> servers) { 202 List<ServerName> serversToRemove = new ArrayList<>(); 203 for (ServerName s : servers) { 204 if (ServerName.isSameAddress(s, serverWithoutStartCode)) { 205 serversToRemove.add(s); 206 } 207 } 208 servers.removeAll(serversToRemove); 209 return serversToRemove; 210 } 211}