@Override
  protected Flow executeFromState(MasterProcedureEnv env, GCRegionState state)
    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
    if (LOG.isTraceEnabled()) {
      LOG.trace(this + " execute state=" + state);
    }
    MasterServices masterServices = env.getMasterServices();
    try {
      switch (state) {
        case GC_REGION_PREPARE:
          // Nothing to do to prepare.
          setNextState(GCRegionState.GC_REGION_ARCHIVE);
          break;
        case GC_REGION_ARCHIVE:
          MasterFileSystem mfs = masterServices.getMasterFileSystem();
          FileSystem fs = mfs.getFileSystem();
          if (HFileArchiver.exists(masterServices.getConfiguration(), fs, getRegion())) {
            if (LOG.isDebugEnabled()) {
              LOG.debug("Archiving region=" + getRegion().getShortNameToLog());
            }
            HFileArchiver.archiveRegion(masterServices.getConfiguration(), fs, getRegion());
          }
          FileSystem walFs = mfs.getWALFileSystem();
          // Cleanup the directories on WAL filesystem also
          Path regionWALDir = CommonFSUtils.getWALRegionDir(env.getMasterConfiguration(),
            getRegion().getTable(), getRegion().getEncodedName());
          if (walFs.exists(regionWALDir)) {
            if (!walFs.delete(regionWALDir, true)) {
              LOG.debug("Failed to delete {}", regionWALDir);
            }
          }
          Path wrongRegionWALDir = CommonFSUtils.getWrongWALRegionDir(env.getMasterConfiguration(),
            getRegion().getTable(), getRegion().getEncodedName());
          if (walFs.exists(wrongRegionWALDir)) {
            if (!walFs.delete(wrongRegionWALDir, true)) {
              LOG.debug("Failed to delete {}", regionWALDir);
            }
          }
          setNextState(GCRegionState.GC_REGION_PURGE_METADATA);
          break;
        case GC_REGION_PURGE_METADATA:
          // TODO: Purge metadata before removing from HDFS? This ordering is copied
          // from CatalogJanitor.
          AssignmentManager am = masterServices.getAssignmentManager();
          if (am != null) {
            if (am.getRegionStates() != null) {
              am.getRegionStates().deleteRegion(getRegion());
            }
          }
          env.getAssignmentManager().getRegionStateStore().deleteRegion(getRegion());
          masterServices.getServerManager().removeRegion(getRegion());
          FavoredNodesManager fnm = masterServices.getFavoredNodesManager();
          if (fnm != null) {
            fnm.deleteFavoredNodesForRegions(Lists.newArrayList(getRegion()));
          }
          return Flow.NO_MORE_STATE;
        default:
          throw new UnsupportedOperationException(this + " unhandled state=" + state);
      }
    } catch (IOException ioe) {
      // TODO: This is going to spew log? Add retry backoff
      LOG.warn("Error trying to GC " + getRegion().getShortNameToLog() + "; retrying...", ioe);
    }
    return Flow.HAS_MORE_STATE;
  }
GC a Region that is no longer in use. It has been split or merged away. Caller determines if it
is GC time. This Procedure does not check.
<p>
This is a Region StateMachine Procedure. We take a read lock on the Table and then exclusive on
the Region.
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/GCRegionProcedure.java