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  public CloseRegionProcedure() {
049    super();
050  }
051
052  public CloseRegionProcedure(TransitRegionStateProcedure parent, RegionInfo region,
053    ServerName targetServer, ServerName assignCandidate) {
054    super(parent, region, targetServer);
055    this.assignCandidate = assignCandidate;
056  }
057
058  @Override
059  public TableOperationType getTableOperationType() {
060    return TableOperationType.REGION_UNASSIGN;
061  }
062
063  @Override
064  public RemoteOperation newRemoteOperation() {
065    return new RegionCloseOperation(this, region, getProcId(), assignCandidate);
066  }
067
068  @Override
069  protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException {
070    super.serializeStateData(serializer);
071    CloseRegionProcedureStateData.Builder builder = CloseRegionProcedureStateData.newBuilder();
072    if (assignCandidate != null) {
073      builder.setAssignCandidate(ProtobufUtil.toServerName(assignCandidate));
074    }
075    serializer.serialize(builder.build());
076  }
077
078  @Override
079  protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException {
080    super.deserializeStateData(serializer);
081    CloseRegionProcedureStateData data =
082      serializer.deserialize(CloseRegionProcedureStateData.class);
083    if (data.hasAssignCandidate()) {
084      assignCandidate = ProtobufUtil.toServerName(data.getAssignCandidate());
085    }
086  }
087
088  @Override
089  protected ProcedureMetrics getProcedureMetrics(MasterProcedureEnv env) {
090    return env.getAssignmentManager().getAssignmentManagerMetrics().getCloseProcMetrics();
091  }
092
093  @Override
094  protected void checkTransition(RegionStateNode regionNode, TransitionCode transitionCode,
095    long seqId) throws UnexpectedStateException {
096    if (transitionCode != TransitionCode.CLOSED) {
097      throw new UnexpectedStateException("Received report unexpected " + transitionCode
098        + " transition, " + regionNode.toShortString() + ", " + this + ", expected CLOSED.");
099    }
100  }
101
102  @Override
103  protected void updateTransitionWithoutPersistingToMeta(MasterProcedureEnv env,
104    RegionStateNode regionNode, TransitionCode transitionCode, long seqId) throws IOException {
105    assert transitionCode == TransitionCode.CLOSED;
106    env.getAssignmentManager().regionClosedWithoutPersistingToMeta(regionNode);
107  }
108
109  @Override
110  protected void restoreSucceedState(AssignmentManager am, RegionStateNode regionNode, long seqId)
111    throws IOException {
112    if (regionNode.getState() == State.CLOSED) {
113      // should have already been persisted, ignore
114      return;
115    }
116    am.regionClosedWithoutPersistingToMeta(regionNode);
117  }
118}