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