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.hadoop.hbase.shaded.protobuf.ProtobufUtil; 027import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos; 028 029/** 030 * State of a Region while undergoing transitions. 031 * 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 * 127 * @return the RegionState.State 128 */ 129 public static State convert(ClusterStatusProtos.RegionState.State protoState) { 130 State state; 131 switch (protoState) { 132 case OFFLINE: 133 state = OFFLINE; 134 break; 135 case PENDING_OPEN: 136 case OPENING: 137 state = OPENING; 138 break; 139 case OPEN: 140 state = OPEN; 141 break; 142 case PENDING_CLOSE: 143 case CLOSING: 144 state = CLOSING; 145 break; 146 case CLOSED: 147 state = CLOSED; 148 break; 149 case SPLITTING: 150 state = SPLITTING; 151 break; 152 case SPLIT: 153 state = SPLIT; 154 break; 155 case FAILED_OPEN: 156 state = FAILED_OPEN; 157 break; 158 case FAILED_CLOSE: 159 state = FAILED_CLOSE; 160 break; 161 case MERGING: 162 state = MERGING; 163 break; 164 case MERGED: 165 state = MERGED; 166 break; 167 case SPLITTING_NEW: 168 state = SPLITTING_NEW; 169 break; 170 case MERGING_NEW: 171 state = MERGING_NEW; 172 break; 173 case ABNORMALLY_CLOSED: 174 state = ABNORMALLY_CLOSED; 175 break; 176 default: 177 throw new IllegalStateException("Unhandled state " + protoState); 178 } 179 return state; 180 } 181 } 182 183 private final long stamp; 184 private final RegionInfo hri; 185 private final ServerName serverName; 186 private final State state; 187 // The duration of region in transition 188 private long ritDuration; 189 190 public static RegionState createForTesting(RegionInfo region, State state) { 191 return new RegionState(region, state, System.currentTimeMillis(), null); 192 } 193 194 public RegionState(RegionInfo region, State state, ServerName serverName) { 195 this(region, state, System.currentTimeMillis(), serverName); 196 } 197 198 public RegionState(RegionInfo region, 199 State state, long stamp, ServerName serverName) { 200 this(region, state, stamp, serverName, 0); 201 } 202 203 public RegionState(RegionInfo region, State state, long stamp, ServerName serverName, 204 long ritDuration) { 205 this.hri = region; 206 this.state = state; 207 this.stamp = stamp; 208 this.serverName = serverName; 209 this.ritDuration = ritDuration; 210 } 211 212 public State getState() { 213 return state; 214 } 215 216 public long getStamp() { 217 return stamp; 218 } 219 220 public RegionInfo getRegion() { 221 return hri; 222 } 223 224 public ServerName getServerName() { 225 return serverName; 226 } 227 228 public long getRitDuration() { 229 return ritDuration; 230 } 231 232 /** 233 * Update the duration of region in transition 234 * @param previousStamp previous RegionState's timestamp 235 */ 236 @InterfaceAudience.Private 237 void updateRitDuration(long previousStamp) { 238 this.ritDuration += (this.stamp - previousStamp); 239 } 240 241 public boolean isClosing() { 242 return state == State.CLOSING; 243 } 244 245 public boolean isClosed() { 246 return state == State.CLOSED; 247 } 248 249 public boolean isClosedOrAbnormallyClosed() { 250 return isClosed() || this.state == State.ABNORMALLY_CLOSED; 251 } 252 253 public boolean isOpening() { 254 return state == State.OPENING; 255 } 256 257 public boolean isOpened() { 258 return state == State.OPEN; 259 } 260 261 public boolean isOffline() { 262 return state == State.OFFLINE; 263 } 264 265 public boolean isSplitting() { 266 return state == State.SPLITTING; 267 } 268 269 public boolean isSplit() { 270 return state == State.SPLIT; 271 } 272 273 public boolean isSplittingNew() { 274 return state == State.SPLITTING_NEW; 275 } 276 277 public boolean isFailedOpen() { 278 return state == State.FAILED_OPEN; 279 } 280 281 public boolean isFailedClose() { 282 return state == State.FAILED_CLOSE; 283 } 284 285 public boolean isMerging() { 286 return state == State.MERGING; 287 } 288 289 public boolean isMerged() { 290 return state == State.MERGED; 291 } 292 293 public boolean isMergingNew() { 294 return state == State.MERGING_NEW; 295 } 296 297 public boolean isOnServer(final ServerName sn) { 298 return serverName != null && serverName.equals(sn); 299 } 300 301 public boolean isMergingOnServer(final ServerName sn) { 302 return isOnServer(sn) && isMerging(); 303 } 304 305 public boolean isMergingNewOnServer(final ServerName sn) { 306 return isOnServer(sn) && isMergingNew(); 307 } 308 309 public boolean isMergingNewOrOpenedOnServer(final ServerName sn) { 310 return isOnServer(sn) && (isMergingNew() || isOpened()); 311 } 312 313 public boolean isMergingNewOrOfflineOnServer(final ServerName sn) { 314 return isOnServer(sn) && (isMergingNew() || isOffline()); 315 } 316 317 public boolean isSplittingOnServer(final ServerName sn) { 318 return isOnServer(sn) && isSplitting(); 319 } 320 321 public boolean isSplittingNewOnServer(final ServerName sn) { 322 return isOnServer(sn) && isSplittingNew(); 323 } 324 325 public boolean isSplittingOrOpenedOnServer(final ServerName sn) { 326 return isOnServer(sn) && (isSplitting() || isOpened()); 327 } 328 329 public boolean isSplittingOrSplitOnServer(final ServerName sn) { 330 return isOnServer(sn) && (isSplitting() || isSplit()); 331 } 332 333 public boolean isClosingOrClosedOnServer(final ServerName sn) { 334 return isOnServer(sn) && (isClosing() || isClosed()); 335 } 336 337 public boolean isOpeningOrFailedOpenOnServer(final ServerName sn) { 338 return isOnServer(sn) && (isOpening() || isFailedOpen()); 339 } 340 341 public boolean isOpeningOrOpenedOnServer(final ServerName sn) { 342 return isOnServer(sn) && (isOpening() || isOpened()); 343 } 344 345 public boolean isOpenedOnServer(final ServerName sn) { 346 return isOnServer(sn) && isOpened(); 347 } 348 349 /** 350 * Check if a region state can transition to offline 351 */ 352 public boolean isReadyToOffline() { 353 return isMerged() || isSplit() || isOffline() 354 || isSplittingNew() || isMergingNew(); 355 } 356 357 /** 358 * Check if a region state can transition to online 359 */ 360 public boolean isReadyToOnline() { 361 return isOpened() || isSplittingNew() || isMergingNew(); 362 } 363 364 /** 365 * Check if a region state is one of offline states that 366 * can't transition to pending_close/closing (unassign/offline) 367 */ 368 public boolean isUnassignable() { 369 return isUnassignable(state); 370 } 371 372 /** 373 * Check if a region state is one of offline states that 374 * can't transition to pending_close/closing (unassign/offline) 375 */ 376 public static boolean isUnassignable(State state) { 377 return state == State.MERGED || state == State.SPLIT || state == State.OFFLINE 378 || state == State.SPLITTING_NEW || state == State.MERGING_NEW; 379 } 380 381 @Override 382 public String toString() { 383 return "{" + hri.getShortNameToLog() 384 + " state=" + state 385 + ", ts=" + stamp 386 + ", server=" + serverName + "}"; 387 } 388 389 /** 390 * A slower (but more easy-to-read) stringification 391 */ 392 public String toDescriptiveString() { 393 long relTime = System.currentTimeMillis() - stamp; 394 return hri.getRegionNameAsString() 395 + " state=" + state 396 + ", ts=" + new Date(stamp) + " (" + (relTime/1000) + "s ago)" 397 + ", server=" + serverName; 398 } 399 400 /** 401 * Convert a RegionState to an HBaseProtos.RegionState 402 * 403 * @return the converted HBaseProtos.RegionState 404 */ 405 public ClusterStatusProtos.RegionState convert() { 406 ClusterStatusProtos.RegionState.Builder regionState = ClusterStatusProtos.RegionState.newBuilder(); 407 regionState.setRegionInfo(ProtobufUtil.toRegionInfo(hri)); 408 regionState.setState(state.convert()); 409 regionState.setStamp(getStamp()); 410 return regionState.build(); 411 } 412 413 /** 414 * Convert a protobuf HBaseProtos.RegionState to a RegionState 415 * 416 * @return the RegionState 417 */ 418 public static RegionState convert(ClusterStatusProtos.RegionState proto) { 419 return new RegionState(ProtobufUtil.toRegionInfo(proto.getRegionInfo()), 420 State.convert(proto.getState()), proto.getStamp(), null); 421 } 422 423 /** 424 * Check if two states are the same, except timestamp 425 */ 426 @Override 427 public boolean equals(Object obj) { 428 if (this == obj) return true; 429 if (obj == null || getClass() != obj.getClass()) { 430 return false; 431 } 432 RegionState tmp = (RegionState)obj; 433 434 return RegionInfo.COMPARATOR.compare(tmp.hri, hri) == 0 && tmp.state == state 435 && ((serverName != null && serverName.equals(tmp.serverName)) 436 || (tmp.serverName == null && serverName == null)); 437 } 438 439 /** 440 * Don't count timestamp in hash code calculation 441 */ 442 @Override 443 public int hashCode() { 444 return (serverName != null ? serverName.hashCode() * 11 : 0) 445 + hri.hashCode() + 5 * state.ordinal(); 446 } 447}