protected boolean closeRegion(String encodedName, final boolean abort,
    final ServerName destination) throws NotServingRegionException {
    // Check for permissions to close.
    HRegion actualRegion = this.getRegion(encodedName);
    // Can be null if we're calling close on a region that's not online
    if ((actualRegion != null) && (actualRegion.getCoprocessorHost() != null)) {
      try {
        actualRegion.getCoprocessorHost().preClose(false);
      } catch (IOException exp) {
        LOG.warn("Unable to close region: the coprocessor launched an error ", exp);
        return false;
      }
    }

    // previous can come back 'null' if not in map.
    final Boolean previous =
      this.regionsInTransitionInRS.putIfAbsent(Bytes.toBytes(encodedName), Boolean.FALSE);

    if (Boolean.TRUE.equals(previous)) {
      LOG.info("Received CLOSE for the region:" + encodedName + " , which we are already "
        + "trying to OPEN. Cancelling OPENING.");
      if (!regionsInTransitionInRS.replace(Bytes.toBytes(encodedName), previous, Boolean.FALSE)) {
        // The replace failed. That should be an exceptional case, but theoretically it can happen.
        // We're going to try to do a standard close then.
        LOG.warn("The opening for region " + encodedName + " was done before we could cancel it."
          + " Doing a standard close now");
        return closeRegion(encodedName, abort, destination);
      }
      // Let's get the region from the online region list again
      actualRegion = this.getRegion(encodedName);
      if (actualRegion == null) { // If already online, we still need to close it.
        LOG.info("The opening previously in progress has been cancelled by a CLOSE request.");
        // The master deletes the znode when it receives this exception.
        throw new NotServingRegionException(
          "The region " + encodedName + " was opening but not yet served. Opening is cancelled.");
      }
    } else if (previous == null) {
      LOG.info("Received CLOSE for {}", encodedName);
    } else if (Boolean.FALSE.equals(previous)) {
      LOG.info("Received CLOSE for the region: " + encodedName
        + ", which we are already trying to CLOSE, but not completed yet");
      return true;
    }

    if (actualRegion == null) {
      LOG.debug("Received CLOSE for a region which is not online, and we're not opening.");
      this.regionsInTransitionInRS.remove(Bytes.toBytes(encodedName));
      // The master deletes the znode when it receives this exception.
      throw new NotServingRegionException(
        "The region " + encodedName + " is not online, and is not opening.");
    }

    CloseRegionHandler crh;
    final RegionInfo hri = actualRegion.getRegionInfo();
    if (hri.isMetaRegion()) {
      crh = new CloseMetaHandler(this, this, hri, abort);
    } else {
      crh = new CloseRegionHandler(this, this, hri, abort, destination);
    }
    this.executorService.submit(crh);
    return true;
  }
Close asynchronously a region, can be called from the master or internally by the regionserver
when stopping. If called from the master, the region will update the status.
<p>
If an opening was in progress, this method will cancel it, but will not start a new close. The
coprocessors are not called in this case. A NotServingRegionException exception is thrown.
</p>
<p>
If a close was in progress, this new request will be ignored, and an exception thrown.
</p>
<p>
Provides additional flag to indicate if this region blocks should be evicted from the cache.
</p>
@param encodedName Region to close
@param abort       True if we are aborting
@param destination Where the Region is being moved too... maybe null if unknown.
@return True if closed a region.
@throws NotServingRegionException if the region is not online
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java