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 java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.Deque;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.NavigableMap;
33 import java.util.Random;
34 import java.util.Set;
35 import java.util.TreeMap;
36
37 import org.apache.commons.lang.NotImplementedException;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.hadoop.conf.Configuration;
41 import org.apache.hadoop.hbase.ClusterStatus;
42 import org.apache.hadoop.hbase.HBaseIOException;
43 import org.apache.hadoop.hbase.HDFSBlocksDistribution;
44 import org.apache.hadoop.hbase.HRegionInfo;
45 import org.apache.hadoop.hbase.RegionLoad;
46 import org.apache.hadoop.hbase.ServerName;
47 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
48 import org.apache.hadoop.hbase.conf.ConfigurationObserver;
49 import org.apache.hadoop.hbase.master.LoadBalancer;
50 import org.apache.hadoop.hbase.master.MasterServices;
51 import org.apache.hadoop.hbase.master.RackManager;
52 import org.apache.hadoop.hbase.master.RegionPlan;
53 import org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer.Cluster.Action.Type;
54 import org.apache.hadoop.util.StringUtils;
55
56 import com.google.common.base.Joiner;
57 import com.google.common.collect.ArrayListMultimap;
58 import com.google.common.collect.Lists;
59 import com.google.common.collect.Sets;
60
61
62
63
64
65
66
67
68 public abstract class BaseLoadBalancer implements LoadBalancer {
69 private static final int MIN_SERVER_BALANCE = 2;
70 private volatile boolean stopped = false;
71
72 private static final List<HRegionInfo> EMPTY_REGION_LIST = new ArrayList<HRegionInfo>(0);
73
74 protected final RegionLocationFinder regionFinder = new RegionLocationFinder();
75
76 private static class DefaultRackManager extends RackManager {
77 @Override
78 public String getRack(ServerName server) {
79 return UNKNOWN_RACK;
80 }
81 }
82
83
84
85
86
87
88
89
90
91
92
93 protected static class Cluster {
94 ServerName[] servers;
95 String[] hosts;
96 String[] racks;
97 boolean multiServersPerHost = false;
98
99 ArrayList<String> tables;
100 HRegionInfo[] regions;
101 Deque<RegionLoad>[] regionLoads;
102 private RegionLocationFinder regionFinder;
103
104 int[][] regionLocations;
105
106 int[] serverIndexToHostIndex;
107 int[] serverIndexToRackIndex;
108
109 int[][] regionsPerServer;
110 int[][] regionsPerHost;
111 int[][] regionsPerRack;
112 int[][] primariesOfRegionsPerServer;
113 int[][] primariesOfRegionsPerHost;
114 int[][] primariesOfRegionsPerRack;
115
116 int[][] serversPerHost;
117 int[][] serversPerRack;
118 int[] regionIndexToServerIndex;
119 int[] initialRegionIndexToServerIndex;
120 int[] regionIndexToTableIndex;
121 int[][] numRegionsPerServerPerTable;
122 int[] numMaxRegionsPerTable;
123 int[] regionIndexToPrimaryIndex;
124 boolean hasRegionReplicas = false;
125
126 Integer[] serverIndicesSortedByRegionCount;
127 Integer[] serverIndicesSortedByLocality;
128
129 Map<String, Integer> serversToIndex;
130 Map<String, Integer> hostsToIndex;
131 Map<String, Integer> racksToIndex;
132 Map<String, Integer> tablesToIndex;
133 Map<HRegionInfo, Integer> regionsToIndex;
134 float[] localityPerServer;
135
136 int numServers;
137 int numHosts;
138 int numRacks;
139 int numTables;
140 int numRegions;
141
142 int numMovedRegions = 0;
143 Map<ServerName, List<HRegionInfo>> clusterState;
144
145 protected final RackManager rackManager;
146
147 protected Cluster(
148 Map<ServerName, List<HRegionInfo>> clusterState,
149 Map<String, Deque<RegionLoad>> loads,
150 RegionLocationFinder regionFinder,
151 RackManager rackManager) {
152 this(null, clusterState, loads, regionFinder,
153 rackManager);
154 }
155
156 @SuppressWarnings("unchecked")
157 protected Cluster(
158 Collection<HRegionInfo> unassignedRegions,
159 Map<ServerName, List<HRegionInfo>> clusterState,
160 Map<String, Deque<RegionLoad>> loads,
161 RegionLocationFinder regionFinder,
162 RackManager rackManager) {
163
164 if (unassignedRegions == null) {
165 unassignedRegions = EMPTY_REGION_LIST;
166 }
167
168 serversToIndex = new HashMap<String, Integer>();
169 hostsToIndex = new HashMap<String, Integer>();
170 racksToIndex = new HashMap<String, Integer>();
171 tablesToIndex = new HashMap<String, Integer>();
172
173
174 tables = new ArrayList<String>();
175 this.rackManager = rackManager != null ? rackManager : new DefaultRackManager();
176
177 numRegions = 0;
178
179 List<List<Integer>> serversPerHostList = new ArrayList<List<Integer>>();
180 List<List<Integer>> serversPerRackList = new ArrayList<List<Integer>>();
181 this.clusterState = clusterState;
182 this.regionFinder = regionFinder;
183
184
185
186 for (ServerName sn : clusterState.keySet()) {
187 if (serversToIndex.get(sn.getHostAndPort()) == null) {
188 serversToIndex.put(sn.getHostAndPort(), numServers++);
189 }
190 if (!hostsToIndex.containsKey(sn.getHostname())) {
191 hostsToIndex.put(sn.getHostname(), numHosts++);
192 serversPerHostList.add(new ArrayList<Integer>(1));
193 }
194
195 int serverIndex = serversToIndex.get(sn.getHostAndPort());
196 int hostIndex = hostsToIndex.get(sn.getHostname());
197 serversPerHostList.get(hostIndex).add(serverIndex);
198
199 String rack = this.rackManager.getRack(sn);
200 if (!racksToIndex.containsKey(rack)) {
201 racksToIndex.put(rack, numRacks++);
202 serversPerRackList.add(new ArrayList<Integer>());
203 }
204 int rackIndex = racksToIndex.get(rack);
205 serversPerRackList.get(rackIndex).add(serverIndex);
206 }
207
208
209 for (Entry<ServerName, List<HRegionInfo>> entry : clusterState.entrySet()) {
210 numRegions += entry.getValue().size();
211 }
212 numRegions += unassignedRegions.size();
213
214 regionsToIndex = new HashMap<HRegionInfo, Integer>(numRegions);
215 servers = new ServerName[numServers];
216 serversPerHost = new int[numHosts][];
217 serversPerRack = new int[numRacks][];
218 regions = new HRegionInfo[numRegions];
219 regionIndexToServerIndex = new int[numRegions];
220 initialRegionIndexToServerIndex = new int[numRegions];
221 regionIndexToTableIndex = new int[numRegions];
222 regionIndexToPrimaryIndex = new int[numRegions];
223 regionLoads = new Deque[numRegions];
224 regionLocations = new int[numRegions][];
225 serverIndicesSortedByRegionCount = new Integer[numServers];
226 serverIndicesSortedByLocality = new Integer[numServers];
227 localityPerServer = new float[numServers];
228
229 serverIndexToHostIndex = new int[numServers];
230 serverIndexToRackIndex = new int[numServers];
231 regionsPerServer = new int[numServers][];
232 regionsPerHost = new int[numHosts][];
233 regionsPerRack = new int[numRacks][];
234 primariesOfRegionsPerServer = new int[numServers][];
235 primariesOfRegionsPerHost = new int[numHosts][];
236 primariesOfRegionsPerRack = new int[numRacks][];
237
238 int tableIndex = 0, regionIndex = 0, regionPerServerIndex = 0;
239
240 for (Entry<ServerName, List<HRegionInfo>> entry : clusterState.entrySet()) {
241 int serverIndex = serversToIndex.get(entry.getKey().getHostAndPort());
242
243
244
245 if (servers[serverIndex] == null ||
246 servers[serverIndex].getStartcode() < entry.getKey().getStartcode()) {
247 servers[serverIndex] = entry.getKey();
248 }
249
250 if (regionsPerServer[serverIndex] != null) {
251
252
253 regionsPerServer[serverIndex] = new int[entry.getValue().size() + regionsPerServer[serverIndex].length];
254 } else {
255 regionsPerServer[serverIndex] = new int[entry.getValue().size()];
256 }
257 primariesOfRegionsPerServer[serverIndex] = new int[regionsPerServer[serverIndex].length];
258 serverIndicesSortedByRegionCount[serverIndex] = serverIndex;
259 serverIndicesSortedByLocality[serverIndex] = serverIndex;
260 }
261
262 hosts = new String[numHosts];
263 for (Entry<String, Integer> entry : hostsToIndex.entrySet()) {
264 hosts[entry.getValue()] = entry.getKey();
265 }
266 racks = new String[numRacks];
267 for (Entry<String, Integer> entry : racksToIndex.entrySet()) {
268 racks[entry.getValue()] = entry.getKey();
269 }
270
271 for (Entry<ServerName, List<HRegionInfo>> entry : clusterState.entrySet()) {
272 int serverIndex = serversToIndex.get(entry.getKey().getHostAndPort());
273 regionPerServerIndex = 0;
274
275 int hostIndex = hostsToIndex.get(entry.getKey().getHostname());
276 serverIndexToHostIndex[serverIndex] = hostIndex;
277
278 int rackIndex = racksToIndex.get(this.rackManager.getRack(entry.getKey()));
279 serverIndexToRackIndex[serverIndex] = rackIndex;
280
281 for (HRegionInfo region : entry.getValue()) {
282 registerRegion(region, regionIndex, serverIndex, loads, regionFinder);
283
284 regionsPerServer[serverIndex][regionPerServerIndex++] = regionIndex;
285 regionIndex++;
286 }
287 }
288 for (HRegionInfo region : unassignedRegions) {
289 registerRegion(region, regionIndex, -1, loads, regionFinder);
290 regionIndex++;
291 }
292
293 for (int i = 0; i < serversPerHostList.size(); i++) {
294 serversPerHost[i] = new int[serversPerHostList.get(i).size()];
295 for (int j = 0; j < serversPerHost[i].length; j++) {
296 serversPerHost[i][j] = serversPerHostList.get(i).get(j);
297 }
298 if (serversPerHost[i].length > 1) {
299 multiServersPerHost = true;
300 }
301 }
302
303 for (int i = 0; i < serversPerRackList.size(); i++) {
304 serversPerRack[i] = new int[serversPerRackList.get(i).size()];
305 for (int j = 0; j < serversPerRack[i].length; j++) {
306 serversPerRack[i][j] = serversPerRackList.get(i).get(j);
307 }
308 }
309
310 numTables = tables.size();
311 numRegionsPerServerPerTable = new int[numServers][numTables];
312
313 for (int i = 0; i < numServers; i++) {
314 for (int j = 0; j < numTables; j++) {
315 numRegionsPerServerPerTable[i][j] = 0;
316 }
317 }
318
319 for (int i=0; i < regionIndexToServerIndex.length; i++) {
320 if (regionIndexToServerIndex[i] >= 0) {
321 numRegionsPerServerPerTable[regionIndexToServerIndex[i]][regionIndexToTableIndex[i]]++;
322 }
323 }
324
325 numMaxRegionsPerTable = new int[numTables];
326 for (int serverIndex = 0 ; serverIndex < numRegionsPerServerPerTable.length; serverIndex++) {
327 for (tableIndex = 0 ; tableIndex < numRegionsPerServerPerTable[serverIndex].length; tableIndex++) {
328 if (numRegionsPerServerPerTable[serverIndex][tableIndex] > numMaxRegionsPerTable[tableIndex]) {
329 numMaxRegionsPerTable[tableIndex] = numRegionsPerServerPerTable[serverIndex][tableIndex];
330 }
331 }
332 }
333
334 for (int i = 0; i < regions.length; i ++) {
335 HRegionInfo info = regions[i];
336 if (RegionReplicaUtil.isDefaultReplica(info)) {
337 regionIndexToPrimaryIndex[i] = i;
338 } else {
339 hasRegionReplicas = true;
340 HRegionInfo primaryInfo = RegionReplicaUtil.getRegionInfoForDefaultReplica(info);
341 regionIndexToPrimaryIndex[i] =
342 regionsToIndex.containsKey(primaryInfo) ?
343 regionsToIndex.get(primaryInfo):
344 -1;
345 }
346 }
347
348 for (int i = 0; i < regionsPerServer.length; i++) {
349 primariesOfRegionsPerServer[i] = new int[regionsPerServer[i].length];
350 for (int j = 0; j < regionsPerServer[i].length; j++) {
351 int primaryIndex = regionIndexToPrimaryIndex[regionsPerServer[i][j]];
352 primariesOfRegionsPerServer[i][j] = primaryIndex;
353 }
354
355 Arrays.sort(primariesOfRegionsPerServer[i]);
356 }
357
358
359 if (multiServersPerHost) {
360 for (int i = 0 ; i < serversPerHost.length; i++) {
361 int numRegionsPerHost = 0;
362 for (int j = 0; j < serversPerHost[i].length; j++) {
363 numRegionsPerHost += regionsPerServer[serversPerHost[i][j]].length;
364 }
365 regionsPerHost[i] = new int[numRegionsPerHost];
366 primariesOfRegionsPerHost[i] = new int[numRegionsPerHost];
367 }
368 for (int i = 0 ; i < serversPerHost.length; i++) {
369 int numRegionPerHostIndex = 0;
370 for (int j = 0; j < serversPerHost[i].length; j++) {
371 for (int k = 0; k < regionsPerServer[serversPerHost[i][j]].length; k++) {
372 int region = regionsPerServer[serversPerHost[i][j]][k];
373 regionsPerHost[i][numRegionPerHostIndex] = region;
374 int primaryIndex = regionIndexToPrimaryIndex[region];
375 primariesOfRegionsPerHost[i][numRegionPerHostIndex] = primaryIndex;
376 numRegionPerHostIndex++;
377 }
378 }
379
380 Arrays.sort(primariesOfRegionsPerHost[i]);
381 }
382 }
383
384
385 if (numRacks > 1) {
386 for (int i = 0 ; i < serversPerRack.length; i++) {
387 int numRegionsPerRack = 0;
388 for (int j = 0; j < serversPerRack[i].length; j++) {
389 numRegionsPerRack += regionsPerServer[serversPerRack[i][j]].length;
390 }
391 regionsPerRack[i] = new int[numRegionsPerRack];
392 primariesOfRegionsPerRack[i] = new int[numRegionsPerRack];
393 }
394
395 for (int i = 0 ; i < serversPerRack.length; i++) {
396 int numRegionPerRackIndex = 0;
397 for (int j = 0; j < serversPerRack[i].length; j++) {
398 for (int k = 0; k < regionsPerServer[serversPerRack[i][j]].length; k++) {
399 int region = regionsPerServer[serversPerRack[i][j]][k];
400 regionsPerRack[i][numRegionPerRackIndex] = region;
401 int primaryIndex = regionIndexToPrimaryIndex[region];
402 primariesOfRegionsPerRack[i][numRegionPerRackIndex] = primaryIndex;
403 numRegionPerRackIndex++;
404 }
405 }
406
407 Arrays.sort(primariesOfRegionsPerRack[i]);
408 }
409 }
410 }
411
412
413 private void registerRegion(HRegionInfo region, int regionIndex, int serverIndex,
414 Map<String, Deque<RegionLoad>> loads, RegionLocationFinder regionFinder) {
415 String tableName = region.getTable().getNameAsString();
416 if (!tablesToIndex.containsKey(tableName)) {
417 tables.add(tableName);
418 tablesToIndex.put(tableName, tablesToIndex.size());
419 }
420 int tableIndex = tablesToIndex.get(tableName);
421
422 regionsToIndex.put(region, regionIndex);
423 regions[regionIndex] = region;
424 regionIndexToServerIndex[regionIndex] = serverIndex;
425 initialRegionIndexToServerIndex[regionIndex] = serverIndex;
426 regionIndexToTableIndex[regionIndex] = tableIndex;
427
428
429 if (loads != null) {
430 Deque<RegionLoad> rl = loads.get(region.getRegionNameAsString());
431
432 if (rl == null) {
433
434 rl = loads.get(region.getEncodedName());
435 }
436 regionLoads[regionIndex] = rl;
437 }
438
439 if (regionFinder != null) {
440
441 List<ServerName> loc = regionFinder.getTopBlockLocations(region);
442 regionLocations[regionIndex] = new int[loc.size()];
443 for (int i=0; i < loc.size(); i++) {
444 regionLocations[regionIndex][i] =
445 loc.get(i) == null ? -1 :
446 (serversToIndex.get(loc.get(i).getHostAndPort()) == null ? -1
447 : serversToIndex.get(loc.get(i).getHostAndPort()));
448 }
449 }
450 }
451
452
453 public static class Action {
454 public static enum Type {
455 ASSIGN_REGION,
456 MOVE_REGION,
457 SWAP_REGIONS,
458 NULL,
459 }
460
461 public Type type;
462 public Action (Type type) {this.type = type;}
463
464 public Action undoAction() { return this; }
465 @Override
466 public String toString() { return type + ":";}
467 }
468
469 public static class AssignRegionAction extends Action {
470 public int region;
471 public int server;
472 public AssignRegionAction(int region, int server) {
473 super(Type.ASSIGN_REGION);
474 this.region = region;
475 this.server = server;
476 }
477 @Override
478 public Action undoAction() {
479
480
481 throw new NotImplementedException();
482 }
483 @Override
484 public String toString() {
485 return type + ": " + region + ":" + server;
486 }
487 }
488
489 public static class MoveRegionAction extends Action {
490 public int region;
491 public int fromServer;
492 public int toServer;
493
494 public MoveRegionAction(int region, int fromServer, int toServer) {
495 super(Type.MOVE_REGION);
496 this.fromServer = fromServer;
497 this.region = region;
498 this.toServer = toServer;
499 }
500 @Override
501 public Action undoAction() {
502 return new MoveRegionAction (region, toServer, fromServer);
503 }
504 @Override
505 public String toString() {
506 return type + ": " + region + ":" + fromServer + " -> " + toServer;
507 }
508 }
509
510 public static class SwapRegionsAction extends Action {
511 public int fromServer;
512 public int fromRegion;
513 public int toServer;
514 public int toRegion;
515 public SwapRegionsAction(int fromServer, int fromRegion, int toServer, int toRegion) {
516 super(Type.SWAP_REGIONS);
517 this.fromServer = fromServer;
518 this.fromRegion = fromRegion;
519 this.toServer = toServer;
520 this.toRegion = toRegion;
521 }
522 @Override
523 public Action undoAction() {
524 return new SwapRegionsAction (fromServer, toRegion, toServer, fromRegion);
525 }
526 @Override
527 public String toString() {
528 return type + ": " + fromRegion + ":" + fromServer + " <-> " + toRegion + ":" + toServer;
529 }
530 }
531
532 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NM_FIELD_NAMING_CONVENTION",
533 justification="Mistake. Too disruptive to change now")
534 public static final Action NullAction = new Action(Type.NULL);
535
536 public void doAction(Action action) {
537 switch (action.type) {
538 case NULL: break;
539 case ASSIGN_REGION:
540
541 assert action instanceof AssignRegionAction: action.getClass();
542 AssignRegionAction ar = (AssignRegionAction) action;
543 regionsPerServer[ar.server] = addRegion(regionsPerServer[ar.server], ar.region);
544 regionMoved(ar.region, -1, ar.server);
545 break;
546 case MOVE_REGION:
547 assert action instanceof MoveRegionAction: action.getClass();
548 MoveRegionAction mra = (MoveRegionAction) action;
549 regionsPerServer[mra.fromServer] = removeRegion(regionsPerServer[mra.fromServer], mra.region);
550 regionsPerServer[mra.toServer] = addRegion(regionsPerServer[mra.toServer], mra.region);
551 regionMoved(mra.region, mra.fromServer, mra.toServer);
552 break;
553 case SWAP_REGIONS:
554 assert action instanceof SwapRegionsAction: action.getClass();
555 SwapRegionsAction a = (SwapRegionsAction) action;
556 regionsPerServer[a.fromServer] = replaceRegion(regionsPerServer[a.fromServer], a.fromRegion, a.toRegion);
557 regionsPerServer[a.toServer] = replaceRegion(regionsPerServer[a.toServer], a.toRegion, a.fromRegion);
558 regionMoved(a.fromRegion, a.fromServer, a.toServer);
559 regionMoved(a.toRegion, a.toServer, a.fromServer);
560 break;
561 default:
562 throw new RuntimeException("Uknown action:" + action.type);
563 }
564 }
565
566
567
568
569
570
571
572
573 boolean wouldLowerAvailability(HRegionInfo regionInfo, ServerName serverName) {
574 if (!serversToIndex.containsKey(serverName.getHostAndPort())) {
575 return false;
576 }
577 int server = serversToIndex.get(serverName.getHostAndPort());
578 int region = regionsToIndex.get(regionInfo);
579
580 int primary = regionIndexToPrimaryIndex[region];
581
582
583
584
585 if (contains(primariesOfRegionsPerServer[server], primary)) {
586
587 for (int i = 0; i < primariesOfRegionsPerServer.length; i++) {
588 if (i != server && !contains(primariesOfRegionsPerServer[i], primary)) {
589 return true;
590 }
591 }
592 return false;
593 }
594
595
596 if (multiServersPerHost) {
597 int host = serverIndexToHostIndex[server];
598 if (contains(primariesOfRegionsPerHost[host], primary)) {
599
600 for (int i = 0; i < primariesOfRegionsPerHost.length; i++) {
601 if (i != host && !contains(primariesOfRegionsPerHost[i], primary)) {
602 return true;
603 }
604 }
605 return false;
606 }
607 }
608
609
610 if (numRacks > 1) {
611 int rack = serverIndexToRackIndex[server];
612 if (contains(primariesOfRegionsPerRack[rack], primary)) {
613
614 for (int i = 0; i < primariesOfRegionsPerRack.length; i++) {
615 if (i != rack && !contains(primariesOfRegionsPerRack[i], primary)) {
616 return true;
617 }
618 }
619 return false;
620 }
621 }
622 return false;
623 }
624
625 void doAssignRegion(HRegionInfo regionInfo, ServerName serverName) {
626 if (!serversToIndex.containsKey(serverName.getHostAndPort())) {
627 return;
628 }
629 int server = serversToIndex.get(serverName.getHostAndPort());
630 int region = regionsToIndex.get(regionInfo);
631 doAction(new AssignRegionAction(region, server));
632 }
633
634 void regionMoved(int region, int oldServer, int newServer) {
635 regionIndexToServerIndex[region] = newServer;
636 if (initialRegionIndexToServerIndex[region] == newServer) {
637 numMovedRegions--;
638 } else if (oldServer >= 0 && initialRegionIndexToServerIndex[region] == oldServer) {
639 numMovedRegions++;
640 }
641 int tableIndex = regionIndexToTableIndex[region];
642 if (oldServer >= 0) {
643 numRegionsPerServerPerTable[oldServer][tableIndex]--;
644 }
645 numRegionsPerServerPerTable[newServer][tableIndex]++;
646
647
648 if (numRegionsPerServerPerTable[newServer][tableIndex] > numMaxRegionsPerTable[tableIndex]) {
649 numMaxRegionsPerTable[tableIndex] = numRegionsPerServerPerTable[newServer][tableIndex];
650 } else if (oldServer >= 0 && (numRegionsPerServerPerTable[oldServer][tableIndex] + 1)
651 == numMaxRegionsPerTable[tableIndex]) {
652
653 numMaxRegionsPerTable[tableIndex] = 0;
654 for (int serverIndex = 0 ; serverIndex < numRegionsPerServerPerTable.length; serverIndex++) {
655 if (numRegionsPerServerPerTable[serverIndex][tableIndex] > numMaxRegionsPerTable[tableIndex]) {
656 numMaxRegionsPerTable[tableIndex] = numRegionsPerServerPerTable[serverIndex][tableIndex];
657 }
658 }
659 }
660
661
662 int primary = regionIndexToPrimaryIndex[region];
663 if (oldServer >= 0) {
664 primariesOfRegionsPerServer[oldServer] = removeRegion(
665 primariesOfRegionsPerServer[oldServer], primary);
666 }
667 primariesOfRegionsPerServer[newServer] = addRegionSorted(
668 primariesOfRegionsPerServer[newServer], primary);
669
670
671 if (multiServersPerHost) {
672 int oldHost = oldServer >= 0 ? serverIndexToHostIndex[oldServer] : -1;
673 int newHost = serverIndexToHostIndex[newServer];
674 if (newHost != oldHost) {
675 regionsPerHost[newHost] = addRegion(regionsPerHost[newHost], region);
676 primariesOfRegionsPerHost[newHost] = addRegionSorted(primariesOfRegionsPerHost[newHost], primary);
677 if (oldHost >= 0) {
678 regionsPerHost[oldHost] = removeRegion(regionsPerHost[oldHost], region);
679 primariesOfRegionsPerHost[oldHost] = removeRegion(
680 primariesOfRegionsPerHost[oldHost], primary);
681 }
682 }
683 }
684
685
686 if (numRacks > 1) {
687 int oldRack = oldServer >= 0 ? serverIndexToRackIndex[oldServer] : -1;
688 int newRack = serverIndexToRackIndex[newServer];
689 if (newRack != oldRack) {
690 regionsPerRack[newRack] = addRegion(regionsPerRack[newRack], region);
691 primariesOfRegionsPerRack[newRack] = addRegionSorted(primariesOfRegionsPerRack[newRack], primary);
692 if (oldRack >= 0) {
693 regionsPerRack[oldRack] = removeRegion(regionsPerRack[oldRack], region);
694 primariesOfRegionsPerRack[oldRack] = removeRegion(
695 primariesOfRegionsPerRack[oldRack], primary);
696 }
697 }
698 }
699 }
700
701 int[] removeRegion(int[] regions, int regionIndex) {
702
703 int[] newRegions = new int[regions.length - 1];
704 int i = 0;
705 for (i = 0; i < regions.length; i++) {
706 if (regions[i] == regionIndex) {
707 break;
708 }
709 newRegions[i] = regions[i];
710 }
711 System.arraycopy(regions, i+1, newRegions, i, newRegions.length - i);
712 return newRegions;
713 }
714
715 int[] addRegion(int[] regions, int regionIndex) {
716 int[] newRegions = new int[regions.length + 1];
717 System.arraycopy(regions, 0, newRegions, 0, regions.length);
718 newRegions[newRegions.length - 1] = regionIndex;
719 return newRegions;
720 }
721
722 int[] addRegionSorted(int[] regions, int regionIndex) {
723 int[] newRegions = new int[regions.length + 1];
724 int i = 0;
725 for (i = 0; i < regions.length; i++) {
726 if (regions[i] > regionIndex) {
727 break;
728 }
729 }
730 System.arraycopy(regions, 0, newRegions, 0, i);
731 System.arraycopy(regions, i, newRegions, i+1, regions.length - i);
732 newRegions[i] = regionIndex;
733
734 return newRegions;
735 }
736
737 int[] replaceRegion(int[] regions, int regionIndex, int newRegionIndex) {
738 int i = 0;
739 for (i = 0; i < regions.length; i++) {
740 if (regions[i] == regionIndex) {
741 regions[i] = newRegionIndex;
742 break;
743 }
744 }
745 return regions;
746 }
747
748 void sortServersByRegionCount() {
749 Arrays.sort(serverIndicesSortedByRegionCount, numRegionsComparator);
750 }
751
752 int getNumRegions(int server) {
753 return regionsPerServer[server].length;
754 }
755
756 boolean contains(int[] arr, int val) {
757 return Arrays.binarySearch(arr, val) >= 0;
758 }
759
760 private Comparator<Integer> numRegionsComparator = new Comparator<Integer>() {
761 @Override
762 public int compare(Integer integer, Integer integer2) {
763 return Integer.compare(getNumRegions(integer), getNumRegions(integer2));
764 }
765 };
766
767 void sortServersByLocality() {
768 Arrays.sort(serverIndicesSortedByLocality, localityComparator);
769 }
770
771 float getLocality(int server) {
772 return localityPerServer[server];
773 }
774
775 private Comparator<Integer> localityComparator = new Comparator<Integer>() {
776 @Override
777 public int compare(Integer integer, Integer integer2) {
778 return Float.compare(getLocality(integer), getLocality(integer2));
779 }
780 };
781
782 int getLowestLocalityRegionServer() {
783 if (regionFinder == null) {
784 return -1;
785 } else {
786 sortServersByLocality();
787
788 int i = 0;
789 int lowestLocalityServerIndex = serverIndicesSortedByLocality[i];
790 while (localityPerServer[lowestLocalityServerIndex] == 0
791 && (regionsPerServer[lowestLocalityServerIndex].length == 0)) {
792 i++;
793 lowestLocalityServerIndex = serverIndicesSortedByLocality[i];
794 }
795 if (LOG.isTraceEnabled()) {
796 LOG.trace("Lowest locality region server with non zero regions is "
797 + servers[lowestLocalityServerIndex].getHostname() + " with locality "
798 + localityPerServer[lowestLocalityServerIndex]);
799 }
800 return lowestLocalityServerIndex;
801 }
802 }
803
804 int getLowestLocalityRegionOnServer(int serverIndex) {
805 if (regionFinder != null) {
806 float lowestLocality = 1.0f;
807 int lowestLocalityRegionIndex = 0;
808 if (regionsPerServer[serverIndex].length == 0) {
809
810 return -1;
811 }
812 for (int j = 0; j < regionsPerServer[serverIndex].length; j++) {
813 int regionIndex = regionsPerServer[serverIndex][j];
814 HDFSBlocksDistribution distribution = regionFinder
815 .getBlockDistribution(regions[regionIndex]);
816 float locality = distribution.getBlockLocalityIndex(servers[serverIndex].getHostname());
817 if (locality < lowestLocality) {
818 lowestLocality = locality;
819 lowestLocalityRegionIndex = j;
820 }
821 }
822 if (LOG.isTraceEnabled()) {
823 LOG.trace(" Lowest locality region index is " + lowestLocalityRegionIndex
824 + " and its region server contains " + regionsPerServer[serverIndex].length
825 + " regions");
826 }
827 return regionsPerServer[serverIndex][lowestLocalityRegionIndex];
828 } else {
829 return -1;
830 }
831 }
832
833 float getLocalityOfRegion(int region, int server) {
834 if (regionFinder != null) {
835 HDFSBlocksDistribution distribution = regionFinder.getBlockDistribution(regions[region]);
836 return distribution.getBlockLocalityIndex(servers[server].getHostname());
837 } else {
838 return 0f;
839 }
840 }
841
842 int getLeastLoadedTopServerForRegion(int region) {
843 if (regionFinder != null) {
844 List<ServerName> topLocalServers = regionFinder.getTopBlockLocations(regions[region]);
845 int leastLoadedServerIndex = -1;
846 int load = Integer.MAX_VALUE;
847 for (ServerName sn : topLocalServers) {
848 if (!serversToIndex.containsKey(sn.getHostAndPort())) {
849 continue;
850 }
851 int index = serversToIndex.get(sn.getHostAndPort());
852 if (regionsPerServer[index] == null) {
853 continue;
854 }
855 int tempLoad = regionsPerServer[index].length;
856 if (tempLoad <= load) {
857 leastLoadedServerIndex = index;
858 load = tempLoad;
859 }
860 }
861 return leastLoadedServerIndex;
862 } else {
863 return -1;
864 }
865 }
866
867 void calculateRegionServerLocalities() {
868 if (regionFinder == null) {
869 LOG.warn("Region location finder found null, skipping locality calculations.");
870 return;
871 }
872 for (int i = 0; i < regionsPerServer.length; i++) {
873 HDFSBlocksDistribution distribution = new HDFSBlocksDistribution();
874 if (regionsPerServer[i].length > 0) {
875 for (int j = 0; j < regionsPerServer[i].length; j++) {
876 int regionIndex = regionsPerServer[i][j];
877 distribution.add(regionFinder.getBlockDistribution(regions[regionIndex]));
878 }
879 } else {
880 LOG.debug("Server " + servers[i].getHostname() + " had 0 regions.");
881 }
882 localityPerServer[i] = distribution.getBlockLocalityIndex(servers[i].getHostname());
883 }
884 }
885
886 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="SBSC_USE_STRINGBUFFER_CONCATENATION",
887 justification="Not important but should be fixed")
888 @Override
889 public String toString() {
890 String desc = "Cluster{" +
891 "servers=[";
892 for(ServerName sn:servers) {
893 desc += sn.getHostAndPort() + ", ";
894 }
895 desc +=
896 ", serverIndicesSortedByRegionCount="+
897 Arrays.toString(serverIndicesSortedByRegionCount) +
898 ", regionsPerServer=[";
899
900 for (int[]r:regionsPerServer) {
901 desc += Arrays.toString(r);
902 }
903 desc += "]" +
904 ", numMaxRegionsPerTable=" +
905 Arrays.toString(numMaxRegionsPerTable) +
906 ", numRegions=" +
907 numRegions +
908 ", numServers=" +
909 numServers +
910 ", numTables=" +
911 numTables +
912 ", numMovedRegions=" +
913 numMovedRegions +
914 '}';
915 return desc;
916 }
917 }
918
919
920 protected float slop;
921 protected Configuration config;
922 protected RackManager rackManager;
923 private static final Random RANDOM = new Random(System.currentTimeMillis());
924 private static final Log LOG = LogFactory.getLog(BaseLoadBalancer.class);
925
926 public static final String TABLES_ON_MASTER =
927 "hbase.balancer.tablesOnMaster";
928
929 protected final Set<String> tablesOnMaster = new HashSet<String>();
930 protected final MetricsBalancer metricsBalancer = new MetricsBalancer();
931 protected ClusterStatus clusterStatus = null;
932 protected ServerName masterServerName;
933 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="IS2_INCONSISTENT_SYNC",
934 justification="The services is just assigned once when master start")
935 protected MasterServices services;
936
937 protected static String[] getTablesOnMaster(Configuration conf) {
938 String valueString = conf.get(TABLES_ON_MASTER);
939 if (valueString != null) {
940 valueString = valueString.trim();
941 }
942 if (valueString == null || valueString.equalsIgnoreCase("none")) {
943 return null;
944 }
945 return StringUtils.getStrings(valueString);
946 }
947
948
949
950
951 public static boolean tablesOnMaster(Configuration conf) {
952 String[] tables = getTablesOnMaster(conf);
953 return tables != null && tables.length > 0;
954 }
955
956 @Override
957 public void setConf(Configuration conf) {
958 setSlop(conf);
959 if (slop < 0) slop = 0;
960 else if (slop > 1) slop = 1;
961
962 this.config = conf;
963 String[] tables = getTablesOnMaster(conf);
964 if (tables != null && tables.length > 0) {
965 Collections.addAll(tablesOnMaster, tables);
966 }
967 this.rackManager = new RackManager(getConf());
968 regionFinder.setConf(conf);
969 }
970
971 protected void setSlop(Configuration conf) {
972 this.slop = conf.getFloat("hbase.regions.slop", (float) 0.2);
973 }
974
975
976
977
978
979 public boolean shouldBeOnMaster(HRegionInfo region) {
980 return tablesOnMaster.contains(region.getTable().getNameAsString())
981 && region.getReplicaId() == HRegionInfo.DEFAULT_REPLICA_ID;
982 }
983
984
985
986
987 protected List<RegionPlan> balanceMasterRegions(
988 Map<ServerName, List<HRegionInfo>> clusterMap) {
989 if (masterServerName == null
990 || clusterMap == null || clusterMap.size() <= 1) return null;
991 List<RegionPlan> plans = null;
992 List<HRegionInfo> regions = clusterMap.get(masterServerName);
993 if (regions != null) {
994 Iterator<ServerName> keyIt = null;
995 for (HRegionInfo region: regions) {
996 if (shouldBeOnMaster(region)) continue;
997
998
999 if (keyIt == null || !keyIt.hasNext()) {
1000 keyIt = clusterMap.keySet().iterator();
1001 }
1002 ServerName dest = keyIt.next();
1003 if (masterServerName.equals(dest)) {
1004 if (!keyIt.hasNext()) {
1005 keyIt = clusterMap.keySet().iterator();
1006 }
1007 dest = keyIt.next();
1008 }
1009
1010
1011 RegionPlan plan = new RegionPlan(region, masterServerName, dest);
1012 if (plans == null) {
1013 plans = new ArrayList<RegionPlan>();
1014 }
1015 plans.add(plan);
1016 }
1017 }
1018 for (Map.Entry<ServerName, List<HRegionInfo>> server: clusterMap.entrySet()) {
1019 if (masterServerName.equals(server.getKey())) continue;
1020 for (HRegionInfo region: server.getValue()) {
1021 if (!shouldBeOnMaster(region)) continue;
1022
1023
1024 RegionPlan plan = new RegionPlan(region, server.getKey(), masterServerName);
1025 if (plans == null) {
1026 plans = new ArrayList<RegionPlan>();
1027 }
1028 plans.add(plan);
1029 }
1030 }
1031 return plans;
1032 }
1033
1034
1035
1036
1037 protected Map<ServerName, List<HRegionInfo>> assignMasterRegions(
1038 Collection<HRegionInfo> regions, List<ServerName> servers) {
1039 if (servers == null || regions == null || regions.isEmpty()) {
1040 return null;
1041 }
1042 Map<ServerName, List<HRegionInfo>> assignments
1043 = new TreeMap<ServerName, List<HRegionInfo>>();
1044 if (masterServerName != null && servers.contains(masterServerName)) {
1045 assignments.put(masterServerName, new ArrayList<HRegionInfo>());
1046 for (HRegionInfo region: regions) {
1047 if (shouldBeOnMaster(region)) {
1048 assignments.get(masterServerName).add(region);
1049 }
1050 }
1051 }
1052 return assignments;
1053 }
1054
1055 @Override
1056 public Configuration getConf() {
1057 return this.config;
1058 }
1059
1060 @Override
1061 public synchronized void setClusterStatus(ClusterStatus st) {
1062 this.clusterStatus = st;
1063 regionFinder.setClusterStatus(st);
1064 }
1065
1066 @Override
1067 public void setMasterServices(MasterServices masterServices) {
1068 masterServerName = masterServices.getServerName();
1069 this.services = masterServices;
1070 this.regionFinder.setServices(masterServices);
1071 }
1072
1073 public void setRackManager(RackManager rackManager) {
1074 this.rackManager = rackManager;
1075 }
1076
1077 protected boolean needsBalance(Cluster c) {
1078 ClusterLoadState cs = new ClusterLoadState(c.clusterState);
1079 if (cs.getNumServers() < MIN_SERVER_BALANCE) {
1080 if (LOG.isDebugEnabled()) {
1081 LOG.debug("Not running balancer because only " + cs.getNumServers()
1082 + " active regionserver(s)");
1083 }
1084 return false;
1085 }
1086 if(areSomeRegionReplicasColocated(c)) return true;
1087
1088
1089 float average = cs.getLoadAverage();
1090 int floor = (int) Math.floor(average * (1 - slop));
1091 int ceiling = (int) Math.ceil(average * (1 + slop));
1092 if (!(cs.getMaxLoad() > ceiling || cs.getMinLoad() < floor)) {
1093 NavigableMap<ServerAndLoad, List<HRegionInfo>> serversByLoad = cs.getServersByLoad();
1094 if (LOG.isTraceEnabled()) {
1095
1096 LOG.trace("Skipping load balancing because balanced cluster; " +
1097 "servers=" + cs.getNumServers() +
1098 " regions=" + cs.getNumRegions() + " average=" + average +
1099 " mostloaded=" + serversByLoad.lastKey().getLoad() +
1100 " leastloaded=" + serversByLoad.firstKey().getLoad());
1101 }
1102 return false;
1103 }
1104 return true;
1105 }
1106
1107
1108
1109
1110
1111
1112
1113
1114 protected boolean areSomeRegionReplicasColocated(Cluster c) {
1115 return false;
1116 }
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135 @Override
1136 public Map<ServerName, List<HRegionInfo>> roundRobinAssignment(List<HRegionInfo> regions,
1137 List<ServerName> servers) {
1138 metricsBalancer.incrMiscInvocations();
1139 Map<ServerName, List<HRegionInfo>> assignments = assignMasterRegions(regions, servers);
1140 if (assignments != null && !assignments.isEmpty()) {
1141 servers = new ArrayList<ServerName>(servers);
1142
1143 servers.remove(masterServerName);
1144 List<HRegionInfo> masterRegions = assignments.get(masterServerName);
1145 if (!masterRegions.isEmpty()) {
1146 regions = new ArrayList<HRegionInfo>(regions);
1147 for (HRegionInfo region: masterRegions) {
1148 regions.remove(region);
1149 }
1150 }
1151 }
1152 if (regions == null || regions.isEmpty()) {
1153 return assignments;
1154 }
1155
1156 int numServers = servers == null ? 0 : servers.size();
1157 if (numServers == 0) {
1158 LOG.warn("Wanted to do round robin assignment but no servers to assign to");
1159 return null;
1160 }
1161
1162
1163
1164
1165
1166
1167 if (numServers == 1) {
1168 ServerName server = servers.get(0);
1169 assignments.put(server, new ArrayList<HRegionInfo>(regions));
1170 return assignments;
1171 }
1172
1173 Cluster cluster = createCluster(servers, regions);
1174 List<HRegionInfo> unassignedRegions = new ArrayList<HRegionInfo>();
1175
1176 roundRobinAssignment(cluster, regions, unassignedRegions,
1177 servers, assignments);
1178
1179 List<HRegionInfo> lastFewRegions = new ArrayList<HRegionInfo>();
1180
1181 int serverIdx = RANDOM.nextInt(numServers);
1182 for (HRegionInfo region : unassignedRegions) {
1183 boolean assigned = false;
1184 for (int j = 0; j < numServers; j++) {
1185 ServerName serverName = servers.get((j + serverIdx) % numServers);
1186 if (!cluster.wouldLowerAvailability(region, serverName)) {
1187 List<HRegionInfo> serverRegions = assignments.get(serverName);
1188 if (serverRegions == null) {
1189 serverRegions = new ArrayList<HRegionInfo>();
1190 assignments.put(serverName, serverRegions);
1191 }
1192 serverRegions.add(region);
1193 cluster.doAssignRegion(region, serverName);
1194 serverIdx = (j + serverIdx + 1) % numServers;
1195 assigned = true;
1196 break;
1197 }
1198 }
1199 if (!assigned) {
1200 lastFewRegions.add(region);
1201 }
1202 }
1203
1204
1205 for (HRegionInfo region : lastFewRegions) {
1206 int i = RANDOM.nextInt(numServers);
1207 ServerName server = servers.get(i);
1208 List<HRegionInfo> serverRegions = assignments.get(server);
1209 if (serverRegions == null) {
1210 serverRegions = new ArrayList<HRegionInfo>();
1211 assignments.put(server, serverRegions);
1212 }
1213 serverRegions.add(region);
1214 cluster.doAssignRegion(region, server);
1215 }
1216 return assignments;
1217 }
1218
1219 protected Cluster createCluster(List<ServerName> servers,
1220 Collection<HRegionInfo> regions) {
1221
1222
1223
1224
1225 Map<ServerName, List<HRegionInfo>> clusterState = getRegionAssignmentsByServer(regions);
1226
1227 for (ServerName server : servers) {
1228 if (!clusterState.containsKey(server)) {
1229 clusterState.put(server, EMPTY_REGION_LIST);
1230 }
1231 }
1232 return new Cluster(regions, clusterState, null, this.regionFinder,
1233 rackManager);
1234 }
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253 @Override
1254 public Map<HRegionInfo, ServerName> immediateAssignment(List<HRegionInfo> regions,
1255 List<ServerName> servers) {
1256 metricsBalancer.incrMiscInvocations();
1257 if (servers == null || servers.isEmpty()) {
1258 LOG.warn("Wanted to do random assignment but no servers to assign to");
1259 return null;
1260 }
1261
1262 Map<HRegionInfo, ServerName> assignments = new TreeMap<HRegionInfo, ServerName>();
1263 for (HRegionInfo region : regions) {
1264 assignments.put(region, randomAssignment(region, servers));
1265 }
1266 return assignments;
1267 }
1268
1269
1270
1271
1272 @Override
1273 public ServerName randomAssignment(HRegionInfo regionInfo, List<ServerName> servers) {
1274 metricsBalancer.incrMiscInvocations();
1275 if (servers != null && servers.contains(masterServerName)) {
1276 if (shouldBeOnMaster(regionInfo)) {
1277 return masterServerName;
1278 }
1279 servers = new ArrayList<ServerName>(servers);
1280
1281 servers.remove(masterServerName);
1282 }
1283
1284 int numServers = servers == null ? 0 : servers.size();
1285 if (numServers == 0) {
1286 LOG.warn("Wanted to do retain assignment but no servers to assign to");
1287 return null;
1288 }
1289 if (numServers == 1) {
1290 return servers.get(0);
1291 }
1292
1293 List<HRegionInfo> regions = Lists.newArrayList(regionInfo);
1294 Cluster cluster = createCluster(servers, regions);
1295 return randomAssignment(cluster, regionInfo, servers);
1296 }
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315 @Override
1316 public Map<ServerName, List<HRegionInfo>> retainAssignment(Map<HRegionInfo, ServerName> regions,
1317 List<ServerName> servers) {
1318
1319 metricsBalancer.incrMiscInvocations();
1320 Map<ServerName, List<HRegionInfo>> assignments
1321 = assignMasterRegions(regions.keySet(), servers);
1322 if (assignments != null && !assignments.isEmpty()) {
1323 servers = new ArrayList<ServerName>(servers);
1324
1325 servers.remove(masterServerName);
1326 List<HRegionInfo> masterRegions = assignments.get(masterServerName);
1327 if (!masterRegions.isEmpty()) {
1328 regions = new HashMap<HRegionInfo, ServerName>(regions);
1329 for (HRegionInfo region: masterRegions) {
1330 regions.remove(region);
1331 }
1332 }
1333 }
1334 if (regions == null || regions.isEmpty()) {
1335 return assignments;
1336 }
1337
1338 int numServers = servers == null ? 0 : servers.size();
1339 if (numServers == 0) {
1340 LOG.warn("Wanted to do retain assignment but no servers to assign to");
1341 return null;
1342 }
1343 if (numServers == 1) {
1344 ServerName server = servers.get(0);
1345 assignments.put(server, new ArrayList<HRegionInfo>(regions.keySet()));
1346 return assignments;
1347 }
1348
1349
1350
1351
1352
1353
1354
1355 ArrayListMultimap<String, ServerName> serversByHostname = ArrayListMultimap.create();
1356 for (ServerName server : servers) {
1357 assignments.put(server, new ArrayList<HRegionInfo>());
1358 serversByHostname.put(server.getHostname(), server);
1359 }
1360
1361
1362
1363
1364 Set<String> oldHostsNoLongerPresent = Sets.newTreeSet();
1365
1366 int numRandomAssignments = 0;
1367 int numRetainedAssigments = 0;
1368
1369 Cluster cluster = createCluster(servers, regions.keySet());
1370
1371 for (Map.Entry<HRegionInfo, ServerName> entry : regions.entrySet()) {
1372 HRegionInfo region = entry.getKey();
1373 ServerName oldServerName = entry.getValue();
1374 List<ServerName> localServers = new ArrayList<ServerName>();
1375 if (oldServerName != null) {
1376 localServers = serversByHostname.get(oldServerName.getHostname());
1377 }
1378 if (localServers.isEmpty()) {
1379
1380
1381 ServerName randomServer = randomAssignment(cluster, region, servers);
1382 assignments.get(randomServer).add(region);
1383 numRandomAssignments++;
1384 if (oldServerName != null) oldHostsNoLongerPresent.add(oldServerName.getHostname());
1385 } else if (localServers.size() == 1) {
1386
1387 ServerName target = localServers.get(0);
1388 assignments.get(target).add(region);
1389 cluster.doAssignRegion(region, target);
1390 numRetainedAssigments++;
1391 } else {
1392
1393 if (localServers.contains(oldServerName)) {
1394 assignments.get(oldServerName).add(region);
1395 cluster.doAssignRegion(region, oldServerName);
1396 } else {
1397 ServerName target = null;
1398 for (ServerName tmp: localServers) {
1399 if (tmp.getPort() == oldServerName.getPort()) {
1400 target = tmp;
1401 break;
1402 }
1403 }
1404 if (target == null) {
1405 target = randomAssignment(cluster, region, localServers);
1406 }
1407 assignments.get(target).add(region);
1408 }
1409 numRetainedAssigments++;
1410 }
1411 }
1412
1413 String randomAssignMsg = "";
1414 if (numRandomAssignments > 0) {
1415 randomAssignMsg =
1416 numRandomAssignments + " regions were assigned "
1417 + "to random hosts, since the old hosts for these regions are no "
1418 + "longer present in the cluster. These hosts were:\n "
1419 + Joiner.on("\n ").join(oldHostsNoLongerPresent);
1420 }
1421
1422 LOG.info("Reassigned " + regions.size() + " regions. " + numRetainedAssigments
1423 + " retained the pre-restart assignment. " + randomAssignMsg);
1424 return assignments;
1425 }
1426
1427 @Override
1428 public void initialize() throws HBaseIOException{
1429 }
1430
1431 @Override
1432 public void regionOnline(HRegionInfo regionInfo, ServerName sn) {
1433 }
1434
1435 @Override
1436 public void regionOffline(HRegionInfo regionInfo) {
1437 }
1438
1439 @Override
1440 public boolean isStopped() {
1441 return stopped;
1442 }
1443
1444 @Override
1445 public void stop(String why) {
1446 LOG.info("Load Balancer stop requested: "+why);
1447 stopped = true;
1448 }
1449
1450
1451
1452
1453 private ServerName randomAssignment(Cluster cluster, HRegionInfo regionInfo,
1454 List<ServerName> servers) {
1455 int numServers = servers.size();
1456 ServerName sn = null;
1457 final int maxIterations = numServers * 4;
1458 int iterations = 0;
1459
1460 do {
1461 int i = RANDOM.nextInt(numServers);
1462 sn = servers.get(i);
1463 } while (cluster.wouldLowerAvailability(regionInfo, sn)
1464 && iterations++ < maxIterations);
1465 cluster.doAssignRegion(regionInfo, sn);
1466 return sn;
1467 }
1468
1469
1470
1471
1472 private void roundRobinAssignment(Cluster cluster, List<HRegionInfo> regions,
1473 List<HRegionInfo> unassignedRegions, List<ServerName> servers,
1474 Map<ServerName, List<HRegionInfo>> assignments) {
1475
1476 int numServers = servers.size();
1477 int numRegions = regions.size();
1478 int max = (int) Math.ceil((float) numRegions / numServers);
1479 int serverIdx = 0;
1480 if (numServers > 1) {
1481 serverIdx = RANDOM.nextInt(numServers);
1482 }
1483 int regionIdx = 0;
1484
1485 for (int j = 0; j < numServers; j++) {
1486 ServerName server = servers.get((j + serverIdx) % numServers);
1487 List<HRegionInfo> serverRegions = new ArrayList<HRegionInfo>(max);
1488 for (int i = regionIdx; i < numRegions; i += numServers) {
1489 HRegionInfo region = regions.get(i % numRegions);
1490 if (cluster.wouldLowerAvailability(region, server)) {
1491 unassignedRegions.add(region);
1492 } else {
1493 serverRegions.add(region);
1494 cluster.doAssignRegion(region, server);
1495 }
1496 }
1497 assignments.put(server, serverRegions);
1498 regionIdx++;
1499 }
1500 }
1501
1502 protected Map<ServerName, List<HRegionInfo>> getRegionAssignmentsByServer(
1503 Collection<HRegionInfo> regions) {
1504 if (this.services != null && this.services.getAssignmentManager() != null) {
1505 return this.services.getAssignmentManager().getSnapShotOfAssignment(regions);
1506 } else {
1507 return new HashMap<ServerName, List<HRegionInfo>>();
1508 }
1509 }
1510
1511 @Override
1512 public void onConfigurationChange(Configuration conf) {
1513 }
1514 }