View Javadoc

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  
22  import org.apache.hadoop.classification.InterfaceAudience;
23  import org.apache.hadoop.classification.InterfaceStability;
24  import org.apache.hadoop.hbase.HRegionInfo;
25  import org.apache.hadoop.hbase.ServerName;
26  import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos;
27  
28  /**
29   * State of a Region while undergoing transitions.
30   * This class is immutable.
31   */
32  @InterfaceAudience.Private
33  public class RegionState {
34  
35    @InterfaceAudience.Public
36    @InterfaceStability.Evolving
37    public enum State {
38      OFFLINE,        // region is in an offline state
39      PENDING_OPEN,   // same as OPENING, to be removed
40      OPENING,        // server has begun to open but not yet done
41      OPEN,           // server opened region and updated meta
42      PENDING_CLOSE,  // same as CLOSING, to be removed
43      CLOSING,        // server has begun to close but not yet done
44      CLOSED,         // server closed region and updated meta
45      SPLITTING,      // server started split of a region
46      SPLIT,          // server completed split of a region
47      FAILED_OPEN,    // failed to open, and won't retry any more
48      FAILED_CLOSE,   // failed to close, and won't retry any more
49      MERGING,        // server started merge a region
50      MERGED,         // server completed merge a region
51      SPLITTING_NEW,  // new region to be created when RS splits a parent
52                      // region but hasn't be created yet, or master doesn't
53                      // know it's already created
54      MERGING_NEW;    // new region to be created when RS merges two
55                      // daughter regions but hasn't be created yet, or
56                      // master doesn't know it's already created
57  
58      /**
59       * Convert to protobuf ClusterStatusProtos.RegionState.State
60       */
61      public ClusterStatusProtos.RegionState.State convert() {
62        ClusterStatusProtos.RegionState.State rs;
63        switch (this) {
64        case OFFLINE:
65          rs = ClusterStatusProtos.RegionState.State.OFFLINE;
66          break;
67        case PENDING_OPEN:
68          rs = ClusterStatusProtos.RegionState.State.PENDING_OPEN;
69          break;
70        case OPENING:
71          rs = ClusterStatusProtos.RegionState.State.OPENING;
72          break;
73        case OPEN:
74          rs = ClusterStatusProtos.RegionState.State.OPEN;
75          break;
76        case PENDING_CLOSE:
77          rs = ClusterStatusProtos.RegionState.State.PENDING_CLOSE;
78          break;
79        case CLOSING:
80          rs = ClusterStatusProtos.RegionState.State.CLOSING;
81          break;
82        case CLOSED:
83          rs = ClusterStatusProtos.RegionState.State.CLOSED;
84          break;
85        case SPLITTING:
86          rs = ClusterStatusProtos.RegionState.State.SPLITTING;
87          break;
88        case SPLIT:
89          rs = ClusterStatusProtos.RegionState.State.SPLIT;
90          break;
91        case FAILED_OPEN:
92          rs = ClusterStatusProtos.RegionState.State.FAILED_OPEN;
93          break;
94        case FAILED_CLOSE:
95          rs = ClusterStatusProtos.RegionState.State.FAILED_CLOSE;
96          break;
97        case MERGING:
98          rs = ClusterStatusProtos.RegionState.State.MERGING;
99          break;
100       case MERGED:
101         rs = ClusterStatusProtos.RegionState.State.MERGED;
102         break;
103       case SPLITTING_NEW:
104         rs = ClusterStatusProtos.RegionState.State.SPLITTING_NEW;
105         break;
106       case MERGING_NEW:
107         rs = ClusterStatusProtos.RegionState.State.MERGING_NEW;
108         break;
109       default:
110         throw new IllegalStateException("");
111       }
112       return rs;
113     }
114 
115     /**
116      * Convert a protobuf HBaseProtos.RegionState.State to a RegionState.State
117      *
118      * @return the RegionState.State
119      */
120     public static State convert(ClusterStatusProtos.RegionState.State protoState) {
121       State state;
122       switch (protoState) {
123       case OFFLINE:
124         state = OFFLINE;
125         break;
126       case PENDING_OPEN:
127         state = PENDING_OPEN;
128         break;
129       case OPENING:
130         state = OPENING;
131         break;
132       case OPEN:
133         state = OPEN;
134         break;
135       case PENDING_CLOSE:
136         state = PENDING_CLOSE;
137         break;
138       case CLOSING:
139         state = CLOSING;
140         break;
141       case CLOSED:
142         state = CLOSED;
143         break;
144       case SPLITTING:
145         state = SPLITTING;
146         break;
147       case SPLIT:
148         state = SPLIT;
149         break;
150       case FAILED_OPEN:
151         state = FAILED_OPEN;
152         break;
153       case FAILED_CLOSE:
154         state = FAILED_CLOSE;
155         break;
156       case MERGING:
157         state = MERGING;
158         break;
159       case MERGED:
160         state = MERGED;
161         break;
162       case SPLITTING_NEW:
163         state = SPLITTING_NEW;
164         break;
165       case MERGING_NEW:
166         state = MERGING_NEW;
167         break;
168       default:
169         throw new IllegalStateException("");
170       }
171       return state;
172     }
173   }
174 
175   private final long stamp;
176   private final HRegionInfo hri;
177   private final ServerName serverName;
178   private final State state;
179 
180   public RegionState(HRegionInfo region, State state) {
181     this(region, state, System.currentTimeMillis(), null);
182   }
183 
184   public RegionState(HRegionInfo region,
185       State state, ServerName serverName) {
186     this(region, state, System.currentTimeMillis(), serverName);
187   }
188 
189   public RegionState(HRegionInfo region,
190       State state, long stamp, ServerName serverName) {
191     this.hri = region;
192     this.state = state;
193     this.stamp = stamp;
194     this.serverName = serverName;
195   }
196 
197   public State getState() {
198     return state;
199   }
200 
201   public long getStamp() {
202     return stamp;
203   }
204 
205   public HRegionInfo getRegion() {
206     return hri;
207   }
208 
209   public ServerName getServerName() {
210     return serverName;
211   }
212 
213   /**
214    * PENDING_CLOSE (to be removed) is the same as CLOSING
215    */
216   public boolean isClosing() {
217     return state == State.PENDING_CLOSE || state == State.CLOSING;
218   }
219 
220   public boolean isClosed() {
221     return state == State.CLOSED;
222   }
223 
224   /**
225    * PENDING_OPEN (to be removed) is the same as OPENING
226    */
227   public boolean isOpening() {
228     return state == State.PENDING_OPEN || state == State.OPENING;
229   }
230 
231   public boolean isOpened() {
232     return state == State.OPEN;
233   }
234 
235   public boolean isOffline() {
236     return state == State.OFFLINE;
237   }
238 
239   public boolean isSplitting() {
240     return state == State.SPLITTING;
241   }
242 
243   public boolean isSplit() {
244     return state == State.SPLIT;
245   }
246 
247   public boolean isSplittingNew() {
248     return state == State.SPLITTING_NEW;
249   }
250 
251   public boolean isFailedOpen() {
252     return state == State.FAILED_OPEN;
253   }
254 
255   public boolean isFailedClose() {
256     return state == State.FAILED_CLOSE;
257   }
258 
259   public boolean isMerging() {
260     return state == State.MERGING;
261   }
262 
263   public boolean isMerged() {
264     return state == State.MERGED;
265   }
266 
267   public boolean isMergingNew() {
268     return state == State.MERGING_NEW;
269   }
270 
271   public boolean isOnServer(final ServerName sn) {
272     return serverName != null && serverName.equals(sn);
273   }
274 
275   /**
276    * Check if a region state can transition to offline
277    */
278   public boolean isReadyToOffline() {
279     return isMerged() || isSplit() || isOffline()
280       || isSplittingNew() || isMergingNew();
281   }
282 
283   /**
284    * Check if a region state can transition to online
285    */
286   public boolean isReadyToOnline() {
287     return isOpened() || isSplittingNew() || isMergingNew();
288   }
289 
290   /**
291    * Check if a region state is one of offline states that
292    * can't transition to pending_close/closing (unassign/offline)
293    */
294   public boolean isUnassignable() {
295     return isUnassignable(state);
296   }
297 
298   /**
299    * Check if a region state is one of offline states that
300    * can't transition to pending_close/closing (unassign/offline)
301    */
302   public static boolean isUnassignable(State state) {
303     return state == State.MERGED || state == State.SPLIT || state == State.OFFLINE
304       || state == State.SPLITTING_NEW || state == State.MERGING_NEW;
305   }
306 
307   @Override
308   public String toString() {
309     return "{" + hri.getShortNameToLog()
310       + " state=" + state
311       + ", ts=" + stamp
312       + ", server=" + serverName + "}";
313   }
314 
315   /**
316    * A slower (but more easy-to-read) stringification
317    */
318   public String toDescriptiveString() {
319     long relTime = System.currentTimeMillis() - stamp;
320     return hri.getRegionNameAsString()
321       + " state=" + state
322       + ", ts=" + new Date(stamp) + " (" + (relTime/1000) + "s ago)"
323       + ", server=" + serverName;
324   }
325 
326   /**
327    * Convert a RegionState to an HBaseProtos.RegionState
328    *
329    * @return the converted HBaseProtos.RegionState
330    */
331   public ClusterStatusProtos.RegionState convert() {
332     ClusterStatusProtos.RegionState.Builder regionState = ClusterStatusProtos.RegionState.newBuilder();
333     regionState.setRegionInfo(HRegionInfo.convert(hri));
334     regionState.setState(state.convert());
335     regionState.setStamp(getStamp());
336     return regionState.build();
337   }
338 
339   /**
340    * Convert a protobuf HBaseProtos.RegionState to a RegionState
341    *
342    * @return the RegionState
343    */
344   public static RegionState convert(ClusterStatusProtos.RegionState proto) {
345     return new RegionState(HRegionInfo.convert(proto.getRegionInfo()),
346       State.convert(proto.getState()), proto.getStamp(), null);
347   }
348 
349   /**
350    * Check if two states are the same, except timestamp
351    */
352   @Override
353   public boolean equals(Object obj) {
354     if (this == obj) return true;
355     if (obj == null || getClass() != obj.getClass()) {
356       return false;
357     }
358     RegionState tmp = (RegionState)obj;
359     return tmp.hri.equals(hri) && tmp.state == state
360       && ((serverName != null && serverName.equals(tmp.serverName))
361         || (tmp.serverName == null && serverName == null));
362   }
363 
364   /**
365    * Don't count timestamp in hash code calculation
366    */
367   @Override
368   public int hashCode() {
369     return (serverName != null ? serverName.hashCode() * 11 : 0)
370       + hri.hashCode() + 5 * state.ordinal();
371   }
372 }