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.TableName;
022import org.apache.hadoop.hbase.client.RegionInfo;
023import org.apache.hadoop.hbase.master.procedure.AbstractStateMachineTableProcedure;
024import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
025import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
026import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
027import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
028import org.apache.yetus.audience.InterfaceAudience;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
033import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos;
034import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.GCMergedRegionsState;
035
036/**
037 * GC regions that have been Merged. Caller determines if it is GC time. This Procedure does not
038 * check.
039 * <p>
040 * This is a Table Procedure. We take a read lock on the Table. We do NOT keep a lock for the life
041 * of this procedure. The subprocedures take locks on the Regions they are purging.
042 * @deprecated 2.3.0 Use {@link GCMultipleMergedRegionsProcedure}.
043 */
044@InterfaceAudience.Private
045@Deprecated
046public class GCMergedRegionsProcedure
047  extends AbstractStateMachineTableProcedure<GCMergedRegionsState> {
048  private static final Logger LOG = LoggerFactory.getLogger(GCMergedRegionsProcedure.class);
049  private RegionInfo father;
050  private RegionInfo mother;
051  private RegionInfo mergedChild;
052
053  public GCMergedRegionsProcedure(final MasterProcedureEnv env, final RegionInfo mergedChild,
054    final RegionInfo father, final RegionInfo mother) {
055    super(env);
056    this.father = father;
057    this.mother = mother;
058    this.mergedChild = mergedChild;
059  }
060
061  public GCMergedRegionsProcedure() {
062    // Required by the Procedure framework to create the procedure on replay
063    super();
064  }
065
066  @Override
067  public TableOperationType getTableOperationType() {
068    return TableOperationType.MERGED_REGIONS_GC;
069  }
070
071  @Override
072  protected Flow executeFromState(MasterProcedureEnv env, GCMergedRegionsState state)
073    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
074    if (LOG.isTraceEnabled()) {
075      LOG.trace(this + " execute state=" + state);
076    }
077    try {
078      switch (state) {
079        case GC_MERGED_REGIONS_PREPARE:
080          // Nothing to do to prepare.
081          setNextState(GCMergedRegionsState.GC_MERGED_REGIONS_PURGE);
082          break;
083        case GC_MERGED_REGIONS_PURGE:
084          addChildProcedure(createGCRegionProcedures(env));
085          setNextState(GCMergedRegionsState.GC_REGION_EDIT_METADATA);
086          break;
087        case GC_REGION_EDIT_METADATA:
088          env.getAssignmentManager().getRegionStateStore().deleteMergeQualifiers(mergedChild);
089          return Flow.NO_MORE_STATE;
090        default:
091          throw new UnsupportedOperationException(this + " unhandled state=" + state);
092      }
093    } catch (IOException ioe) {
094      // TODO: This is going to spew log?
095      LOG.warn("Error trying to GC merged regions " + this.father.getShortNameToLog() + " & "
096        + this.mother.getShortNameToLog() + "; retrying...", ioe);
097    }
098    return Flow.HAS_MORE_STATE;
099  }
100
101  private GCRegionProcedure[] createGCRegionProcedures(final MasterProcedureEnv env) {
102    GCRegionProcedure[] procs = new GCRegionProcedure[2];
103    int index = 0;
104    for (RegionInfo hri : new RegionInfo[] { this.father, this.mother }) {
105      GCRegionProcedure proc = new GCRegionProcedure(env, hri);
106      proc.setOwner(env.getRequestUser().getShortName());
107      procs[index++] = proc;
108    }
109    return procs;
110  }
111
112  @Override
113  protected void rollbackState(MasterProcedureEnv env, GCMergedRegionsState state)
114    throws IOException, InterruptedException {
115    // no-op
116  }
117
118  @Override
119  protected GCMergedRegionsState getState(int stateId) {
120    return GCMergedRegionsState.forNumber(stateId);
121  }
122
123  @Override
124  protected int getStateId(GCMergedRegionsState state) {
125    return state.getNumber();
126  }
127
128  @Override
129  protected GCMergedRegionsState getInitialState() {
130    return GCMergedRegionsState.GC_MERGED_REGIONS_PREPARE;
131  }
132
133  @Override
134  protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException {
135    super.serializeStateData(serializer);
136    final MasterProcedureProtos.GCMergedRegionsStateData.Builder msg =
137      MasterProcedureProtos.GCMergedRegionsStateData.newBuilder()
138        .setParentA(ProtobufUtil.toRegionInfo(this.father))
139        .setParentB(ProtobufUtil.toRegionInfo(this.mother))
140        .setMergedChild(ProtobufUtil.toRegionInfo(this.mergedChild));
141    serializer.serialize(msg.build());
142  }
143
144  @Override
145  protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException {
146    super.deserializeStateData(serializer);
147    final MasterProcedureProtos.GCMergedRegionsStateData msg =
148      serializer.deserialize(MasterProcedureProtos.GCMergedRegionsStateData.class);
149    this.father = ProtobufUtil.toRegionInfo(msg.getParentA());
150    this.mother = ProtobufUtil.toRegionInfo(msg.getParentB());
151    this.mergedChild = ProtobufUtil.toRegionInfo(msg.getMergedChild());
152  }
153
154  @Override
155  public void toStringClassDetails(StringBuilder sb) {
156    sb.append(getClass().getSimpleName());
157    sb.append(" child=");
158    sb.append(this.mergedChild.getShortNameToLog());
159    sb.append(", father=");
160    sb.append(this.father.getShortNameToLog());
161    sb.append(", mother=");
162    sb.append(this.mother.getShortNameToLog());
163  }
164
165  @Override
166  public TableName getTableName() {
167    return this.mergedChild.getTable();
168  }
169}