/**
   * Update the assignment plan to all the region servers
   *
   * @param plan
   * @throws IOException
   */
  private void updateAssignmentPlanToRegionServers(FavoredNodesPlan plan) throws IOException {
    LOG.info("Start to update the region servers with the new assignment plan");
    // Get the region to region server map
    Map<ServerName, List<HRegionInfo>> currentAssignment =
        this.getRegionAssignmentSnapshot().getRegionServerToRegionMap();

    // track of the failed and succeeded updates
    int succeededNum = 0;
    Map<ServerName, Exception> failedUpdateMap = new HashMap<ServerName, Exception>();

    for (Map.Entry<ServerName, List<HRegionInfo>> entry : currentAssignment.entrySet()) {
      List<Pair<HRegionInfo, List<ServerName>>> regionUpdateInfos =
          new ArrayList<Pair<HRegionInfo, List<ServerName>>>();
      try {
        // Keep track of the favored updates for the current region server
        FavoredNodesPlan singleServerPlan = null;
        // Find out all the updates for the current region server
        for (HRegionInfo region : entry.getValue()) {
          List<ServerName> favoredServerList = plan.getFavoredNodes(region);
          if (favoredServerList != null
              && favoredServerList.size() == FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) {
            // Create the single server plan if necessary
            if (singleServerPlan == null) {
              singleServerPlan = new FavoredNodesPlan();
            }
            // Update the single server update
            singleServerPlan.updateAssignmentPlan(region, favoredServerList);
            regionUpdateInfos.add(
                new Pair<HRegionInfo, List<ServerName>>(region, favoredServerList));
          }
        }
        if (singleServerPlan != null) {
          // Update the current region server with its updated favored nodes
          BlockingInterface currentRegionServer =
              ((ClusterConnection) this.connection).getAdmin(entry.getKey());
          UpdateFavoredNodesRequest request =
              RequestConverter.buildUpdateFavoredNodesRequest(regionUpdateInfos);

          UpdateFavoredNodesResponse updateFavoredNodesResponse =
              currentRegionServer.updateFavoredNodes(null, request);
          LOG.info(
              "Region server "
                  + ProtobufUtil.getServerInfo(null, currentRegionServer).getServerName()
                  + " has updated "
                  + updateFavoredNodesResponse.getResponse()
                  + " / "
                  + singleServerPlan.getAssignmentMap().size()
                  + " regions with the assignment plan");
          succeededNum++;
        }
      } catch (Exception e) {
        failedUpdateMap.put(entry.getKey(), e);
      }
    }
    // log the succeeded updates
    LOG.info("Updated " + succeededNum + " region servers with " + "the new assignment plan");

    // log the failed updates
    int failedNum = failedUpdateMap.size();
    if (failedNum != 0) {
      LOG.error(
          "Failed to update the following + "
              + failedNum
              + " region servers with its corresponding favored nodes");
      for (Map.Entry<ServerName, Exception> entry : failedUpdateMap.entrySet()) {
        LOG.error(
            "Failed to update "
                + entry.getKey().getHostAndPort()
                + " because of "
                + entry.getValue().getMessage());
      }
    }
  }