1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master;
19
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.TreeMap;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.hbase.HConstants;
37 import org.apache.hadoop.hbase.HRegionInfo;
38 import org.apache.hadoop.hbase.RegionTransition;
39 import org.apache.hadoop.hbase.HTableDescriptor;
40 import org.apache.hadoop.hbase.MetaTableAccessor;
41 import org.apache.hadoop.hbase.Server;
42 import org.apache.hadoop.hbase.ServerLoad;
43 import org.apache.hadoop.hbase.ServerName;
44 import org.apache.hadoop.hbase.TableName;
45 import org.apache.hadoop.hbase.TableStateManager;
46 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
47 import org.apache.hadoop.hbase.MetaTableAccessor;
48 import org.apache.hadoop.hbase.master.RegionState.State;
49 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
50 import org.apache.hadoop.hbase.util.Bytes;
51 import org.apache.hadoop.hbase.util.FSUtils;
52 import org.apache.hadoop.hbase.util.Pair;
53 import org.apache.hadoop.hbase.zookeeper.ZKAssign;
54 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
55 import org.apache.zookeeper.KeeperException;
56
57 import com.google.common.annotations.VisibleForTesting;
58 import com.google.common.base.Preconditions;
59
60
61
62
63
64
65
66 @InterfaceAudience.Private
67 public class RegionStates {
68 private static final Log LOG = LogFactory.getLog(RegionStates.class);
69
70
71
72
73 final HashMap<String, RegionState> regionsInTransition =
74 new HashMap<String, RegionState>();
75
76
77
78
79
80 private final Map<String, RegionState> regionStates =
81 new HashMap<String, RegionState>();
82
83
84
85
86 private final Map<TableName, Map<String, RegionState>> regionStatesTableIndex =
87 new HashMap<TableName, Map<String, RegionState>>();
88
89
90
91
92
93 private final Map<ServerName, Set<HRegionInfo>> serverHoldings =
94 new HashMap<ServerName, Set<HRegionInfo>>();
95
96
97
98
99 private final Map<HRegionInfo, Set<HRegionInfo>> defaultReplicaToOtherReplicas =
100 new HashMap<HRegionInfo, Set<HRegionInfo>>();
101
102
103
104
105
106 private final TreeMap<HRegionInfo, ServerName> regionAssignments =
107 new TreeMap<HRegionInfo, ServerName>();
108
109
110
111
112
113
114
115
116
117
118
119 private final HashMap<String, ServerName> lastAssignments =
120 new HashMap<String, ServerName>();
121
122
123
124
125
126
127
128
129
130
131 private final HashMap<String, ServerName> oldAssignments =
132 new HashMap<String, ServerName>();
133
134
135
136
137
138
139 private final HashMap<String, Long> deadServers =
140 new HashMap<String, Long>();
141
142
143
144
145
146
147
148
149 private final HashMap<ServerName, Long> processedServers =
150 new HashMap<ServerName, Long>();
151 private long lastProcessedServerCleanTime;
152
153 private final TableStateManager tableStateManager;
154 private final RegionStateStore regionStateStore;
155 private final ServerManager serverManager;
156 private final Server server;
157
158
159 static final String LOG_SPLIT_TIME = "hbase.master.maximum.logsplit.keeptime";
160 static final long DEFAULT_LOG_SPLIT_TIME = 7200000L;
161
162 RegionStates(final Server master, final TableStateManager tableStateManager,
163 final ServerManager serverManager, final RegionStateStore regionStateStore) {
164 this.tableStateManager = tableStateManager;
165 this.regionStateStore = regionStateStore;
166 this.serverManager = serverManager;
167 this.server = master;
168 }
169
170
171
172
173 public synchronized Map<HRegionInfo, ServerName> getRegionAssignments() {
174 return new TreeMap<HRegionInfo, ServerName>(regionAssignments);
175 }
176
177
178
179
180
181
182 synchronized Map<ServerName, List<HRegionInfo>> getRegionAssignments(
183 Collection<HRegionInfo> regions) {
184 Map<ServerName, List<HRegionInfo>> map = new HashMap<ServerName, List<HRegionInfo>>();
185 for (HRegionInfo region : regions) {
186 HRegionInfo defaultReplica = RegionReplicaUtil.getRegionInfoForDefaultReplica(region);
187 Set<HRegionInfo> allReplicas = defaultReplicaToOtherReplicas.get(defaultReplica);
188 if (allReplicas != null) {
189 for (HRegionInfo hri : allReplicas) {
190 ServerName server = regionAssignments.get(hri);
191 if (server != null) {
192 List<HRegionInfo> regionsOnServer = map.get(server);
193 if (regionsOnServer == null) {
194 regionsOnServer = new ArrayList<HRegionInfo>(1);
195 map.put(server, regionsOnServer);
196 }
197 regionsOnServer.add(hri);
198 }
199 }
200 }
201 }
202 return map;
203 }
204
205 public synchronized ServerName getRegionServerOfRegion(HRegionInfo hri) {
206 return regionAssignments.get(hri);
207 }
208
209
210
211
212 @SuppressWarnings("unchecked")
213 public synchronized Map<String, RegionState> getRegionsInTransition() {
214 return (Map<String, RegionState>)regionsInTransition.clone();
215 }
216
217
218
219
220 public synchronized boolean isRegionInTransition(final HRegionInfo hri) {
221 return regionsInTransition.containsKey(hri.getEncodedName());
222 }
223
224
225
226
227 public synchronized boolean isRegionInTransition(final String encodedName) {
228 return regionsInTransition.containsKey(encodedName);
229 }
230
231
232
233
234 public synchronized boolean isRegionsInTransition() {
235 return !regionsInTransition.isEmpty();
236 }
237
238
239
240
241 public synchronized boolean isRegionOnline(final HRegionInfo hri) {
242 return !isRegionInTransition(hri) && regionAssignments.containsKey(hri);
243 }
244
245
246
247
248
249 public synchronized boolean isRegionOffline(final HRegionInfo hri) {
250 return getRegionState(hri) == null || (!isRegionInTransition(hri)
251 && isRegionInState(hri, State.OFFLINE, State.CLOSED));
252 }
253
254
255
256
257 public boolean isRegionInState(
258 final HRegionInfo hri, final State... states) {
259 return isRegionInState(hri.getEncodedName(), states);
260 }
261
262
263
264
265 public boolean isRegionInState(
266 final String encodedName, final State... states) {
267 RegionState regionState = getRegionState(encodedName);
268 return isOneOfStates(regionState, states);
269 }
270
271
272
273
274 public synchronized void waitForUpdate(
275 final long timeout) throws InterruptedException {
276 this.wait(timeout);
277 }
278
279
280
281
282 public RegionState getRegionTransitionState(final HRegionInfo hri) {
283 return getRegionTransitionState(hri.getEncodedName());
284 }
285
286
287
288
289 public synchronized RegionState
290 getRegionTransitionState(final String encodedName) {
291 return regionsInTransition.get(encodedName);
292 }
293
294
295
296
297
298
299 public void createRegionStates(
300 final List<HRegionInfo> hris) {
301 for (HRegionInfo hri: hris) {
302 createRegionState(hri);
303 }
304 }
305
306
307
308
309
310
311
312 public RegionState createRegionState(final HRegionInfo hri) {
313 return createRegionState(hri, null, null, null);
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327 public synchronized RegionState createRegionState(final HRegionInfo hri,
328 State newState, ServerName serverName, ServerName lastHost) {
329 if (newState == null || (newState == State.OPEN && serverName == null)) {
330 newState = State.OFFLINE;
331 }
332 if (hri.isOffline() && hri.isSplit()) {
333 newState = State.SPLIT;
334 serverName = null;
335 }
336 String encodedName = hri.getEncodedName();
337 RegionState regionState = regionStates.get(encodedName);
338 if (regionState != null) {
339 LOG.warn("Tried to create a state for a region already in RegionStates, "
340 + "used existing: " + regionState + ", ignored new: " + newState);
341 } else {
342 regionState = new RegionState(hri, newState, serverName);
343 putRegionState(regionState);
344 if (newState == State.OPEN) {
345 if (!serverName.equals(lastHost)) {
346 LOG.warn("Open region's last host " + lastHost
347 + " should be the same as the current one " + serverName
348 + ", ignored the last and used the current one");
349 lastHost = serverName;
350 }
351 lastAssignments.put(encodedName, lastHost);
352 regionAssignments.put(hri, lastHost);
353 } else if (!regionState.isUnassignable()) {
354 regionsInTransition.put(encodedName, regionState);
355 }
356 if (lastHost != null && newState != State.SPLIT) {
357 addToServerHoldings(lastHost, hri);
358 if (newState != State.OPEN) {
359 oldAssignments.put(encodedName, lastHost);
360 }
361 }
362 }
363 return regionState;
364 }
365
366 private RegionState putRegionState(RegionState regionState) {
367 HRegionInfo hri = regionState.getRegion();
368 String encodedName = hri.getEncodedName();
369 TableName table = hri.getTable();
370 RegionState oldState = regionStates.put(encodedName, regionState);
371 Map<String, RegionState> map = regionStatesTableIndex.get(table);
372 if (map == null) {
373 map = new HashMap<String, RegionState>();
374 regionStatesTableIndex.put(table, map);
375 }
376 map.put(encodedName, regionState);
377 return oldState;
378 }
379
380
381
382
383 public RegionState updateRegionState(
384 final HRegionInfo hri, final State state) {
385 RegionState regionState = getRegionState(hri.getEncodedName());
386 return updateRegionState(hri, state,
387 regionState == null ? null : regionState.getServerName());
388 }
389
390
391
392
393
394
395
396 public RegionState updateRegionState(
397 final RegionTransition transition, final State state) {
398 byte [] regionName = transition.getRegionName();
399 HRegionInfo regionInfo = getRegionInfo(regionName);
400 if (regionInfo == null) {
401 String prettyRegionName = HRegionInfo.prettyPrint(
402 HRegionInfo.encodeRegionName(regionName));
403 LOG.warn("Failed to find region " + prettyRegionName
404 + " in updating its state to " + state
405 + " based on region transition " + transition);
406 return null;
407 }
408 return updateRegionState(regionInfo, state,
409 transition.getServerName());
410 }
411
412
413
414
415 public synchronized RegionState transitionOpenFromPendingOpenOrOpeningOnServer(
416 final RegionTransition transition, final RegionState fromState, final ServerName sn) {
417 if(fromState.isPendingOpenOrOpeningOnServer(sn)){
418 return updateRegionState(transition, State.OPEN);
419 }
420 return null;
421 }
422
423
424
425
426 public RegionState updateRegionState(
427 final HRegionInfo hri, final State state, final ServerName serverName) {
428 return updateRegionState(hri, state, serverName, HConstants.NO_SEQNUM);
429 }
430
431 public void regionOnline(
432 final HRegionInfo hri, final ServerName serverName) {
433 regionOnline(hri, serverName, HConstants.NO_SEQNUM);
434 }
435
436
437
438
439
440
441 public void regionOnline(final HRegionInfo hri,
442 final ServerName serverName, long openSeqNum) {
443 String encodedName = hri.getEncodedName();
444 if (!serverManager.isServerOnline(serverName)) {
445
446
447
448
449 LOG.warn("Ignored, " + encodedName
450 + " was opened on a dead server: " + serverName);
451 return;
452 }
453 updateRegionState(hri, State.OPEN, serverName, openSeqNum);
454
455 synchronized (this) {
456 regionsInTransition.remove(encodedName);
457 ServerName oldServerName = regionAssignments.put(hri, serverName);
458 if (!serverName.equals(oldServerName)) {
459 if (LOG.isDebugEnabled()) {
460 LOG.debug("Onlined " + hri.getShortNameToLog() + " on " + serverName + " " + hri);
461 } else {
462 LOG.debug("Onlined " + hri.getShortNameToLog() + " on " + serverName);
463 }
464 addToServerHoldings(serverName, hri);
465 addToReplicaMapping(hri);
466 if (oldServerName == null) {
467 oldServerName = oldAssignments.remove(encodedName);
468 }
469 if (oldServerName != null
470 && !oldServerName.equals(serverName)
471 && serverHoldings.containsKey(oldServerName)) {
472 LOG.info("Offlined " + hri.getShortNameToLog() + " from " + oldServerName);
473 removeFromServerHoldings(oldServerName, hri);
474 }
475 }
476 }
477 }
478
479 private void addToServerHoldings(ServerName serverName, HRegionInfo hri) {
480 Set<HRegionInfo> regions = serverHoldings.get(serverName);
481 if (regions == null) {
482 regions = new HashSet<HRegionInfo>();
483 serverHoldings.put(serverName, regions);
484 }
485 regions.add(hri);
486 }
487
488 private void addToReplicaMapping(HRegionInfo hri) {
489 HRegionInfo defaultReplica = RegionReplicaUtil.getRegionInfoForDefaultReplica(hri);
490 Set<HRegionInfo> replicas =
491 defaultReplicaToOtherReplicas.get(defaultReplica);
492 if (replicas == null) {
493 replicas = new HashSet<HRegionInfo>();
494 defaultReplicaToOtherReplicas.put(defaultReplica, replicas);
495 }
496 replicas.add(hri);
497 }
498
499 private void removeFromServerHoldings(ServerName serverName, HRegionInfo hri) {
500 Set<HRegionInfo> oldRegions = serverHoldings.get(serverName);
501 oldRegions.remove(hri);
502 if (oldRegions.isEmpty()) {
503 serverHoldings.remove(serverName);
504 }
505 }
506
507 private void removeFromReplicaMapping(HRegionInfo hri) {
508 HRegionInfo defaultReplica = RegionReplicaUtil.getRegionInfoForDefaultReplica(hri);
509 Set<HRegionInfo> replicas = defaultReplicaToOtherReplicas.get(defaultReplica);
510 if (replicas != null) {
511 replicas.remove(hri);
512 if (replicas.isEmpty()) {
513 defaultReplicaToOtherReplicas.remove(defaultReplica);
514 }
515 }
516 }
517
518
519
520
521
522 public synchronized void logSplit(final ServerName serverName) {
523 for (Iterator<Map.Entry<String, ServerName>> it
524 = lastAssignments.entrySet().iterator(); it.hasNext();) {
525 Map.Entry<String, ServerName> e = it.next();
526 if (e.getValue().equals(serverName)) {
527 it.remove();
528 }
529 }
530 long now = System.currentTimeMillis();
531 if (LOG.isDebugEnabled()) {
532 LOG.debug("Adding to processed servers " + serverName);
533 }
534 processedServers.put(serverName, Long.valueOf(now));
535 Configuration conf = server.getConfiguration();
536 long obsoleteTime = conf.getLong(LOG_SPLIT_TIME, DEFAULT_LOG_SPLIT_TIME);
537
538 if (now > lastProcessedServerCleanTime + obsoleteTime) {
539 lastProcessedServerCleanTime = now;
540 long cutoff = now - obsoleteTime;
541 for (Iterator<Map.Entry<ServerName, Long>> it
542 = processedServers.entrySet().iterator(); it.hasNext();) {
543 Map.Entry<ServerName, Long> e = it.next();
544 if (e.getValue().longValue() < cutoff) {
545 if (LOG.isDebugEnabled()) {
546 LOG.debug("Removed from processed servers " + e.getKey());
547 }
548 it.remove();
549 }
550 }
551 }
552 }
553
554
555
556
557 public void logSplit(final HRegionInfo region) {
558 clearLastAssignment(region);
559 }
560
561 public synchronized void clearLastAssignment(final HRegionInfo region) {
562 lastAssignments.remove(region.getEncodedName());
563 }
564
565
566
567
568 public void regionOffline(final HRegionInfo hri) {
569 regionOffline(hri, null);
570 }
571
572
573
574
575
576
577 public void regionOffline(
578 final HRegionInfo hri, final State expectedState) {
579 Preconditions.checkArgument(expectedState == null
580 || RegionState.isUnassignable(expectedState),
581 "Offlined region should not be " + expectedState);
582 if (isRegionInState(hri, State.SPLITTING_NEW, State.MERGING_NEW)) {
583
584 deleteRegion(hri);
585 return;
586 }
587 State newState =
588 expectedState == null ? State.OFFLINE : expectedState;
589 updateRegionState(hri, newState);
590 String encodedName = hri.getEncodedName();
591 synchronized (this) {
592 regionsInTransition.remove(encodedName);
593 ServerName oldServerName = regionAssignments.remove(hri);
594 if (oldServerName != null && serverHoldings.containsKey(oldServerName)) {
595 if (newState == State.MERGED || newState == State.SPLIT
596 || hri.isMetaRegion() || tableStateManager.isTableState(hri.getTable(),
597 ZooKeeperProtos.Table.State.DISABLED, ZooKeeperProtos.Table.State.DISABLING)) {
598
599
600 LOG.info("Offlined " + hri.getShortNameToLog() + " from " + oldServerName);
601 removeFromServerHoldings(oldServerName, hri);
602 removeFromReplicaMapping(hri);
603 } else {
604
605
606 oldAssignments.put(encodedName, oldServerName);
607 }
608 }
609 }
610 }
611
612
613
614
615 public List<HRegionInfo> serverOffline(final ZooKeeperWatcher watcher, final ServerName sn) {
616
617 List<HRegionInfo> rits = new ArrayList<HRegionInfo>();
618 Set<HRegionInfo> regionsToCleanIfNoMetaEntry = new HashSet<HRegionInfo>();
619
620
621
622 Set<HRegionInfo> regionsToOffline = new HashSet<HRegionInfo>();
623 synchronized (this) {
624 Set<HRegionInfo> assignedRegions = serverHoldings.get(sn);
625 if (assignedRegions == null) {
626 assignedRegions = new HashSet<HRegionInfo>();
627 }
628
629 for (HRegionInfo region : assignedRegions) {
630
631 if (isRegionOnline(region)) {
632 regionsToOffline.add(region);
633 } else if (isRegionInState(region, State.SPLITTING, State.MERGING)) {
634 LOG.debug("Offline splitting/merging region " + getRegionState(region));
635 try {
636
637 ZKAssign.deleteNodeFailSilent(watcher, region);
638 regionsToOffline.add(region);
639 } catch (KeeperException ke) {
640 server.abort("Unexpected ZK exception deleting node " + region, ke);
641 }
642 }
643 }
644
645 for (RegionState state : regionsInTransition.values()) {
646 HRegionInfo hri = state.getRegion();
647 if (assignedRegions.contains(hri)) {
648
649
650
651 LOG.info("Transitioning " + state + " will be handled by SSH for " + sn);
652 } else if (sn.equals(state.getServerName())) {
653
654
655
656
657
658
659
660 if (state.isPendingOpenOrOpening() || state.isFailedClose() || state.isOffline()) {
661 LOG.info("Found region in " + state + " to be reassigned by SSH for " + sn);
662 rits.add(hri);
663 } else if(state.isSplittingNew()) {
664 regionsToCleanIfNoMetaEntry.add(state.getRegion());
665 } else {
666 LOG.warn("THIS SHOULD NOT HAPPEN: unexpected " + state);
667 }
668 }
669 }
670 this.notifyAll();
671 }
672
673 for (HRegionInfo hri : regionsToOffline) {
674 regionOffline(hri);
675 }
676
677 cleanIfNoMetaEntry(regionsToCleanIfNoMetaEntry);
678 return rits;
679 }
680
681
682
683
684
685 private void cleanIfNoMetaEntry(Set<HRegionInfo> hris) {
686 if (hris.isEmpty()) return;
687 for (HRegionInfo hri: hris) {
688 try {
689
690
691
692 if (MetaTableAccessor.getRegion(server.getConnection(), hri.getEncodedNameAsBytes()) ==
693 null) {
694 regionOffline(hri);
695 FSUtils.deleteRegionDir(server.getConfiguration(), hri);
696 }
697 } catch (IOException e) {
698 LOG.warn("Got exception while deleting " + hri + " directories from file system.", e);
699 }
700 }
701 }
702
703
704
705
706
707
708
709
710
711
712
713 public synchronized List<HRegionInfo> getRegionsOfTable(TableName tableName) {
714 List<HRegionInfo> tableRegions = new ArrayList<HRegionInfo>();
715
716
717 HRegionInfo boundary = new HRegionInfo(tableName, null, null, false, 0L);
718 for (HRegionInfo hri: regionAssignments.tailMap(boundary).keySet()) {
719 if(!hri.getTable().equals(tableName)) break;
720 tableRegions.add(hri);
721 }
722 return tableRegions;
723 }
724
725
726
727
728
729
730
731
732
733
734 public synchronized Map<RegionState.State, List<HRegionInfo>>
735 getRegionByStateOfTable(TableName tableName) {
736 Map<RegionState.State, List<HRegionInfo>> tableRegions =
737 new HashMap<State, List<HRegionInfo>>();
738 for (State state : State.values()) {
739 tableRegions.put(state, new ArrayList<HRegionInfo>());
740 }
741 Map<String, RegionState> indexMap = regionStatesTableIndex.get(tableName);
742 if (indexMap == null)
743 return tableRegions;
744 for (RegionState regionState : indexMap.values()) {
745 tableRegions.get(regionState.getState()).add(regionState.getRegion());
746 }
747 return tableRegions;
748 }
749
750
751
752
753
754
755
756 public synchronized void waitOnRegionToClearRegionsInTransition(
757 final HRegionInfo hri) throws InterruptedException {
758 if (!isRegionInTransition(hri)) return;
759
760 while(!server.isStopped() && isRegionInTransition(hri)) {
761 RegionState rs = getRegionState(hri);
762 LOG.info("Waiting on " + rs + " to clear regions-in-transition");
763 waitForUpdate(100);
764 }
765
766 if (server.isStopped()) {
767 LOG.info("Giving up wait on region in " +
768 "transition because stoppable.isStopped is set");
769 }
770 }
771
772
773
774
775
776 public void tableDeleted(final TableName tableName) {
777 Set<HRegionInfo> regionsToDelete = new HashSet<HRegionInfo>();
778 synchronized (this) {
779 for (RegionState state: regionStates.values()) {
780 HRegionInfo region = state.getRegion();
781 if (region.getTable().equals(tableName)) {
782 regionsToDelete.add(region);
783 }
784 }
785 }
786 for (HRegionInfo region: regionsToDelete) {
787 deleteRegion(region);
788 }
789 }
790
791
792
793
794 public synchronized Set<HRegionInfo> getServerRegions(ServerName serverName) {
795 Set<HRegionInfo> regions = serverHoldings.get(serverName);
796 if (regions == null) return null;
797 return new HashSet<HRegionInfo>(regions);
798 }
799
800
801
802
803 @VisibleForTesting
804 public synchronized void deleteRegion(final HRegionInfo hri) {
805 String encodedName = hri.getEncodedName();
806 regionsInTransition.remove(encodedName);
807 regionStates.remove(encodedName);
808 TableName table = hri.getTable();
809 Map<String, RegionState> indexMap = regionStatesTableIndex.get(table);
810 indexMap.remove(encodedName);
811 if (indexMap.size() == 0)
812 regionStatesTableIndex.remove(table);
813 lastAssignments.remove(encodedName);
814 ServerName sn = regionAssignments.remove(hri);
815 if (sn != null) {
816 Set<HRegionInfo> regions = serverHoldings.get(sn);
817 regions.remove(hri);
818 }
819 }
820
821
822
823
824
825
826
827
828
829
830
831 synchronized boolean wasRegionOnDeadServer(final String encodedName) {
832 ServerName server = lastAssignments.get(encodedName);
833 return isServerDeadAndNotProcessed(server);
834 }
835
836 synchronized boolean isServerDeadAndNotProcessed(ServerName server) {
837 if (server == null) return false;
838 if (serverManager.isServerOnline(server)) {
839 String hostAndPort = server.getHostAndPort();
840 long startCode = server.getStartcode();
841 Long deadCode = deadServers.get(hostAndPort);
842 if (deadCode == null || startCode > deadCode.longValue()) {
843 if (serverManager.isServerReachable(server)) {
844 return false;
845 }
846
847 deadServers.put(hostAndPort, Long.valueOf(startCode));
848 }
849
850
851
852
853
854
855
856 LOG.warn("Couldn't reach online server " + server);
857 }
858
859 return !processedServers.containsKey(server);
860 }
861
862
863
864
865
866 synchronized ServerName getLastRegionServerOfRegion(final String encodedName) {
867 return lastAssignments.get(encodedName);
868 }
869
870 synchronized void setLastRegionServerOfRegions(
871 final ServerName serverName, final List<HRegionInfo> regionInfos) {
872 for (HRegionInfo hri: regionInfos) {
873 setLastRegionServerOfRegion(serverName, hri.getEncodedName());
874 }
875 }
876
877 synchronized void setLastRegionServerOfRegion(
878 final ServerName serverName, final String encodedName) {
879 lastAssignments.put(encodedName, serverName);
880 }
881
882 void splitRegion(HRegionInfo p,
883 HRegionInfo a, HRegionInfo b, ServerName sn) throws IOException {
884
885 regionStateStore.splitRegion(p, a, b, sn, getRegionReplication(p));
886 synchronized (this) {
887
888
889 Set<HRegionInfo> regions = serverHoldings.get(sn);
890 if (regions == null) {
891 throw new IllegalStateException(sn + " should host some regions");
892 }
893 regions.remove(p);
894 regions.add(a);
895 regions.add(b);
896 }
897 }
898
899 void mergeRegions(HRegionInfo p,
900 HRegionInfo a, HRegionInfo b, ServerName sn) throws IOException {
901 regionStateStore.mergeRegions(p, a, b, sn, getRegionReplication(a));
902 synchronized (this) {
903
904
905 Set<HRegionInfo> regions = serverHoldings.get(sn);
906 if (regions == null) {
907 throw new IllegalStateException(sn + " should host some regions");
908 }
909 regions.remove(a);
910 regions.remove(b);
911 regions.add(p);
912 }
913 }
914
915 private int getRegionReplication(HRegionInfo r) throws IOException {
916 if (tableStateManager != null) {
917 HTableDescriptor htd = ((MasterServices)server).getTableDescriptors().get(r.getTable());
918 if (htd != null) {
919 return htd.getRegionReplication();
920 }
921 }
922 return 1;
923 }
924
925
926
927
928
929
930 synchronized Map<HRegionInfo, ServerName> closeAllUserRegions(Set<TableName> excludedTables) {
931 boolean noExcludeTables = excludedTables == null || excludedTables.isEmpty();
932 Set<HRegionInfo> toBeClosed = new HashSet<HRegionInfo>(regionStates.size());
933 for(RegionState state: regionStates.values()) {
934 HRegionInfo hri = state.getRegion();
935 if (state.isSplit() || hri.isSplit()) {
936 continue;
937 }
938 TableName tableName = hri.getTable();
939 if (!TableName.META_TABLE_NAME.equals(tableName)
940 && (noExcludeTables || !excludedTables.contains(tableName))) {
941 toBeClosed.add(hri);
942 }
943 }
944 Map<HRegionInfo, ServerName> allUserRegions =
945 new HashMap<HRegionInfo, ServerName>(toBeClosed.size());
946 for (HRegionInfo hri: toBeClosed) {
947 RegionState regionState = updateRegionState(hri, State.CLOSED);
948 allUserRegions.put(hri, regionState.getServerName());
949 }
950 return allUserRegions;
951 }
952
953
954
955
956
957
958
959 protected synchronized double getAverageLoad() {
960 int numServers = 0, totalLoad = 0;
961 for (Map.Entry<ServerName, Set<HRegionInfo>> e: serverHoldings.entrySet()) {
962 Set<HRegionInfo> regions = e.getValue();
963 ServerName serverName = e.getKey();
964 int regionCount = regions.size();
965 if (serverManager.isServerOnline(serverName)) {
966 totalLoad += regionCount;
967 numServers++;
968 }
969 }
970 if (numServers > 1) {
971
972
973
974 Set<HRegionInfo> hris = serverHoldings.get(server.getServerName());
975 if (hris != null) {
976 totalLoad -= hris.size();
977 numServers--;
978 }
979 }
980 return numServers == 0 ? 0.0 :
981 (double)totalLoad / (double)numServers;
982 }
983
984
985
986
987
988
989
990
991
992 protected Map<TableName, Map<ServerName, List<HRegionInfo>>>
993 getAssignmentsByTable() {
994 Map<TableName, Map<ServerName, List<HRegionInfo>>> result =
995 new HashMap<TableName, Map<ServerName,List<HRegionInfo>>>();
996 synchronized (this) {
997 if (!server.getConfiguration().getBoolean("hbase.master.loadbalance.bytable", false)) {
998 Map<ServerName, List<HRegionInfo>> svrToRegions =
999 new HashMap<ServerName, List<HRegionInfo>>(serverHoldings.size());
1000 for (Map.Entry<ServerName, Set<HRegionInfo>> e: serverHoldings.entrySet()) {
1001 svrToRegions.put(e.getKey(), new ArrayList<HRegionInfo>(e.getValue()));
1002 }
1003 result.put(TableName.valueOf("ensemble"), svrToRegions);
1004 } else {
1005 for (Map.Entry<ServerName, Set<HRegionInfo>> e: serverHoldings.entrySet()) {
1006 for (HRegionInfo hri: e.getValue()) {
1007 if (hri.isMetaRegion()) continue;
1008 TableName tablename = hri.getTable();
1009 Map<ServerName, List<HRegionInfo>> svrToRegions = result.get(tablename);
1010 if (svrToRegions == null) {
1011 svrToRegions = new HashMap<ServerName, List<HRegionInfo>>(serverHoldings.size());
1012 result.put(tablename, svrToRegions);
1013 }
1014 List<HRegionInfo> regions = svrToRegions.get(e.getKey());
1015 if (regions == null) {
1016 regions = new ArrayList<HRegionInfo>();
1017 svrToRegions.put(e.getKey(), regions);
1018 }
1019 regions.add(hri);
1020 }
1021 }
1022 }
1023 }
1024
1025 Map<ServerName, ServerLoad>
1026 onlineSvrs = serverManager.getOnlineServers();
1027
1028 List<ServerName> drainingServers = this.serverManager.getDrainingServersList();
1029 for (Map<ServerName, List<HRegionInfo>> map: result.values()) {
1030 for (ServerName svr: onlineSvrs.keySet()) {
1031 if (!map.containsKey(svr)) {
1032 map.put(svr, new ArrayList<HRegionInfo>());
1033 }
1034 }
1035 map.keySet().removeAll(drainingServers);
1036 }
1037 return result;
1038 }
1039
1040 protected RegionState getRegionState(final HRegionInfo hri) {
1041 return getRegionState(hri.getEncodedName());
1042 }
1043
1044
1045
1046
1047
1048 protected synchronized Map<ServerName, List<HRegionInfo>> getRegionAssignmentsByServer() {
1049 Map<ServerName, List<HRegionInfo>> regionsByServer =
1050 new HashMap<ServerName, List<HRegionInfo>>(serverHoldings.size());
1051 for (Map.Entry<ServerName, Set<HRegionInfo>> e: serverHoldings.entrySet()) {
1052 regionsByServer.put(e.getKey(), new ArrayList<HRegionInfo>(e.getValue()));
1053 }
1054 return regionsByServer;
1055 }
1056
1057 protected synchronized RegionState getRegionState(final String encodedName) {
1058 return regionStates.get(encodedName);
1059 }
1060
1061
1062
1063
1064
1065
1066 @SuppressWarnings("deprecation")
1067 protected HRegionInfo getRegionInfo(final byte [] regionName) {
1068 String encodedName = HRegionInfo.encodeRegionName(regionName);
1069 RegionState regionState = getRegionState(encodedName);
1070 if (regionState != null) {
1071 return regionState.getRegion();
1072 }
1073
1074 try {
1075 Pair<HRegionInfo, ServerName> p =
1076 MetaTableAccessor.getRegion(server.getConnection(), regionName);
1077 HRegionInfo hri = p == null ? null : p.getFirst();
1078 if (hri != null) {
1079 createRegionState(hri);
1080 }
1081 return hri;
1082 } catch (IOException e) {
1083 server.abort("Aborting because error occoured while reading "
1084 + Bytes.toStringBinary(regionName) + " from hbase:meta", e);
1085 return null;
1086 }
1087 }
1088
1089 static boolean isOneOfStates(RegionState regionState, State... states) {
1090 State s = regionState != null ? regionState.getState() : null;
1091 for (State state: states) {
1092 if (s == state) return true;
1093 }
1094 return false;
1095 }
1096
1097
1098
1099
1100 private RegionState updateRegionState(final HRegionInfo hri,
1101 final State state, final ServerName serverName, long openSeqNum) {
1102 if (state == State.FAILED_CLOSE || state == State.FAILED_OPEN) {
1103 LOG.warn("Failed to open/close " + hri.getShortNameToLog()
1104 + " on " + serverName + ", set to " + state);
1105 }
1106
1107 String encodedName = hri.getEncodedName();
1108 RegionState regionState = new RegionState(
1109 hri, state, System.currentTimeMillis(), serverName);
1110 RegionState oldState = getRegionState(encodedName);
1111 if (!regionState.equals(oldState)) {
1112 LOG.info("Transition " + oldState + " to " + regionState);
1113
1114 regionStateStore.updateRegionState(openSeqNum, regionState, oldState);
1115 }
1116
1117 synchronized (this) {
1118 regionsInTransition.put(encodedName, regionState);
1119 putRegionState(regionState);
1120
1121
1122
1123 if ((state == State.CLOSED || state == State.MERGED
1124 || state == State.SPLIT) && lastAssignments.containsKey(encodedName)) {
1125 ServerName last = lastAssignments.get(encodedName);
1126 if (last.equals(serverName)) {
1127 lastAssignments.remove(encodedName);
1128 } else {
1129 LOG.warn(encodedName + " moved to " + state + " on "
1130 + serverName + ", expected " + last);
1131 }
1132 }
1133
1134
1135 if (serverName != null && state == State.OPEN) {
1136 ServerName last = lastAssignments.get(encodedName);
1137 if (!serverName.equals(last)) {
1138 lastAssignments.put(encodedName, serverName);
1139 if (last != null && isServerDeadAndNotProcessed(last)) {
1140 LOG.warn(encodedName + " moved to " + serverName
1141 + ", while it's previous host " + last
1142 + " is dead but not processed yet");
1143 }
1144 }
1145 }
1146
1147
1148 this.notifyAll();
1149 }
1150 return regionState;
1151 }
1152 }