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.assignment;
019
020import java.io.IOException;
021import org.apache.hadoop.hbase.ServerName;
022import org.apache.hadoop.hbase.client.RegionInfo;
023import org.apache.hadoop.hbase.exceptions.UnexpectedStateException;
024import org.apache.hadoop.hbase.master.RegionState.State;
025import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
026import org.apache.hadoop.hbase.master.procedure.RSProcedureDispatcher.RegionCloseOperation;
027import org.apache.hadoop.hbase.procedure2.ProcedureMetrics;
028import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
029import org.apache.hadoop.hbase.procedure2.RemoteProcedureDispatcher.RemoteOperation;
030import org.apache.yetus.audience.InterfaceAudience;
031
032import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
033import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.CloseRegionProcedureStateData;
034import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionStateTransition.TransitionCode;
035
036/**
037 * The remote procedure used to close a region.
038 */
039@InterfaceAudience.Private
040public class CloseRegionProcedure extends RegionRemoteProcedureBase {
041
042  // For a region move operation, we will assign the region after we unassign it, this is the target
043  // server for the subsequent assign. We will send this value to RS, and RS will record the region
044  // in a Map to tell client that where the region has been moved to. Can be null. And also, can be
045  // wrong(but do not make it wrong intentionally). The client can handle this error.
046  private ServerName assignCandidate;
047
048  private boolean isSplit;
049
050  public CloseRegionProcedure() {
051    super();
052  }
053
054  public CloseRegionProcedure(TransitRegionStateProcedure parent, RegionInfo region,
055    ServerName targetServer, ServerName assignCandidate, boolean isSplit) {
056    super(parent, region, targetServer);
057    this.assignCandidate = assignCandidate;
058    this.isSplit = isSplit;
059  }
060
061  @Override
062  public TableOperationType getTableOperationType() {
063    return TableOperationType.REGION_UNASSIGN;
064  }
065
066  @Override
067  public RemoteOperation newRemoteOperation(MasterProcedureEnv env) {
068    return new RegionCloseOperation(this, region, getProcId(), assignCandidate, isSplit,
069      env.getMasterServices().getMasterActiveTime());
070  }
071
072  @Override
073  protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException {
074    super.serializeStateData(serializer);
075    CloseRegionProcedureStateData.Builder builder = CloseRegionProcedureStateData.newBuilder();
076    if (assignCandidate != null) {
077      builder.setAssignCandidate(ProtobufUtil.toServerName(assignCandidate));
078    }
079    builder.setEvictCache(isSplit);
080    serializer.serialize(builder.build());
081  }
082
083  @Override
084  protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException {
085    super.deserializeStateData(serializer);
086    CloseRegionProcedureStateData data =
087      serializer.deserialize(CloseRegionProcedureStateData.class);
088    if (data.hasAssignCandidate()) {
089      assignCandidate = ProtobufUtil.toServerName(data.getAssignCandidate());
090    }
091    isSplit = data.getEvictCache();
092  }
093
094  @Override
095  protected ProcedureMetrics getProcedureMetrics(MasterProcedureEnv env) {
096    return env.getAssignmentManager().getAssignmentManagerMetrics().getCloseProcMetrics();
097  }
098
099  @Override
100  protected void checkTransition(RegionStateNode regionNode, TransitionCode transitionCode,
101    long seqId) throws UnexpectedStateException {
102    if (transitionCode != TransitionCode.CLOSED) {
103      throw new UnexpectedStateException("Received report unexpected " + transitionCode
104        + " transition, " + regionNode.toShortString() + ", " + this + ", expected CLOSED.");
105    }
106  }
107
108  @Override
109  protected void updateTransitionWithoutPersistingToMeta(MasterProcedureEnv env,
110    RegionStateNode regionNode, TransitionCode transitionCode, long seqId) throws IOException {
111    assert transitionCode == TransitionCode.CLOSED;
112    env.getAssignmentManager().regionClosedWithoutPersistingToMeta(regionNode);
113  }
114
115  @Override
116  protected void restoreSucceedState(AssignmentManager am, RegionStateNode regionNode, long seqId)
117    throws IOException {
118    if (regionNode.getState() == State.CLOSED) {
119      // should have already been persisted, ignore
120      return;
121    }
122    am.regionClosedWithoutPersistingToMeta(regionNode);
123  }
124}