private void unloadRegions(ServerName server, List<ServerName> regionServers,
    List<RegionInfo> movedRegions, List<String> isolateRegionIdArray) throws Exception {
    while (true) {
      List<RegionInfo> isolateRegionInfoList = Collections.synchronizedList(new ArrayList<>());
      RegionInfo isolateRegionInfo = null;
      if (isolateRegionIdArray != null && !isolateRegionIdArray.isEmpty()) {
        // Region will be moved to target region server with Ack mode.
        final ExecutorService isolateRegionPool = Executors.newFixedThreadPool(maxthreads);
        List<Future<Boolean>> isolateRegionTaskList = new ArrayList<>();
        List<RegionInfo> recentlyIsolatedRegion = Collections.synchronizedList(new ArrayList<>());
        boolean allRegionOpsSuccessful = true;
        boolean isMetaIsolated = false;
        RegionInfo metaRegionInfo = RegionInfoBuilder.FIRST_META_REGIONINFO;
        List<HRegionLocation> hRegionLocationRegionIsolation =
          Collections.synchronizedList(new ArrayList<>());
        for (String isolateRegionId : isolateRegionIdArray) {
          if (isolateRegionId.equalsIgnoreCase(metaRegionInfo.getEncodedName())) {
            isMetaIsolated = true;
            continue;
          }
          Result result = MetaTableAccessor.scanByRegionEncodedName(conn, isolateRegionId);
          HRegionLocation hRegionLocation =
            MetaTableAccessor.getRegionLocation(conn, result.getRow());
          if (hRegionLocation != null) {
            hRegionLocationRegionIsolation.add(hRegionLocation);
          } else {
            LOG.error("Region " + isolateRegionId + " doesn't exists/can't fetch from"
              + " meta...Quitting now");
            // We only move the regions if all the regions were found.
            allRegionOpsSuccessful = false;
            break;
          }
        }

        if (!allRegionOpsSuccessful) {
          break;
        }
        // If hbase:meta region was isolated, then it needs to be part of isolateRegionInfoList.
        if (isMetaIsolated) {
          ZKWatcher zkWatcher = new ZKWatcher(conf, null, null);
          List<HRegionLocation> result = new ArrayList<>();
          for (String znode : zkWatcher.getMetaReplicaNodes()) {
            String path = ZNodePaths.joinZNode(zkWatcher.getZNodePaths().baseZNode, znode);
            int replicaId = zkWatcher.getZNodePaths().getMetaReplicaIdFromPath(path);
            RegionState state = MetaTableLocator.getMetaRegionState(zkWatcher, replicaId);
            result.add(new HRegionLocation(state.getRegion(), state.getServerName()));
          }
          ServerName metaSeverName = result.get(0).getServerName();
          // For isolating hbase:meta, it should move explicitly in Ack mode,
          // hence the forceMoveRegionByAck = true.
          if (!metaSeverName.equals(server)) {
            LOG.info("Region of hbase:meta " + metaRegionInfo.getEncodedName() + " is on server "
              + metaSeverName + " moving to " + server);
            submitRegionMovesWhileUnloading(metaSeverName, Collections.singletonList(server),
              movedRegions, Collections.singletonList(metaRegionInfo), true);
          } else {
            LOG.info("Region of hbase:meta " + metaRegionInfo.getEncodedName() + " already exists"
              + " on server : " + server);
          }
          isolateRegionInfoList.add(RegionInfoBuilder.FIRST_META_REGIONINFO);
        }

        if (!hRegionLocationRegionIsolation.isEmpty()) {
          for (HRegionLocation hRegionLocation : hRegionLocationRegionIsolation) {
            isolateRegionInfo = hRegionLocation.getRegion();
            isolateRegionInfoList.add(isolateRegionInfo);
            if (hRegionLocation.getServerName() == server) {
              LOG.info("Region " + hRegionLocation.getRegion().getEncodedName() + " already exists"
                + " on server : " + server.getHostname());
            } else {
              Future<Boolean> isolateRegionTask =
                isolateRegionPool.submit(new MoveWithAck(conn, isolateRegionInfo,
                  hRegionLocation.getServerName(), server, recentlyIsolatedRegion));
              isolateRegionTaskList.add(isolateRegionTask);
            }
          }
        }

        if (!isolateRegionTaskList.isEmpty()) {
          isolateRegionPool.shutdown();
          // Now that we have fetched all the region's regionInfo, we can move them.
          waitMoveTasksToFinish(isolateRegionPool, isolateRegionTaskList,
            admin.getConfiguration().getLong(MOVE_WAIT_MAX_KEY, DEFAULT_MOVE_WAIT_MAX));

          Set<RegionInfo> currentRegionsOnTheServer = new HashSet<>(admin.getRegions(server));
          if (!currentRegionsOnTheServer.containsAll(isolateRegionInfoList)) {
            // If all the regions are not online on the target server,
            // we don't put RS in decommission mode and exit from here.
            LOG.error("One of the Region move failed OR stuck in transition...Quitting now");
            break;
          }
        } else {
          LOG.info("All regions already exists on server : " + server.getHostname());
        }
        // Once region has been moved to target RS, put the target RS into decommission mode,
        // so master doesn't assign new region to the target RS while we unload the target RS.
        // Also pass 'offload' flag as false since we don't want master to offload the target RS.
        List<ServerName> listOfServer = new ArrayList<>();
        listOfServer.add(server);
        LOG.info("Putting server : " + server.getHostname() + " in decommission/draining mode");
        admin.decommissionRegionServers(listOfServer, false);
      }
      List<RegionInfo> regionsToMove = admin.getRegions(server);
      // Remove all the regions from the online Region list, that we just isolated.
      // This will also include hbase:meta if it was isolated.
      regionsToMove.removeAll(isolateRegionInfoList);
      regionsToMove.removeAll(movedRegions);
      if (regionsToMove.isEmpty()) {
        LOG.info("No Regions to move....Quitting now");
        break;
      }
      LOG.info("Moving {} regions from {} to {} servers using {} threads .Ack Mode: {}",
        regionsToMove.size(), this.hostname, regionServers.size(), this.maxthreads, ack);

      Optional<RegionInfo> metaRegion = getMetaRegionInfoIfToBeMoved(regionsToMove);
      if (metaRegion.isPresent()) {
        RegionInfo meta = metaRegion.get();
        // hbase:meta should move explicitly in Ack mode.
        submitRegionMovesWhileUnloading(server, regionServers, movedRegions,
          Collections.singletonList(meta), true);
        regionsToMove.remove(meta);
      }
      submitRegionMovesWhileUnloading(server, regionServers, movedRegions, regionsToMove, false);
    }
  }
Isolated regions specified in {@link #isolateRegionIdArray} on {@link #hostname} in ack Mode
and Unload regions from given {@link #hostname} using ack/noAck mode and {@link #maxthreads}.
In noAck mode we do not make sure that region is successfully online on the target region
server,hence it is the best effort. We do not unload regions to hostnames given in
{@link #excludeFile}. If designatedFile is present with some contents, we will unload regions
to hostnames provided in {@link #designatedFile}
@return true if region isolation succeeded, false otherwise
hbase-server/src/main/java/org/apache/hadoop/hbase/util/RegionMover.java