1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master.balancer;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.when;
24
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.TreeMap;
32 import java.util.TreeSet;
33
34 import org.apache.commons.lang.ArrayUtils;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.hadoop.conf.Configuration;
38 import org.apache.hadoop.hbase.HBaseConfiguration;
39 import org.apache.hadoop.hbase.HBaseIOException;
40 import org.apache.hadoop.hbase.HRegionInfo;
41 import org.apache.hadoop.hbase.testclassification.MediumTests;
42 import org.apache.hadoop.hbase.ServerName;
43 import org.apache.hadoop.hbase.TableName;
44 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
45 import org.apache.hadoop.hbase.master.LoadBalancer;
46 import org.apache.hadoop.hbase.master.MasterServices;
47 import org.apache.hadoop.hbase.master.RackManager;
48 import org.apache.hadoop.hbase.master.RegionPlan;
49 import org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer.Cluster;
50 import org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer.Cluster.MoveRegionAction;
51 import org.apache.hadoop.net.DNSToSwitchMapping;
52 import org.junit.BeforeClass;
53 import org.junit.Test;
54 import org.junit.experimental.categories.Category;
55 import org.mockito.Mockito;
56
57 import com.google.common.collect.Lists;
58
59 @Category(MediumTests.class)
60 public class TestBaseLoadBalancer extends BalancerTestBase {
61
62 private static LoadBalancer loadBalancer;
63 private static final Log LOG = LogFactory.getLog(TestBaseLoadBalancer.class);
64 private static final ServerName master = ServerName.valueOf("fake-master", 0, 1L);
65 private static RackManager rackManager;
66 private static final int NUM_SERVERS = 15;
67 private static ServerName[] servers = new ServerName[NUM_SERVERS];
68
69 int[][] regionsAndServersMocks = new int[][] {
70
71 new int[] { 0, 0 }, new int[] { 0, 1 }, new int[] { 1, 1 }, new int[] { 2, 1 },
72 new int[] { 10, 1 }, new int[] { 1, 2 }, new int[] { 2, 2 }, new int[] { 3, 2 },
73 new int[] { 1, 3 }, new int[] { 2, 3 }, new int[] { 3, 3 }, new int[] { 25, 3 },
74 new int[] { 2, 10 }, new int[] { 2, 100 }, new int[] { 12, 10 }, new int[] { 12, 100 }, };
75
76 @BeforeClass
77 public static void beforeAllTests() throws Exception {
78 Configuration conf = HBaseConfiguration.create();
79 conf.setClass("hbase.util.ip.to.rack.determiner", MockMapping.class, DNSToSwitchMapping.class);
80 loadBalancer = new MockBalancer();
81 loadBalancer.setConf(conf);
82 MasterServices st = Mockito.mock(MasterServices.class);
83 Mockito.when(st.getServerName()).thenReturn(master);
84 loadBalancer.setMasterServices(st);
85
86
87 rackManager = Mockito.mock(RackManager.class);
88 for (int i = 0; i < NUM_SERVERS; i++) {
89 servers[i] = ServerName.valueOf("foo"+i+":1234",-1);
90 if (i < 5) {
91 Mockito.when(rackManager.getRack(servers[i])).thenReturn("rack1");
92 }
93 if (i >= 5 && i < 10) {
94 Mockito.when(rackManager.getRack(servers[i])).thenReturn("rack2");
95 }
96 if (i >= 10) {
97 Mockito.when(rackManager.getRack(servers[i])).thenReturn("rack3");
98 }
99 }
100 }
101
102 public static class MockBalancer extends BaseLoadBalancer {
103
104 @Override
105 public List<RegionPlan> balanceCluster(Map<ServerName, List<HRegionInfo>> clusterState) {
106 return null;
107 }
108
109 @Override
110 public List<RegionPlan> balanceCluster(TableName tableName,
111 Map<ServerName, List<HRegionInfo>> clusterState) throws HBaseIOException {
112 return null;
113 }
114
115 }
116
117
118
119
120
121
122
123
124 @Test (timeout=30000)
125 public void testImmediateAssignment() throws Exception {
126 for (int[] mock : regionsAndServersMocks) {
127 LOG.debug("testImmediateAssignment with " + mock[0] + " regions and " + mock[1] + " servers");
128 List<HRegionInfo> regions = randomRegions(mock[0]);
129 List<ServerAndLoad> servers = randomServers(mock[1], 0);
130 List<ServerName> list = getListOfServerNames(servers);
131 Map<HRegionInfo, ServerName> assignments = loadBalancer.immediateAssignment(regions, list);
132 assertImmediateAssignment(regions, list, assignments);
133 returnRegions(regions);
134 returnServers(list);
135 }
136 }
137
138
139
140
141
142
143
144 private void assertImmediateAssignment(List<HRegionInfo> regions, List<ServerName> servers,
145 Map<HRegionInfo, ServerName> assignments) {
146 for (HRegionInfo region : regions) {
147 assertTrue(assignments.containsKey(region));
148 }
149 }
150
151
152
153
154
155
156
157
158
159 @Test (timeout=180000)
160 public void testBulkAssignment() throws Exception {
161 for (int[] mock : regionsAndServersMocks) {
162 LOG.debug("testBulkAssignment with " + mock[0] + " regions and " + mock[1] + " servers");
163 List<HRegionInfo> regions = randomRegions(mock[0]);
164 List<ServerAndLoad> servers = randomServers(mock[1], 0);
165 List<ServerName> list = getListOfServerNames(servers);
166 Map<ServerName, List<HRegionInfo>> assignments =
167 loadBalancer.roundRobinAssignment(regions, list);
168 float average = (float) regions.size() / servers.size();
169 int min = (int) Math.floor(average);
170 int max = (int) Math.ceil(average);
171 if (assignments != null && !assignments.isEmpty()) {
172 for (List<HRegionInfo> regionList : assignments.values()) {
173 assertTrue(regionList.size() == min || regionList.size() == max);
174 }
175 }
176 returnRegions(regions);
177 returnServers(list);
178 }
179 }
180
181
182
183
184
185
186 @Test (timeout=180000)
187 public void testRetainAssignment() throws Exception {
188
189 List<ServerAndLoad> servers = randomServers(10, 10);
190 List<HRegionInfo> regions = randomRegions(100);
191 Map<HRegionInfo, ServerName> existing = new TreeMap<HRegionInfo, ServerName>();
192 for (int i = 0; i < regions.size(); i++) {
193 ServerName sn = servers.get(i % servers.size()).getServerName();
194
195
196 ServerName snWithOldStartCode =
197 ServerName.valueOf(sn.getHostname(), sn.getPort(), sn.getStartcode() - 10);
198 existing.put(regions.get(i), snWithOldStartCode);
199 }
200 List<ServerName> listOfServerNames = getListOfServerNames(servers);
201 Map<ServerName, List<HRegionInfo>> assignment =
202 loadBalancer.retainAssignment(existing, listOfServerNames);
203 assertRetainedAssignment(existing, listOfServerNames, assignment);
204
205
206 List<ServerAndLoad> servers2 = new ArrayList<ServerAndLoad>(servers);
207 servers2.add(randomServer(10));
208 servers2.add(randomServer(10));
209 listOfServerNames = getListOfServerNames(servers2);
210 assignment = loadBalancer.retainAssignment(existing, listOfServerNames);
211 assertRetainedAssignment(existing, listOfServerNames, assignment);
212
213
214 List<ServerAndLoad> servers3 = new ArrayList<ServerAndLoad>(servers);
215 servers3.remove(0);
216 servers3.remove(0);
217 listOfServerNames = getListOfServerNames(servers3);
218 assignment = loadBalancer.retainAssignment(existing, listOfServerNames);
219 assertRetainedAssignment(existing, listOfServerNames, assignment);
220 }
221
222 @Test (timeout=180000)
223 public void testRegionAvailability() throws Exception {
224
225
226
227
228
229 List<HRegionInfo> list0 = new ArrayList<HRegionInfo>();
230 List<HRegionInfo> list1 = new ArrayList<HRegionInfo>();
231 List<HRegionInfo> list2 = new ArrayList<HRegionInfo>();
232
233 HRegionInfo hri1 = new HRegionInfo(
234 TableName.valueOf("table"), "key1".getBytes(), "key2".getBytes(),
235 false, 100);
236
237 HRegionInfo hri2 = RegionReplicaUtil.getRegionInfoForReplica(hri1, 1);
238
239 HRegionInfo hri3 = new HRegionInfo(
240 TableName.valueOf("table"), "key2".getBytes(), "key3".getBytes(),
241 false, 101);
242 list0.add(hri1);
243 list1.add(hri2);
244 list2.add(hri3);
245 Map<ServerName, List<HRegionInfo>> clusterState =
246 new LinkedHashMap<ServerName, List<HRegionInfo>>();
247 clusterState.put(servers[0], list0);
248 clusterState.put(servers[1], list1);
249 clusterState.put(servers[2], list2);
250
251
252
253
254 Cluster cluster = new Cluster(clusterState, null, null, rackManager);
255
256
257 assertTrue(cluster.wouldLowerAvailability(hri1, servers[1]));
258
259
260 assertTrue(!cluster.wouldLowerAvailability(hri1, servers[2]));
261
262
263 assertTrue(!cluster.wouldLowerAvailability(hri2, servers[2]));
264
265
266 assertTrue(!cluster.wouldLowerAvailability(hri3, servers[1]));
267
268
269 list1.add(RegionReplicaUtil.getRegionInfoForReplica(hri3, 1));
270
271 cluster = new Cluster(clusterState, null, null, rackManager);
272
273
274 assertTrue(cluster.wouldLowerAvailability(hri3, servers[1]));
275
276
277 clusterState.clear();
278 clusterState.put(servers[0], list0);
279 clusterState.put(servers[5], list1);
280 clusterState.put(servers[6], list2);
281 clusterState.put(servers[10], new ArrayList<HRegionInfo>());
282
283 cluster = new Cluster(clusterState, null, null, rackManager);
284
285
286
287 assertTrue(cluster.wouldLowerAvailability(hri1, servers[0]));
288
289
290 cluster = new Cluster(clusterState, null, null, null);
291
292
293 assertTrue(!cluster.wouldLowerAvailability(hri1, servers[6]));
294 }
295
296 @Test (timeout=180000)
297 public void testRegionAvailabilityWithRegionMoves() throws Exception {
298 List<HRegionInfo> list0 = new ArrayList<HRegionInfo>();
299 List<HRegionInfo> list1 = new ArrayList<HRegionInfo>();
300 List<HRegionInfo> list2 = new ArrayList<HRegionInfo>();
301
302 HRegionInfo hri1 = new HRegionInfo(
303 TableName.valueOf("table"), "key1".getBytes(), "key2".getBytes(),
304 false, 100);
305
306 HRegionInfo hri2 = RegionReplicaUtil.getRegionInfoForReplica(hri1, 1);
307
308 HRegionInfo hri3 = new HRegionInfo(
309 TableName.valueOf("table"), "key2".getBytes(), "key3".getBytes(),
310 false, 101);
311 list0.add(hri1);
312 list1.add(hri2);
313 list2.add(hri3);
314 Map<ServerName, List<HRegionInfo>> clusterState =
315 new LinkedHashMap<ServerName, List<HRegionInfo>>();
316 clusterState.put(servers[0], list0);
317 clusterState.put(servers[1], list1);
318 clusterState.put(servers[2], list2);
319
320
321
322
323 Cluster cluster = new Cluster(clusterState, null, null, rackManager);
324
325 assertTrue(!cluster.wouldLowerAvailability(hri1, servers[2]));
326
327
328 cluster.doAction(new MoveRegionAction(0, 0, 2));
329
330
331 assertTrue(cluster.wouldLowerAvailability(hri1, servers[2]));
332
333
334 clusterState.clear();
335 List<HRegionInfo> list3 = new ArrayList<HRegionInfo>();
336 HRegionInfo hri4 = RegionReplicaUtil.getRegionInfoForReplica(hri3, 1);
337 list3.add(hri4);
338 clusterState.put(servers[0], list0);
339 clusterState.put(servers[5], list1);
340 clusterState.put(servers[6], list2);
341 clusterState.put(servers[12], list3);
342
343 cluster = new Cluster(clusterState, null, null, rackManager);
344
345
346 assertTrue(!cluster.wouldLowerAvailability(hri4, servers[0]));
347
348 cluster.doAction(new MoveRegionAction(2, 2, 0));
349
350
351 assertTrue(cluster.wouldLowerAvailability(hri3, servers[0]));
352 }
353
354 private List<ServerName> getListOfServerNames(final List<ServerAndLoad> sals) {
355 List<ServerName> list = new ArrayList<ServerName>();
356 for (ServerAndLoad e : sals) {
357 list.add(e.getServerName());
358 }
359 return list;
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375 private void assertRetainedAssignment(Map<HRegionInfo, ServerName> existing,
376 List<ServerName> servers, Map<ServerName, List<HRegionInfo>> assignment) {
377
378 Set<ServerName> onlineServerSet = new TreeSet<ServerName>(servers);
379 Set<HRegionInfo> assignedRegions = new TreeSet<HRegionInfo>();
380 for (Map.Entry<ServerName, List<HRegionInfo>> a : assignment.entrySet()) {
381 assertTrue("Region assigned to server that was not listed as online",
382 onlineServerSet.contains(a.getKey()));
383 for (HRegionInfo r : a.getValue())
384 assignedRegions.add(r);
385 }
386 assertEquals(existing.size(), assignedRegions.size());
387
388
389 Set<String> onlineHostNames = new TreeSet<String>();
390 for (ServerName s : servers) {
391 onlineHostNames.add(s.getHostname());
392 }
393
394 for (Map.Entry<ServerName, List<HRegionInfo>> a : assignment.entrySet()) {
395 ServerName assignedTo = a.getKey();
396 for (HRegionInfo r : a.getValue()) {
397 ServerName address = existing.get(r);
398 if (address != null && onlineHostNames.contains(address.getHostname())) {
399
400
401
402 assertEquals(address.getHostname(), assignedTo.getHostname());
403 }
404 }
405 }
406 }
407
408 @Test (timeout=180000)
409 public void testClusterServersWithSameHostPort() {
410
411
412 List<ServerName> servers = getListOfServerNames(randomServers(10, 10));
413 List<HRegionInfo> regions = randomRegions(101);
414 Map<ServerName, List<HRegionInfo>> clusterState = new HashMap<ServerName, List<HRegionInfo>>();
415
416 assignRegions(regions, servers, clusterState);
417
418
419 List<ServerName> oldServers = new ArrayList<ServerName>(servers.size());
420 for (ServerName sn : servers) {
421
422 oldServers.add(ServerName.valueOf(sn.getHostname(), sn.getPort(), sn.getStartcode() - 10));
423 }
424
425 regions = randomRegions(9);
426 assignRegions(regions, oldServers, clusterState);
427
428
429 BaseLoadBalancer.Cluster cluster = new Cluster(clusterState, null, null, null);
430 assertEquals(101 + 9, cluster.numRegions);
431 assertEquals(10, cluster.numServers);
432 }
433
434 private void assignRegions(List<HRegionInfo> regions, List<ServerName> servers,
435 Map<ServerName, List<HRegionInfo>> clusterState) {
436 for (int i = 0; i < regions.size(); i++) {
437 ServerName sn = servers.get(i % servers.size());
438 List<HRegionInfo> regionsOfServer = clusterState.get(sn);
439 if (regionsOfServer == null) {
440 regionsOfServer = new ArrayList<HRegionInfo>(10);
441 clusterState.put(sn, regionsOfServer);
442 }
443
444 regionsOfServer.add(regions.get(i));
445 }
446 }
447
448 @Test (timeout=180000)
449 public void testClusterRegionLocations() {
450
451 List<ServerName> servers = getListOfServerNames(randomServers(10, 10));
452 List<HRegionInfo> regions = randomRegions(101);
453 Map<ServerName, List<HRegionInfo>> clusterState = new HashMap<ServerName, List<HRegionInfo>>();
454
455 assignRegions(regions, servers, clusterState);
456
457
458 RegionLocationFinder locationFinder = mock(RegionLocationFinder.class);
459
460
461
462 when(locationFinder.getTopBlockLocations(regions.get(0))).thenReturn(
463 Lists.newArrayList(servers.get(0)));
464 when(locationFinder.getTopBlockLocations(regions.get(1))).thenReturn(
465 Lists.newArrayList(servers.get(0), servers.get(1)));
466 when(locationFinder.getTopBlockLocations(regions.get(42))).thenReturn(
467 Lists.newArrayList(servers.get(4), servers.get(9), servers.get(5)));
468 when(locationFinder.getTopBlockLocations(regions.get(43))).thenReturn(
469 Lists.newArrayList(ServerName.valueOf("foo", 0, 0)));
470
471 BaseLoadBalancer.Cluster cluster = new Cluster(clusterState, null, locationFinder, null);
472
473 int r0 = ArrayUtils.indexOf(cluster.regions, regions.get(0));
474 int r1 = ArrayUtils.indexOf(cluster.regions, regions.get(1));
475 int r10 = ArrayUtils.indexOf(cluster.regions, regions.get(10));
476 int r42 = ArrayUtils.indexOf(cluster.regions, regions.get(42));
477 int r43 = ArrayUtils.indexOf(cluster.regions, regions.get(43));
478
479 int s0 = cluster.serversToIndex.get(servers.get(0).getHostAndPort());
480 int s1 = cluster.serversToIndex.get(servers.get(1).getHostAndPort());
481 int s4 = cluster.serversToIndex.get(servers.get(4).getHostAndPort());
482 int s5 = cluster.serversToIndex.get(servers.get(5).getHostAndPort());
483 int s9 = cluster.serversToIndex.get(servers.get(9).getHostAndPort());
484
485
486 assertEquals(1, cluster.regionLocations[r0].length);
487 assertEquals(s0, cluster.regionLocations[r0][0]);
488
489
490 assertEquals(2, cluster.regionLocations[r1].length);
491 assertEquals(s0, cluster.regionLocations[r1][0]);
492 assertEquals(s1, cluster.regionLocations[r1][1]);
493
494
495 assertEquals(0, cluster.regionLocations[r10].length);
496
497
498 assertEquals(3, cluster.regionLocations[r42].length);
499 assertEquals(s4, cluster.regionLocations[r42][0]);
500 assertEquals(s9, cluster.regionLocations[r42][1]);
501 assertEquals(s5, cluster.regionLocations[r42][2]);
502
503
504 assertEquals(1, cluster.regionLocations[r43].length);
505 assertEquals(-1, cluster.regionLocations[r43][0]);
506 }
507 }