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