/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.master;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos;
/**
* State of a Region while undergoing transitions.
* Region state cannot be modified except the stamp field.
* So it is almost immutable.
*/
@InterfaceAudience.Private
public class RegionState implements org.apache.hadoop.io.Writable {
public enum State {
OFFLINE, // region is in an offline state
PENDING_OPEN, // sent rpc to server to open but has not begun
OPENING, // server has begun to open but not yet done
OPEN, // server opened region and updated meta
PENDING_CLOSE, // sent rpc to server to close but has not begun
CLOSING, // server has begun to close but not yet done
CLOSED, // server closed region and updated meta
SPLITTING, // server started split of a region
SPLIT // server completed split of a region
}
// Many threads can update the state at the stamp at the same time
private final AtomicLong stamp;
private HRegionInfo region;
private volatile ServerName serverName;
private volatile State state;
public RegionState() {
this.stamp = new AtomicLong(System.currentTimeMillis());
}
public RegionState(HRegionInfo region, State state) {
this(region, state, System.currentTimeMillis(), null);
}
public RegionState(HRegionInfo region,
State state, long stamp, ServerName serverName) {
this.region = region;
this.state = state;
this.stamp = new AtomicLong(stamp);
this.serverName = serverName;
}
public void updateTimestampToNow() {
setTimestamp(System.currentTimeMillis());
}
public State getState() {
return state;
}
public long getStamp() {
return stamp.get();
}
public HRegionInfo getRegion() {
return region;
}
public ServerName getServerName() {
return serverName;
}
public boolean isClosing() {
return state == State.CLOSING;
}
public boolean isClosed() {
return state == State.CLOSED;
}
public boolean isPendingClose() {
return state == State.PENDING_CLOSE;
}
public boolean isOpening() {
return state == State.OPENING;
}
public boolean isOpened() {
return state == State.OPEN;
}
public boolean isPendingOpen() {
return state == State.PENDING_OPEN;
}
public boolean isOffline() {
return state == State.OFFLINE;
}
public boolean isSplitting() {
return state == State.SPLITTING;
}
public boolean isSplit() {
return state == State.SPLIT;
}
public boolean isPendingOpenOrOpeningOnServer(final ServerName sn) {
return isOnServer(sn) && (isPendingOpen() || isOpening());
}
public boolean isPendingCloseOrClosingOnServer(final ServerName sn) {
return isOnServer(sn) && (isPendingClose() || isClosing());
}
public boolean isOnServer(final ServerName sn) {
return serverName != null && serverName.equals(sn);
}
@Override
public String toString() {
return "{" + region.getRegionNameAsString()
+ " state=" + state
+ ", ts=" + stamp
+ ", server=" + serverName + "}";
}
/**
* A slower (but more easy-to-read) stringification
*/
public String toDescriptiveString() {
long lstamp = stamp.get();
long relTime = System.currentTimeMillis() - lstamp;
return region.getRegionNameAsString()
+ " state=" + state
+ ", ts=" + new Date(lstamp) + " (" + (relTime/1000) + "s ago)"
+ ", server=" + serverName;
}
/**
* Convert a RegionState to an HBaseProtos.RegionState
*
* @return the converted HBaseProtos.RegionState
*/
public ClusterStatusProtos.RegionState convert() {
ClusterStatusProtos.RegionState.Builder regionState = ClusterStatusProtos.RegionState.newBuilder();
ClusterStatusProtos.RegionState.State rs;
switch (regionState.getState()) {
case OFFLINE:
rs = ClusterStatusProtos.RegionState.State.OFFLINE;
break;
case PENDING_OPEN:
rs = ClusterStatusProtos.RegionState.State.PENDING_OPEN;
break;
case OPENING:
rs = ClusterStatusProtos.RegionState.State.OPENING;
break;
case OPEN:
rs = ClusterStatusProtos.RegionState.State.OPEN;
break;
case PENDING_CLOSE:
rs = ClusterStatusProtos.RegionState.State.PENDING_CLOSE;
break;
case CLOSING:
rs = ClusterStatusProtos.RegionState.State.CLOSING;
break;
case CLOSED:
rs = ClusterStatusProtos.RegionState.State.CLOSED;
break;
case SPLITTING:
rs = ClusterStatusProtos.RegionState.State.SPLITTING;
break;
case SPLIT:
rs = ClusterStatusProtos.RegionState.State.SPLIT;
break;
default:
throw new IllegalStateException("");
}
regionState.setRegionInfo(HRegionInfo.convert(region));
regionState.setState(rs);
regionState.setStamp(getStamp());
return regionState.build();
}
/**
* Convert a protobuf HBaseProtos.RegionState to a RegionState
*
* @return the RegionState
*/
public static RegionState convert(ClusterStatusProtos.RegionState proto) {
RegionState.State state;
switch (proto.getState()) {
case OFFLINE:
state = State.OFFLINE;
break;
case PENDING_OPEN:
state = State.PENDING_OPEN;
break;
case OPENING:
state = State.OPENING;
break;
case OPEN:
state = State.OPEN;
break;
case PENDING_CLOSE:
state = State.PENDING_CLOSE;
break;
case CLOSING:
state = State.CLOSING;
break;
case CLOSED:
state = State.CLOSED;
break;
case SPLITTING:
state = State.SPLITTING;
break;
case SPLIT:
state = State.SPLIT;
break;
default:
throw new IllegalStateException("");
}
return new RegionState(HRegionInfo.convert(proto.getRegionInfo()),state,proto.getStamp(),null);
}
protected void setTimestamp(final long timestamp) {
stamp.set(timestamp);
}
/**
* @deprecated Writables are going away
*/
@Deprecated
@Override
public void readFields(DataInput in) throws IOException {
region = new HRegionInfo();
region.readFields(in);
state = State.valueOf(in.readUTF());
stamp.set(in.readLong());
}
/**
* @deprecated Writables are going away
*/
@Deprecated
@Override
public void write(DataOutput out) throws IOException {
region.write(out);
out.writeUTF(state.name());
out.writeLong(stamp.get());
}
}