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