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