View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.master;
19  
20  import static org.junit.Assert.*;
21  
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.hbase.HBaseIOException;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.HConstants;
34  import org.apache.hadoop.hbase.HRegionInfo;
35  import org.apache.hadoop.hbase.ServerName;
36  import org.apache.hadoop.hbase.TableName;
37  import org.apache.hadoop.hbase.master.balancer.FavoredNodeLoadBalancer;
38  import org.apache.hadoop.hbase.master.balancer.LoadBalancerFactory;
39  import org.apache.hadoop.hbase.master.balancer.FavoredNodesPlan.Position;
40  import org.apache.hadoop.hbase.testclassification.MediumTests;
41  import org.junit.AfterClass;
42  import org.junit.BeforeClass;
43  import org.junit.Test;
44  import org.junit.experimental.categories.Category;
45  
46  @Category({MediumTests.class})
47  public class TestRegionPlacement2 {
48    final static Log LOG = LogFactory.getLog(TestRegionPlacement2.class);
49    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
50    private final static int SLAVES = 7;
51    private final static int PRIMARY = Position.PRIMARY.ordinal();
52    private final static int SECONDARY = Position.SECONDARY.ordinal();
53    private final static int TERTIARY = Position.TERTIARY.ordinal();
54  
55    @BeforeClass
56    public static void setupBeforeClass() throws Exception {
57      Configuration conf = TEST_UTIL.getConfiguration();
58      // Enable the favored nodes based load balancer
59      conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
60          FavoredNodeLoadBalancer.class, LoadBalancer.class);
61      conf.setBoolean("hbase.tests.use.shortcircuit.reads", false);
62      TEST_UTIL.startMiniCluster(SLAVES);
63    }
64  
65    @AfterClass
66    public static void tearDownAfterClass() throws Exception {
67      TEST_UTIL.shutdownMiniCluster();
68    }
69  
70    @Test
71    public void testFavoredNodesPresentForRoundRobinAssignment() throws HBaseIOException {
72      LoadBalancer balancer = LoadBalancerFactory.getLoadBalancer(TEST_UTIL.getConfiguration());
73      balancer.setMasterServices(TEST_UTIL.getMiniHBaseCluster().getMaster());
74      List<ServerName> servers = new ArrayList<ServerName>();
75      for (int i = 0; i < SLAVES; i++) {
76        ServerName server = TEST_UTIL.getMiniHBaseCluster().getRegionServer(i).getServerName();
77        servers.add(server);
78      }
79      List<HRegionInfo> regions = new ArrayList<HRegionInfo>(1);
80      HRegionInfo region = new HRegionInfo(TableName.valueOf("foobar"));
81      regions.add(region);
82      Map<ServerName,List<HRegionInfo>> assignmentMap = balancer.roundRobinAssignment(regions,
83          servers);
84      Set<ServerName> serverBefore = assignmentMap.keySet();
85      List<ServerName> favoredNodesBefore =
86          ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region);
87      assertTrue(favoredNodesBefore.size() == 3);
88      // the primary RS should be the one that the balancer's assignment returns
89      assertTrue(ServerName.isSameHostnameAndPort(serverBefore.iterator().next(),
90          favoredNodesBefore.get(PRIMARY)));
91      // now remove the primary from the list of available servers
92      List<ServerName> removedServers = removeMatchingServers(serverBefore, servers);
93      // call roundRobinAssignment with the modified servers list
94      assignmentMap = balancer.roundRobinAssignment(regions, servers);
95      List<ServerName> favoredNodesAfter =
96          ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region);
97      assertTrue(favoredNodesAfter.size() == 3);
98      // We don't expect the favored nodes assignments to change in multiple calls
99      // to the roundRobinAssignment method in the balancer (relevant for AssignmentManager.assign
100     // failures)
101     assertTrue(favoredNodesAfter.containsAll(favoredNodesBefore));
102     Set<ServerName> serverAfter = assignmentMap.keySet();
103     // We expect the new RegionServer assignee to be one of the favored nodes
104     // chosen earlier.
105     assertTrue(ServerName.isSameHostnameAndPort(serverAfter.iterator().next(),
106                  favoredNodesBefore.get(SECONDARY)) ||
107                ServerName.isSameHostnameAndPort(serverAfter.iterator().next(),
108                  favoredNodesBefore.get(TERTIARY)));
109 
110     // put back the primary in the list of available servers
111     servers.addAll(removedServers);
112     // now roundRobinAssignment with the modified servers list should return the primary
113     // as the regionserver assignee
114     assignmentMap = balancer.roundRobinAssignment(regions, servers);
115     Set<ServerName> serverWithPrimary = assignmentMap.keySet();
116     assertTrue(serverBefore.containsAll(serverWithPrimary));
117 
118     // Make all the favored nodes unavailable for assignment
119     removeMatchingServers(favoredNodesAfter, servers);
120     // call roundRobinAssignment with the modified servers list
121     assignmentMap = balancer.roundRobinAssignment(regions, servers);
122     List<ServerName> favoredNodesNow =
123         ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region);
124     assertTrue(favoredNodesNow.size() == 3);
125     assertTrue(!favoredNodesNow.contains(favoredNodesAfter.get(PRIMARY)) &&
126         !favoredNodesNow.contains(favoredNodesAfter.get(SECONDARY)) &&
127         !favoredNodesNow.contains(favoredNodesAfter.get(TERTIARY)));
128   }
129 
130   @Test
131   public void testFavoredNodesPresentForRandomAssignment() throws HBaseIOException {
132     LoadBalancer balancer = LoadBalancerFactory.getLoadBalancer(TEST_UTIL.getConfiguration());
133     balancer.setMasterServices(TEST_UTIL.getMiniHBaseCluster().getMaster());
134     List<ServerName> servers = new ArrayList<ServerName>();
135     for (int i = 0; i < SLAVES; i++) {
136       ServerName server = TEST_UTIL.getMiniHBaseCluster().getRegionServer(i).getServerName();
137       servers.add(server);
138     }
139     List<HRegionInfo> regions = new ArrayList<HRegionInfo>(1);
140     HRegionInfo region = new HRegionInfo(TableName.valueOf("foobar"));
141     regions.add(region);
142     ServerName serverBefore = balancer.randomAssignment(region, servers);
143     List<ServerName> favoredNodesBefore =
144         ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region);
145     assertTrue(favoredNodesBefore.size() == 3);
146     // the primary RS should be the one that the balancer's assignment returns
147     assertTrue(ServerName.isSameHostnameAndPort(serverBefore,favoredNodesBefore.get(PRIMARY)));
148     // now remove the primary from the list of servers
149     removeMatchingServers(serverBefore, servers);
150     // call randomAssignment with the modified servers list
151     ServerName serverAfter = balancer.randomAssignment(region, servers);
152     List<ServerName> favoredNodesAfter =
153         ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region);
154     assertTrue(favoredNodesAfter.size() == 3);
155     // We don't expect the favored nodes assignments to change in multiple calls
156     // to the randomAssignment method in the balancer (relevant for AssignmentManager.assign
157     // failures)
158     assertTrue(favoredNodesAfter.containsAll(favoredNodesBefore));
159     // We expect the new RegionServer assignee to be one of the favored nodes
160     // chosen earlier.
161     assertTrue(ServerName.isSameHostnameAndPort(serverAfter, favoredNodesBefore.get(SECONDARY)) ||
162                ServerName.isSameHostnameAndPort(serverAfter, favoredNodesBefore.get(TERTIARY)));
163     // Make all the favored nodes unavailable for assignment
164     removeMatchingServers(favoredNodesAfter, servers);
165     // call randomAssignment with the modified servers list
166     balancer.randomAssignment(region, servers);
167     List<ServerName> favoredNodesNow =
168         ((FavoredNodeLoadBalancer)balancer).getFavoredNodes(region);
169     assertTrue(favoredNodesNow.size() == 3);
170     assertTrue(!favoredNodesNow.contains(favoredNodesAfter.get(PRIMARY)) &&
171         !favoredNodesNow.contains(favoredNodesAfter.get(SECONDARY)) &&
172         !favoredNodesNow.contains(favoredNodesAfter.get(TERTIARY)));
173   }
174 
175   private List<ServerName> removeMatchingServers(Collection<ServerName> serversWithoutStartCode,
176       List<ServerName> servers) {
177     List<ServerName> serversToRemove = new ArrayList<ServerName>();
178     for (ServerName s : serversWithoutStartCode) {
179       serversToRemove.addAll(removeMatchingServers(s, servers));
180     }
181     return serversToRemove;
182   }
183 
184   private List<ServerName> removeMatchingServers(ServerName serverWithoutStartCode,
185       List<ServerName> servers) {
186     List<ServerName> serversToRemove = new ArrayList<ServerName>();
187     for (ServerName s : servers) {
188       if (ServerName.isSameHostnameAndPort(s, serverWithoutStartCode)) {
189         serversToRemove.add(s);
190       }
191     }
192     servers.removeAll(serversToRemove);
193     return serversToRemove;
194   }
195 }