1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.hadoop.hbase.master;
19 
20 import java.util.Date;
21 import java.util.concurrent.atomic.AtomicLong;
22 
23 import org.apache.hadoop.hbase.classification.InterfaceAudience;
24 import org.apache.hadoop.hbase.classification.InterfaceStability;
25 import org.apache.hadoop.hbase.HRegionInfo;
26 import org.apache.hadoop.hbase.ServerName;
27 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos;
28 
29 /**
30  * State of a Region while undergoing transitions.
31  * Region state cannot be modified except the stamp field.
32  * So it is almost immutable.
33  */
34 @InterfaceAudience.Private
35 public class RegionState {
36 
37   @InterfaceAudience.Private
38   @InterfaceStability.Evolving
39   public enum State {
40     OFFLINE,        // region is in an offline state
41     PENDING_OPEN,   // sent rpc to server to open but has not begun
42     OPENING,        // server has begun to open but not yet done
43     OPEN,           // server opened region and updated meta
44     PENDING_CLOSE,  // sent rpc to server to close but has not begun
45     CLOSING,        // server has begun to close but not yet done
46     CLOSED,         // server closed region and updated meta
47     SPLITTING,      // server started split of a region
48     SPLIT,          // server completed split of a region
49     FAILED_OPEN,    // failed to open, and won't retry any more
50     FAILED_CLOSE,   // failed to close, and won't retry any more
51     MERGING,        // server started merge a region
52     MERGED,         // server completed merge a region
53     SPLITTING_NEW,  // new region to be created when RS splits a parent
54                     // region but hasn't be created yet, or master doesn't
55                     // know it's already created
56     MERGING_NEW;    // new region to be created when RS merges two
57                     // daughter regions but hasn't be created yet, or
58                     // master doesn't know it's already created
59 
60     /**
61      * Convert to protobuf ClusterStatusProtos.RegionState.State
62      */
convert()63     public ClusterStatusProtos.RegionState.State convert() {
64       ClusterStatusProtos.RegionState.State rs;
65       switch (this) {
66       case OFFLINE:
67         rs = ClusterStatusProtos.RegionState.State.OFFLINE;
68         break;
69       case PENDING_OPEN:
70         rs = ClusterStatusProtos.RegionState.State.PENDING_OPEN;
71         break;
72       case OPENING:
73         rs = ClusterStatusProtos.RegionState.State.OPENING;
74         break;
75       case OPEN:
76         rs = ClusterStatusProtos.RegionState.State.OPEN;
77         break;
78       case PENDING_CLOSE:
79         rs = ClusterStatusProtos.RegionState.State.PENDING_CLOSE;
80         break;
81       case CLOSING:
82         rs = ClusterStatusProtos.RegionState.State.CLOSING;
83         break;
84       case CLOSED:
85         rs = ClusterStatusProtos.RegionState.State.CLOSED;
86         break;
87       case SPLITTING:
88         rs = ClusterStatusProtos.RegionState.State.SPLITTING;
89         break;
90       case SPLIT:
91         rs = ClusterStatusProtos.RegionState.State.SPLIT;
92         break;
93       case FAILED_OPEN:
94         rs = ClusterStatusProtos.RegionState.State.FAILED_OPEN;
95         break;
96       case FAILED_CLOSE:
97         rs = ClusterStatusProtos.RegionState.State.FAILED_CLOSE;
98         break;
99       case MERGING:
100         rs = ClusterStatusProtos.RegionState.State.MERGING;
101         break;
102       case MERGED:
103         rs = ClusterStatusProtos.RegionState.State.MERGED;
104         break;
105       case SPLITTING_NEW:
106         rs = ClusterStatusProtos.RegionState.State.SPLITTING_NEW;
107         break;
108       case MERGING_NEW:
109         rs = ClusterStatusProtos.RegionState.State.MERGING_NEW;
110         break;
111       default:
112         throw new IllegalStateException("");
113       }
114       return rs;
115     }
116 
117     /**
118      * Convert a protobuf HBaseProtos.RegionState.State to a RegionState.State
119      *
120      * @return the RegionState.State
121      */
convert(ClusterStatusProtos.RegionState.State protoState)122     public static State convert(ClusterStatusProtos.RegionState.State protoState) {
123       State state;
124       switch (protoState) {
125       case OFFLINE:
126         state = OFFLINE;
127         break;
128       case PENDING_OPEN:
129         state = PENDING_OPEN;
130         break;
131       case OPENING:
132         state = OPENING;
133         break;
134       case OPEN:
135         state = OPEN;
136         break;
137       case PENDING_CLOSE:
138         state = PENDING_CLOSE;
139         break;
140       case CLOSING:
141         state = CLOSING;
142         break;
143       case CLOSED:
144         state = CLOSED;
145         break;
146       case SPLITTING:
147         state = SPLITTING;
148         break;
149       case SPLIT:
150         state = SPLIT;
151         break;
152       case FAILED_OPEN:
153         state = FAILED_OPEN;
154         break;
155       case FAILED_CLOSE:
156         state = FAILED_CLOSE;
157         break;
158       case MERGING:
159         state = MERGING;
160         break;
161       case MERGED:
162         state = MERGED;
163         break;
164       case SPLITTING_NEW:
165         state = SPLITTING_NEW;
166         break;
167       case MERGING_NEW:
168         state = MERGING_NEW;
169         break;
170       default:
171         throw new IllegalStateException("");
172       }
173       return state;
174     }
175   }
176 
177   // Many threads can update the state at the stamp at the same time
178   private final AtomicLong stamp;
179   private HRegionInfo hri;
180 
181   private volatile ServerName serverName;
182   private volatile State state;
183 
RegionState()184   public RegionState() {
185     this.stamp = new AtomicLong(System.currentTimeMillis());
186   }
187 
RegionState(HRegionInfo region, State state)188   public RegionState(HRegionInfo region, State state) {
189     this(region, state, System.currentTimeMillis(), null);
190   }
191 
RegionState(HRegionInfo region, State state, ServerName serverName)192   public RegionState(HRegionInfo region,
193       State state, ServerName serverName) {
194     this(region, state, System.currentTimeMillis(), serverName);
195   }
196 
RegionState(HRegionInfo region, State state, long stamp, ServerName serverName)197   public RegionState(HRegionInfo region,
198       State state, long stamp, ServerName serverName) {
199     this.hri = region;
200     this.state = state;
201     this.stamp = new AtomicLong(stamp);
202     this.serverName = serverName;
203   }
204 
updateTimestampToNow()205   public void updateTimestampToNow() {
206     setTimestamp(System.currentTimeMillis());
207   }
208 
getState()209   public State getState() {
210     return state;
211   }
212 
getStamp()213   public long getStamp() {
214     return stamp.get();
215   }
216 
getRegion()217   public HRegionInfo getRegion() {
218     return hri;
219   }
220 
getServerName()221   public ServerName getServerName() {
222     return serverName;
223   }
224 
isClosing()225   public boolean isClosing() {
226     return state == State.CLOSING;
227   }
228 
isClosed()229   public boolean isClosed() {
230     return state == State.CLOSED;
231   }
232 
isPendingClose()233   public boolean isPendingClose() {
234     return state == State.PENDING_CLOSE;
235   }
236 
isOpening()237   public boolean isOpening() {
238     return state == State.OPENING;
239   }
240 
isOpened()241   public boolean isOpened() {
242     return state == State.OPEN;
243   }
244 
isPendingOpen()245   public boolean isPendingOpen() {
246     return state == State.PENDING_OPEN;
247   }
248 
isOffline()249   public boolean isOffline() {
250     return state == State.OFFLINE;
251   }
252 
isSplitting()253   public boolean isSplitting() {
254     return state == State.SPLITTING;
255   }
256 
isSplit()257   public boolean isSplit() {
258     return state == State.SPLIT;
259   }
260 
isSplittingNew()261   public boolean isSplittingNew() {
262     return state == State.SPLITTING_NEW;
263   }
264 
isFailedOpen()265   public boolean isFailedOpen() {
266     return state == State.FAILED_OPEN;
267   }
268 
isFailedClose()269   public boolean isFailedClose() {
270     return state == State.FAILED_CLOSE;
271   }
272 
isMerging()273   public boolean isMerging() {
274     return state == State.MERGING;
275   }
276 
isMerged()277   public boolean isMerged() {
278     return state == State.MERGED;
279   }
280 
isMergingNew()281   public boolean isMergingNew() {
282     return state == State.MERGING_NEW;
283   }
284 
isOpenOrMergingOnServer(final ServerName sn)285   public boolean isOpenOrMergingOnServer(final ServerName sn) {
286     return isOnServer(sn) && (isOpened() || isMerging());
287   }
288 
isOpenOrMergingNewOnServer(final ServerName sn)289   public boolean isOpenOrMergingNewOnServer(final ServerName sn) {
290     return isOnServer(sn) && (isOpened() || isMergingNew());
291   }
292 
isOpenOrSplittingOnServer(final ServerName sn)293   public boolean isOpenOrSplittingOnServer(final ServerName sn) {
294     return isOnServer(sn) && (isOpened() || isSplitting());
295   }
296 
isOpenOrSplittingNewOnServer(final ServerName sn)297   public boolean isOpenOrSplittingNewOnServer(final ServerName sn) {
298     return isOnServer(sn) && (isOpened() || isSplittingNew());
299   }
300 
isPendingOpenOrOpeningOnServer(final ServerName sn)301   public boolean isPendingOpenOrOpeningOnServer(final ServerName sn) {
302     return isOnServer(sn) && isPendingOpenOrOpening();
303   }
304 
305   // Failed open is also kind of pending open
isPendingOpenOrOpening()306   public boolean isPendingOpenOrOpening() {
307     return isPendingOpen() || isOpening() || isFailedOpen();
308   }
309 
isPendingCloseOrClosingOnServer(final ServerName sn)310   public boolean isPendingCloseOrClosingOnServer(final ServerName sn) {
311     return isOnServer(sn) && isPendingCloseOrClosing();
312   }
313 
314   // Failed close is also kind of pending close
isPendingCloseOrClosing()315   public boolean isPendingCloseOrClosing() {
316     return isPendingClose() || isClosing() || isFailedClose();
317   }
318 
isOnServer(final ServerName sn)319   public boolean isOnServer(final ServerName sn) {
320     return serverName != null && serverName.equals(sn);
321   }
322 
323   /**
324    * Check if a region state can transition to offline
325    */
isReadyToOffline()326   public boolean isReadyToOffline() {
327     return isMerged() || isSplit() || isOffline()
328       || isSplittingNew() || isMergingNew();
329   }
330 
331   /**
332    * Check if a region state can transition to online
333    */
isReadyToOnline()334   public boolean isReadyToOnline() {
335     return isOpened() || isSplittingNew() || isMergingNew();
336   }
337 
338   /**
339    * Check if a region state is one of offline states that
340    * can't transition to pending_close/closing (unassign/offline)
341    */
isUnassignable()342   public boolean isUnassignable() {
343     return isUnassignable(state);
344   }
345 
346   /**
347    * Check if a region state is one of offline states that
348    * can't transition to pending_close/closing (unassign/offline)
349    */
isUnassignable(State state)350   public static boolean isUnassignable(State state) {
351     return state == State.MERGED || state == State.SPLIT || state == State.OFFLINE
352       || state == State.SPLITTING_NEW || state == State.MERGING_NEW;
353   }
354 
355   @Override
toString()356   public String toString() {
357     return "{" + hri.getShortNameToLog()
358       + " state=" + state
359       + ", ts=" + stamp
360       + ", server=" + serverName + "}";
361   }
362 
363   /**
364    * A slower (but more easy-to-read) stringification
365    */
toDescriptiveString()366   public String toDescriptiveString() {
367     long lstamp = stamp.get();
368     long relTime = System.currentTimeMillis() - lstamp;
369 
370     return hri.getRegionNameAsString()
371       + " state=" + state
372       + ", ts=" + new Date(lstamp) + " (" + (relTime/1000) + "s ago)"
373       + ", server=" + serverName;
374   }
375 
376   /**
377    * Convert a RegionState to an HBaseProtos.RegionState
378    *
379    * @return the converted HBaseProtos.RegionState
380    */
convert()381   public ClusterStatusProtos.RegionState convert() {
382     ClusterStatusProtos.RegionState.Builder regionState = ClusterStatusProtos.RegionState.newBuilder();
383     regionState.setRegionInfo(HRegionInfo.convert(hri));
384     regionState.setState(state.convert());
385     regionState.setStamp(getStamp());
386     return regionState.build();
387   }
388 
389   /**
390    * Convert a protobuf HBaseProtos.RegionState to a RegionState
391    *
392    * @return the RegionState
393    */
convert(ClusterStatusProtos.RegionState proto)394   public static RegionState convert(ClusterStatusProtos.RegionState proto) {
395     return new RegionState(HRegionInfo.convert(proto.getRegionInfo()),
396       State.convert(proto.getState()), proto.getStamp(), null);
397   }
398 
setTimestamp(final long timestamp)399   protected void setTimestamp(final long timestamp) {
400     stamp.set(timestamp);
401   }
402 
403   /**
404    * Check if two states are the same, except timestamp
405    */
406   @Override
equals(Object obj)407   public boolean equals(Object obj) {
408     if (this == obj) return true;
409     if (obj == null || getClass() != obj.getClass()) {
410       return false;
411     }
412     RegionState tmp = (RegionState)obj;
413     return tmp.hri.equals(hri) && tmp.state == state
414       && ((serverName != null && serverName.equals(tmp.serverName))
415         || (tmp.serverName == null && serverName == null));
416   }
417 
418   /**
419    * Don't count timestamp in hash code calculation
420    */
421   @Override
hashCode()422   public int hashCode() {
423     return (serverName != null ? serverName.hashCode() * 11 : 0)
424       + hri.hashCode() + 5 * state.ordinal();
425   }
426 }
427