001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.master; 019 020import java.util.Date; 021import org.apache.hadoop.hbase.ServerName; 022import org.apache.hadoop.hbase.client.RegionInfo; 023import org.apache.yetus.audience.InterfaceAudience; 024import org.apache.yetus.audience.InterfaceStability; 025 026import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; 027import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 028import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos; 029 030/** 031 * State of a Region while undergoing transitions. 032 * This class is immutable. 033 */ 034@InterfaceAudience.Private 035public class RegionState { 036 037 @InterfaceAudience.Private 038 @InterfaceStability.Evolving 039 public enum State { 040 OFFLINE, // region is in an offline state 041 OPENING, // server has begun to open but not yet done 042 OPEN, // server opened region and updated meta 043 CLOSING, // server has begun to close but not yet done 044 CLOSED, // server closed region and updated meta 045 SPLITTING, // server started split of a region 046 SPLIT, // server completed split of a region 047 FAILED_OPEN, // failed to open, and won't retry any more 048 FAILED_CLOSE, // failed to close, and won't retry any more 049 MERGING, // server started merge a region 050 MERGED, // server completed merge a region 051 SPLITTING_NEW, // new region to be created when RS splits a parent 052 // region but hasn't be created yet, or master doesn't 053 // know it's already created 054 MERGING_NEW, // new region to be created when RS merges two 055 // daughter regions but hasn't be created yet, or 056 // master doesn't know it's already created 057 ABNORMALLY_CLOSED; // the region is CLOSED because of a RS crashes. Usually it is the same 058 // with CLOSED, but for some operations such as merge/split, we can not 059 // apply it to a region in this state, as it may lead to data loss as we 060 // may have some data in recovered edits. 061 062 public boolean matches(State... expected) { 063 for (State state : expected) { 064 if (this == state) { 065 return true; 066 } 067 } 068 return false; 069 } 070 071 /** 072 * Convert to protobuf ClusterStatusProtos.RegionState.State 073 */ 074 public ClusterStatusProtos.RegionState.State convert() { 075 ClusterStatusProtos.RegionState.State rs; 076 switch (this) { 077 case OFFLINE: 078 rs = ClusterStatusProtos.RegionState.State.OFFLINE; 079 break; 080 case OPENING: 081 rs = ClusterStatusProtos.RegionState.State.OPENING; 082 break; 083 case OPEN: 084 rs = ClusterStatusProtos.RegionState.State.OPEN; 085 break; 086 case CLOSING: 087 rs = ClusterStatusProtos.RegionState.State.CLOSING; 088 break; 089 case CLOSED: 090 rs = ClusterStatusProtos.RegionState.State.CLOSED; 091 break; 092 case SPLITTING: 093 rs = ClusterStatusProtos.RegionState.State.SPLITTING; 094 break; 095 case SPLIT: 096 rs = ClusterStatusProtos.RegionState.State.SPLIT; 097 break; 098 case FAILED_OPEN: 099 rs = ClusterStatusProtos.RegionState.State.FAILED_OPEN; 100 break; 101 case FAILED_CLOSE: 102 rs = ClusterStatusProtos.RegionState.State.FAILED_CLOSE; 103 break; 104 case MERGING: 105 rs = ClusterStatusProtos.RegionState.State.MERGING; 106 break; 107 case MERGED: 108 rs = ClusterStatusProtos.RegionState.State.MERGED; 109 break; 110 case SPLITTING_NEW: 111 rs = ClusterStatusProtos.RegionState.State.SPLITTING_NEW; 112 break; 113 case MERGING_NEW: 114 rs = ClusterStatusProtos.RegionState.State.MERGING_NEW; 115 break; 116 case ABNORMALLY_CLOSED: 117 rs = ClusterStatusProtos.RegionState.State.ABNORMALLY_CLOSED; 118 break; 119 default: 120 throw new IllegalStateException(""); 121 } 122 return rs; 123 } 124 125 /** 126 * Convert a protobuf HBaseProtos.RegionState.State to a RegionState.State 127 * 128 * @return the RegionState.State 129 */ 130 public static State convert(ClusterStatusProtos.RegionState.State protoState) { 131 State state; 132 switch (protoState) { 133 case OFFLINE: 134 state = OFFLINE; 135 break; 136 case PENDING_OPEN: 137 case OPENING: 138 state = OPENING; 139 break; 140 case OPEN: 141 state = OPEN; 142 break; 143 case PENDING_CLOSE: 144 case CLOSING: 145 state = CLOSING; 146 break; 147 case CLOSED: 148 state = CLOSED; 149 break; 150 case SPLITTING: 151 state = SPLITTING; 152 break; 153 case SPLIT: 154 state = SPLIT; 155 break; 156 case FAILED_OPEN: 157 state = FAILED_OPEN; 158 break; 159 case FAILED_CLOSE: 160 state = FAILED_CLOSE; 161 break; 162 case MERGING: 163 state = MERGING; 164 break; 165 case MERGED: 166 state = MERGED; 167 break; 168 case SPLITTING_NEW: 169 state = SPLITTING_NEW; 170 break; 171 case MERGING_NEW: 172 state = MERGING_NEW; 173 break; 174 case ABNORMALLY_CLOSED: 175 state = ABNORMALLY_CLOSED; 176 break; 177 default: 178 throw new IllegalStateException("Unhandled state " + protoState); 179 } 180 return state; 181 } 182 } 183 184 private final long stamp; 185 private final RegionInfo hri; 186 private final ServerName serverName; 187 private final State state; 188 // The duration of region in transition 189 private long ritDuration; 190 191 @VisibleForTesting 192 public static RegionState createForTesting(RegionInfo region, State state) { 193 return new RegionState(region, state, System.currentTimeMillis(), null); 194 } 195 196 public RegionState(RegionInfo region, State state, ServerName serverName) { 197 this(region, state, System.currentTimeMillis(), serverName); 198 } 199 200 public RegionState(RegionInfo region, 201 State state, long stamp, ServerName serverName) { 202 this(region, state, stamp, serverName, 0); 203 } 204 205 public RegionState(RegionInfo region, State state, long stamp, ServerName serverName, 206 long ritDuration) { 207 this.hri = region; 208 this.state = state; 209 this.stamp = stamp; 210 this.serverName = serverName; 211 this.ritDuration = ritDuration; 212 } 213 214 public State getState() { 215 return state; 216 } 217 218 public long getStamp() { 219 return stamp; 220 } 221 222 public RegionInfo getRegion() { 223 return hri; 224 } 225 226 public ServerName getServerName() { 227 return serverName; 228 } 229 230 public long getRitDuration() { 231 return ritDuration; 232 } 233 234 /** 235 * Update the duration of region in transition 236 * @param previousStamp previous RegionState's timestamp 237 */ 238 @InterfaceAudience.Private 239 void updateRitDuration(long previousStamp) { 240 this.ritDuration += (this.stamp - previousStamp); 241 } 242 243 public boolean isClosing() { 244 return state == State.CLOSING; 245 } 246 247 public boolean isClosed() { 248 return state == State.CLOSED; 249 } 250 251 public boolean isClosedOrAbnormallyClosed() { 252 return isClosed() || this.state == State.ABNORMALLY_CLOSED; 253 } 254 255 public boolean isOpening() { 256 return state == State.OPENING; 257 } 258 259 public boolean isOpened() { 260 return state == State.OPEN; 261 } 262 263 public boolean isOffline() { 264 return state == State.OFFLINE; 265 } 266 267 public boolean isSplitting() { 268 return state == State.SPLITTING; 269 } 270 271 public boolean isSplit() { 272 return state == State.SPLIT; 273 } 274 275 public boolean isSplittingNew() { 276 return state == State.SPLITTING_NEW; 277 } 278 279 public boolean isFailedOpen() { 280 return state == State.FAILED_OPEN; 281 } 282 283 public boolean isFailedClose() { 284 return state == State.FAILED_CLOSE; 285 } 286 287 public boolean isMerging() { 288 return state == State.MERGING; 289 } 290 291 public boolean isMerged() { 292 return state == State.MERGED; 293 } 294 295 public boolean isMergingNew() { 296 return state == State.MERGING_NEW; 297 } 298 299 public boolean isOnServer(final ServerName sn) { 300 return serverName != null && serverName.equals(sn); 301 } 302 303 public boolean isMergingOnServer(final ServerName sn) { 304 return isOnServer(sn) && isMerging(); 305 } 306 307 public boolean isMergingNewOnServer(final ServerName sn) { 308 return isOnServer(sn) && isMergingNew(); 309 } 310 311 public boolean isMergingNewOrOpenedOnServer(final ServerName sn) { 312 return isOnServer(sn) && (isMergingNew() || isOpened()); 313 } 314 315 public boolean isMergingNewOrOfflineOnServer(final ServerName sn) { 316 return isOnServer(sn) && (isMergingNew() || isOffline()); 317 } 318 319 public boolean isSplittingOnServer(final ServerName sn) { 320 return isOnServer(sn) && isSplitting(); 321 } 322 323 public boolean isSplittingNewOnServer(final ServerName sn) { 324 return isOnServer(sn) && isSplittingNew(); 325 } 326 327 public boolean isSplittingOrOpenedOnServer(final ServerName sn) { 328 return isOnServer(sn) && (isSplitting() || isOpened()); 329 } 330 331 public boolean isSplittingOrSplitOnServer(final ServerName sn) { 332 return isOnServer(sn) && (isSplitting() || isSplit()); 333 } 334 335 public boolean isClosingOrClosedOnServer(final ServerName sn) { 336 return isOnServer(sn) && (isClosing() || isClosed()); 337 } 338 339 public boolean isOpeningOrFailedOpenOnServer(final ServerName sn) { 340 return isOnServer(sn) && (isOpening() || isFailedOpen()); 341 } 342 343 public boolean isOpeningOrOpenedOnServer(final ServerName sn) { 344 return isOnServer(sn) && (isOpening() || isOpened()); 345 } 346 347 public boolean isOpenedOnServer(final ServerName sn) { 348 return isOnServer(sn) && isOpened(); 349 } 350 351 /** 352 * Check if a region state can transition to offline 353 */ 354 public boolean isReadyToOffline() { 355 return isMerged() || isSplit() || isOffline() 356 || isSplittingNew() || isMergingNew(); 357 } 358 359 /** 360 * Check if a region state can transition to online 361 */ 362 public boolean isReadyToOnline() { 363 return isOpened() || isSplittingNew() || isMergingNew(); 364 } 365 366 /** 367 * Check if a region state is one of offline states that 368 * can't transition to pending_close/closing (unassign/offline) 369 */ 370 public boolean isUnassignable() { 371 return isUnassignable(state); 372 } 373 374 /** 375 * Check if a region state is one of offline states that 376 * can't transition to pending_close/closing (unassign/offline) 377 */ 378 public static boolean isUnassignable(State state) { 379 return state == State.MERGED || state == State.SPLIT || state == State.OFFLINE 380 || state == State.SPLITTING_NEW || state == State.MERGING_NEW; 381 } 382 383 @Override 384 public String toString() { 385 return "{" + hri.getShortNameToLog() 386 + " state=" + state 387 + ", ts=" + stamp 388 + ", server=" + serverName + "}"; 389 } 390 391 /** 392 * A slower (but more easy-to-read) stringification 393 */ 394 public String toDescriptiveString() { 395 long relTime = System.currentTimeMillis() - stamp; 396 return hri.getRegionNameAsString() 397 + " state=" + state 398 + ", ts=" + new Date(stamp) + " (" + (relTime/1000) + "s ago)" 399 + ", server=" + serverName; 400 } 401 402 /** 403 * Convert a RegionState to an HBaseProtos.RegionState 404 * 405 * @return the converted HBaseProtos.RegionState 406 */ 407 public ClusterStatusProtos.RegionState convert() { 408 ClusterStatusProtos.RegionState.Builder regionState = ClusterStatusProtos.RegionState.newBuilder(); 409 regionState.setRegionInfo(ProtobufUtil.toRegionInfo(hri)); 410 regionState.setState(state.convert()); 411 regionState.setStamp(getStamp()); 412 return regionState.build(); 413 } 414 415 /** 416 * Convert a protobuf HBaseProtos.RegionState to a RegionState 417 * 418 * @return the RegionState 419 */ 420 public static RegionState convert(ClusterStatusProtos.RegionState proto) { 421 return new RegionState(ProtobufUtil.toRegionInfo(proto.getRegionInfo()), 422 State.convert(proto.getState()), proto.getStamp(), null); 423 } 424 425 /** 426 * Check if two states are the same, except timestamp 427 */ 428 @Override 429 public boolean equals(Object obj) { 430 if (this == obj) return true; 431 if (obj == null || getClass() != obj.getClass()) { 432 return false; 433 } 434 RegionState tmp = (RegionState)obj; 435 436 return RegionInfo.COMPARATOR.compare(tmp.hri, hri) == 0 && tmp.state == state 437 && ((serverName != null && serverName.equals(tmp.serverName)) 438 || (tmp.serverName == null && serverName == null)); 439 } 440 441 /** 442 * Don't count timestamp in hash code calculation 443 */ 444 @Override 445 public int hashCode() { 446 return (serverName != null ? serverName.hashCode() * 11 : 0) 447 + hri.hashCode() + 5 * state.ordinal(); 448 } 449}