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