1717 */
1818package org .apache .hadoop .hbase .master .assignment ;
1919
20+ import com .google .errorprone .annotations .RestrictedApi ;
2021import java .util .ArrayList ;
2122import java .util .List ;
22- import java .util .concurrent .ConcurrentSkipListMap ;
23+ import java .util .Objects ;
24+ import java .util .concurrent .ConcurrentHashMap ;
25+ import java .util .function .LongConsumer ;
2326import org .apache .hadoop .hbase .TableName ;
2427import org .apache .hadoop .hbase .client .RegionInfo ;
2528import org .apache .hadoop .hbase .client .TableState ;
2629import org .apache .hadoop .hbase .master .RegionState ;
2730import org .apache .hadoop .hbase .master .TableStateManager ;
31+ import org .apache .hadoop .hbase .util .EnvironmentEdgeManager ;
32+ import org .apache .hadoop .hbase .util .Pair ;
2833import org .apache .yetus .audience .InterfaceAudience ;
2934import org .slf4j .Logger ;
3035import org .slf4j .LoggerFactory ;
3641public class RegionInTransitionTracker {
3742 private static final Logger LOG = LoggerFactory .getLogger (RegionInTransitionTracker .class );
3843
39- private final List <RegionState .State > DISABLE_TABLE_REGION_STATE =
44+ private static final List <RegionState .State > DISABLE_TABLE_REGION_STATE =
4045 List .of (RegionState .State .OFFLINE , RegionState .State .CLOSED );
4146
42- private final List <RegionState .State > ENABLE_TABLE_REGION_STATE = List .of (RegionState .State .OPEN );
47+ private static final List <RegionState .State > ENABLE_TABLE_REGION_STATE =
48+ List .of (RegionState .State .OPEN );
4349
44- // DO NOT USE containsKey()/remove() on regionInTransition with a different RegionInfo instance:
45- // this map is ordered by RegionInfo.COMPARATOR, and that comparator includes the offline flag.
46- // Lookups can therefore fail if the RegionInfo used as the key has a different offline value,
47- // even when it refers to the same region. Offline value changes with splitting.
48- private final ConcurrentSkipListMap <RegionInfo , RegionStateNode > regionInTransition =
49- new ConcurrentSkipListMap <>(RegionInfo . COMPARATOR );
50+ // DO NOT USE containsKey()/remove() on regionInTransition with a RegionInfo instance whose
51+ // offline flag differs from the one stored as the key: RegionInfo#equals and #hashCode both
52+ // include the offline flag, so such a lookup misses even when it refers to the same region.
53+ // Offline value changes with splitting.
54+ private final ConcurrentHashMap <RegionInfo , Pair < RegionStateNode , Long > > regionInTransition =
55+ new ConcurrentHashMap <>();
5056
57+ private final LongConsumer ritDurationConsumer ;
5158 private TableStateManager tableStateManager ;
5259
60+ public RegionInTransitionTracker (LongConsumer ritDurationConsumer ) {
61+ this .ritDurationConsumer = Objects .requireNonNull (ritDurationConsumer );
62+ }
63+
64+ @ RestrictedApi (explanation = "Should only be called in tests" , link = "" ,
65+ allowedOnPath = ".*/src/test/.*" )
66+ boolean isRegionInTransition (final RegionInfo regionInfo ) {
67+ return regionInTransition .containsKey (regionInfo );
68+ }
69+
5370 /**
5471 * Handles a region whose hosting RegionServer has crashed. When a RegionServer fails, all regions
5572 * it was hosting are automatically added to the RIT list since they need to be reassigned to
5673 * other servers.
74+ * @param regionStateNode the region whose hosting server crashed
75+ * @param crashTime the RIT start time to use when the region is not already in transition
76+ * (an existing entry keeps its earlier start). Passed explicitly rather
77+ * than read from {@link RegionStateNode#getLastUpdate()}, which a stale
78+ * procedure can mask. A non-positive value falls back to the node's last
79+ * update.
5780 */
58- public void regionCrashed (RegionStateNode regionStateNode ) {
81+ public void regionCrashed (RegionStateNode regionStateNode , long crashTime ) {
5982 if (isReplica (regionStateNode )) {
6083 return ;
6184 }
6285
63- if (addRegionInTransition (regionStateNode )) {
86+ long startTime = crashTime > 0 ? crashTime : regionStateNode .getLastUpdate ();
87+ if (addRegionInTransition (regionStateNode , startTime )) {
6488 LOG .debug ("{} added to RIT list because hosting region server is crashed " ,
6589 regionStateNode .getRegionInfo ().getEncodedName ());
6690 }
@@ -128,11 +152,26 @@ public void handleRegionDelete(RegionInfo regionInfo) {
128152 }
129153
130154 private boolean addRegionInTransition (final RegionStateNode regionStateNode ) {
131- return regionInTransition .putIfAbsent (regionStateNode .getRegionInfo (), regionStateNode ) == null ;
155+ return addRegionInTransition (regionStateNode , regionStateNode .getLastUpdate ());
156+ }
157+
158+ private boolean addRegionInTransition (final RegionStateNode regionStateNode , long startTime ) {
159+ if (startTime <= 0 ) {
160+ startTime = EnvironmentEdgeManager .currentTime ();
161+ }
162+ return regionInTransition .putIfAbsent (regionStateNode .getRegionInfo (),
163+ Pair .newPair (regionStateNode , startTime )) == null ;
132164 }
133165
134166 private boolean removeRegionInTransition (final RegionInfo regionInfo ) {
135- return regionInTransition .remove (regionInfo ) != null ;
167+ Pair <RegionStateNode , Long > removed = regionInTransition .remove (regionInfo );
168+ if (removed != null ) {
169+ long duration = EnvironmentEdgeManager .currentTime () - removed .getSecond ();
170+ if (duration >= 0 ) {
171+ ritDurationConsumer .accept (duration );
172+ }
173+ }
174+ return removed != null ;
136175 }
137176
138177 public void stop () {
@@ -143,8 +182,16 @@ public boolean hasRegionsInTransition() {
143182 return !regionInTransition .isEmpty ();
144183 }
145184
185+ public int getRegionsInTransitionCount () {
186+ return regionInTransition .size ();
187+ }
188+
146189 public List <RegionStateNode > getRegionsInTransition () {
147- return new ArrayList <>(regionInTransition .values ());
190+ List <RegionStateNode > regions = new ArrayList <>(regionInTransition .size ());
191+ for (Pair <RegionStateNode , Long > entry : regionInTransition .values ()) {
192+ regions .add (entry .getFirst ());
193+ }
194+ return regions ;
148195 }
149196
150197 public void setTableStateManager (TableStateManager tableStateManager ) {
@@ -154,5 +201,4 @@ public void setTableStateManager(TableStateManager tableStateManager) {
154201 private static boolean isReplica (RegionStateNode regionStateNode ) {
155202 return regionStateNode .getRegionInfo ().getReplicaId () != RegionInfo .DEFAULT_REPLICA_ID ;
156203 }
157-
158204}
0 commit comments