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