private void recursiveDestroyRegion(Set eventSet, RegionEventImpl regionEvent, boolean cacheWrite)
      throws CacheWriterException, TimeoutException {
    final boolean isClose = regionEvent.getOperation().isClose();
    // do the cacheWriter beforeRegionDestroy first
    if (eventSet != null && cacheWrite) {
      try {
        cacheWriteBeforeRegionDestroy(regionEvent);
      } catch (CancelException e) {
        if (!cache.forcedDisconnect()) {
          logger.warn("recursiveDestroyRegion: problem in cacheWriteBeforeRegionDestroy", e);
        }
      }
    }

    getEventTracker().stop();
    if (logger.isTraceEnabled(LogMarker.RVV_VERBOSE) && getVersionVector() != null) {
      logger.trace(LogMarker.RVV_VERBOSE, "version vector for {} is {}", getName(),
          getVersionVector().fullToString());
    }
    cancelTTLExpiryTask();
    cancelIdleExpiryTask();
    cancelAllEntryExpiryTasks();
    if (!isInternalRegion()) {
      getCachePerfStats().incRegions(-1);
    }
    cache.getInternalResourceManager(false).removeResourceListener(this);
    if (getMembershipAttributes().hasRequiredRoles()) {
      if (!isInternalRegion()) {
        getCachePerfStats().incReliableRegions(-1);
      }
    }

    // Note we need to do this even if we don't have a listener
    // because of the SystemMemberCacheEventProcessor. Once we have
    // a way to check for existence of SystemMemberCacheEventProcessor listeners
    // then the add only needs to be done if hasListener || hasAdminListener
    if (eventSet != null) {
      eventSet.add(regionEvent);
    }

    try {
      // call recursiveDestroyRegion on each subregion and remove it
      // from this subregion map
      Collection values = subregions.values();
      for (Iterator itr = values.iterator(); itr.hasNext();) {
        // element is a LocalRegion
        Object element = itr.next();
        LocalRegion region;
        try {
          setThreadInitLevelRequirement(BEFORE_INITIAL_IMAGE);
          try {
            // converts to a LocalRegion
            region = toRegion(element);
          } finally {
            setThreadInitLevelRequirement(AFTER_INITIAL_IMAGE);
          }
        } catch (CancelException ignore) {
          // ignore, keep going through the motions though
          region = (LocalRegion) element;
        } catch (RegionDestroyedException ignore) {
          // SharedRegionData was destroyed
          continue;
        }

        // if the region is destroyed, then it is a race condition with
        // failed initialization removing it from the parent subregion map
        if (region.isDestroyed) {
          continue;
        }
        // BEGIN operating on subregion of this region (rgn)
        if (eventSet != null) {
          regionEvent = (RegionEventImpl) regionEvent.clone();
          regionEvent.region = region;
        }

        try {
          region.recursiveDestroyRegion(eventSet, regionEvent, cacheWrite);
          if (!region.isInternalRegion()) {
            InternalDistributedSystem system = region.cache.getInternalDistributedSystem();
            system.handleResourceEvent(ResourceEvent.REGION_REMOVE, region);
          }
        } catch (CancelException e) {
          if (!cache.forcedDisconnect()) {
            logger.warn(String.format(
                "recursiveDestroyRegion: recursion failed due to cache closure. region, %s",
                region.getFullPath()),
                e);
          }
        }
        // remove from this subregion map;
        itr.remove();
        // END operating on subregion of this region
      }

      try {
        if (indexManager != null) {
          try {
            if (this instanceof BucketRegion) {
              indexManager.removeBucketIndexes(getPartitionedRegion());
            }
            indexManager.destroy();
          } catch (QueryException e) {
            throw new IndexMaintenanceException(e);
          }
        }
      } catch (CancelException e) {
        if (!cache.forcedDisconnect()) {
          logger.warn(String.format(
              "basicDestroyRegion: index removal failed due to cache closure. region, %s",
              getFullPath()),
              e);
        }
      }
    } finally {
      // mark this region as destroyed.
      if (regionEvent.isReinitializing()) {
        reinitialized_old = true;
      }
      cache.setRegionByPath(getFullPath(), null);

      getEventTracker().stop();

      if (diskRegion != null) {
        diskRegion.prepareForClose();
      }

      isDestroyed = true;
      // after isDestroyed is set to true call removeResourceListener
      cache.getInternalResourceManager(false).removeResourceListener(this);
      closeEntries();
      if (logger.isDebugEnabled()) {
        logger.debug("recursiveDestroyRegion: Region Destroyed: {}", getFullPath());
      }

      // if eventSet is null then we need to close the listener as well
      // otherwise, the listener will be closed after the destroy event
      try {
        postDestroyRegion(!isClose, regionEvent);
      } catch (CancelException e) {
        logger.warn(String.format(
            "recursiveDestroyRegion: postDestroyRegion failed due to cache closure. region, %s",
            getFullPath()),
            e);
      }

      // Destroy cqs created against this Region in a server cache.
      if (getServerProxy() == null) {
        closeCqs();
      }

      detachPool();

      if (eventSet != null) {
        closeCallbacksExceptListener();
      } else {
        closeAllCallbacks();
      }
      if (getConcurrencyChecksEnabled() && getDataPolicy().withReplication()
          && !cache.isClosed()) {
        cache.getTombstoneService().unscheduleTombstones(this);
      }
      if (hasOwnStats) {
        cachePerfStats.close();
      }
    }
  }
Removes entries and recursively destroys subregions.

@param eventSet collects the events for all destroyed regions if null, then we're closing so
       don't send events to callbacks or destroy the disk region
geode-core/src/main/java/org/apache/geode/internal/cache/LocalRegion.java