@Override
  protected Flow executeFromState(MasterProcedureEnv env, GCMergedRegionsState state)
    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
    if (LOG.isTraceEnabled()) {
      LOG.trace(this + " execute state=" + state);
    }
    try {
      switch (state) {
        case GC_MERGED_REGIONS_PREPARE:
          // If GCMultipleMergedRegionsProcedure processing is slower than the CatalogJanitor's scan
          // interval, it will end resubmitting GCMultipleMergedRegionsProcedure for the same
          // region. We can skip duplicate GCMultipleMergedRegionsProcedure while previous finished
          List<RegionInfo> parents =
            env.getAssignmentManager().getRegionStateStore().getMergeRegions(mergedChild);
          if (parents == null || parents.isEmpty()) {
            LOG.info("{} mergeXXX qualifiers have ALL been deleted",
              mergedChild.getShortNameToLog());
            return Flow.NO_MORE_STATE;
          }
          setNextState(GCMergedRegionsState.GC_MERGED_REGIONS_PURGE);
          break;
        case GC_MERGED_REGIONS_PURGE:
          addChildProcedure(createGCRegionProcedures(env));
          setNextState(GCMergedRegionsState.GC_REGION_EDIT_METADATA);
          break;
        case GC_REGION_EDIT_METADATA:
          env.getAssignmentManager().getRegionStateStore().deleteMergeQualifiers(mergedChild);
          return Flow.NO_MORE_STATE;
        default:
          throw new UnsupportedOperationException(this + " unhandled state=" + state);
      }
    } catch (IOException ioe) {
      // TODO: This is going to spew log?
      LOG.warn("Error trying to GC merged regions {}; retrying...", this.parents.stream()
        .map(r -> RegionInfo.getShortNameToLog(r)).collect(Collectors.joining(", ")), ioe);
    }
    return Flow.HAS_MORE_STATE;
  }
GC regions that have been Merged. Caller determines if it is GC time. This Procedure does not
check. This is a Table Procedure. We take a read lock on the Table. We do NOT keep a lock for the
life of this procedure. The sub-procedures take locks on the Regions they are purging. Replaces a
Procedure that did two regions only at a time instead doing multiple merges in the one go; only
difference from the old {@link GCMergedRegionsState} is the serialization; this class has a
different serialization profile writing out more than just two regions.
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/GCMultipleMergedRegionsProcedure.java