public void printLocalityAndDispersionForCurrentPlan(
     Map<String, Map<String, Float>> regionLocalityMap) throws IOException {
   SnapshotOfRegionAssignmentFromMeta snapshot = this.getRegionAssignmentSnapshot();
   FavoredNodesPlan assignmentPlan = snapshot.getExistingAssignmentPlan();
   Set<TableName> tables = snapshot.getTableSet();
   Map<TableName, List<HRegionInfo>> tableToRegionsMap = snapshot.getTableToRegionMap();
   for (TableName table : tables) {
     float[] locality = new float[3];
     if (!this.targetTableSet.isEmpty() && !this.targetTableSet.contains(table)) {
       continue;
     }
     List<HRegionInfo> regions = tableToRegionsMap.get(table);
     for (HRegionInfo currentRegion : regions) {
       Map<String, Float> regionLocality = regionLocalityMap.get(currentRegion.getEncodedName());
       if (regionLocality == null) {
         continue;
       }
       List<ServerName> servers = assignmentPlan.getFavoredNodes(currentRegion);
       if (servers != null) {
         int i = 0;
         for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
           ServerName server = servers.get(p.ordinal());
           Float currentLocality = 0f;
           if (servers != null) {
             currentLocality = regionLocality.get(server.getHostname());
             if (currentLocality == null) {
               currentLocality = 0f;
             }
             locality[i] += currentLocality;
           }
           i++;
         }
       }
     }
     for (int i = 0; i < locality.length; i++) {
       String copy = null;
       if (i == 0) {
         copy = "primary";
       } else if (i == 1) {
         copy = "secondary";
       } else if (i == 2) {
         copy = "tertiary";
       }
       float avgLocality = 100 * locality[i] / regions.size();
       LOG.info(
           "For Table: "
               + table
               + " ; #Total Regions: "
               + regions.size()
               + " ; The average locality for "
               + copy
               + " is "
               + avgLocality
               + " %");
     }
     printDispersionScores(table, snapshot, regions.size(), null, false);
   }
 }
 /**
  * Compares two plans and check whether the locality dropped or increased (prints the information
  * as a string) also prints the baseline locality
  *
  * @param movesPerTable - how many primary regions will move per table
  * @param regionLocalityMap - locality map from FS
  * @param newPlan - new assignment plan
  * @throws IOException
  */
 public void checkDifferencesWithOldPlan(
     Map<TableName, Integer> movesPerTable,
     Map<String, Map<String, Float>> regionLocalityMap,
     FavoredNodesPlan newPlan)
     throws IOException {
   // localities for primary, secondary and tertiary
   SnapshotOfRegionAssignmentFromMeta snapshot = this.getRegionAssignmentSnapshot();
   FavoredNodesPlan oldPlan = snapshot.getExistingAssignmentPlan();
   Set<TableName> tables = snapshot.getTableSet();
   Map<TableName, List<HRegionInfo>> tableToRegionsMap = snapshot.getTableToRegionMap();
   for (TableName table : tables) {
     float[] deltaLocality = new float[3];
     float[] locality = new float[3];
     if (!this.targetTableSet.isEmpty() && !this.targetTableSet.contains(table)) {
       continue;
     }
     List<HRegionInfo> regions = tableToRegionsMap.get(table);
     System.out.println("==================================================");
     System.out.println("Assignment Plan Projection Report For Table: " + table);
     System.out.println("\t Total regions: " + regions.size());
     System.out.println(
         "\t"
             + movesPerTable.get(table)
             + " primaries will move due to their primary has changed");
     for (HRegionInfo currentRegion : regions) {
       Map<String, Float> regionLocality = regionLocalityMap.get(currentRegion.getEncodedName());
       if (regionLocality == null) {
         continue;
       }
       List<ServerName> oldServers = oldPlan.getFavoredNodes(currentRegion);
       List<ServerName> newServers = newPlan.getFavoredNodes(currentRegion);
       if (newServers != null && oldServers != null) {
         int i = 0;
         for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
           ServerName newServer = newServers.get(p.ordinal());
           ServerName oldServer = oldServers.get(p.ordinal());
           Float oldLocality = 0f;
           if (oldServers != null) {
             oldLocality = regionLocality.get(oldServer.getHostname());
             if (oldLocality == null) {
               oldLocality = 0f;
             }
             locality[i] += oldLocality;
           }
           Float newLocality = regionLocality.get(newServer.getHostname());
           if (newLocality == null) {
             newLocality = 0f;
           }
           deltaLocality[i] += newLocality - oldLocality;
           i++;
         }
       }
     }
     DecimalFormat df = new java.text.DecimalFormat("#.##");
     for (int i = 0; i < deltaLocality.length; i++) {
       System.out.print("\t\t Baseline locality for ");
       if (i == 0) {
         System.out.print("primary ");
       } else if (i == 1) {
         System.out.print("secondary ");
       } else if (i == 2) {
         System.out.print("tertiary ");
       }
       System.out.println(df.format(100 * locality[i] / regions.size()) + "%");
       System.out.print("\t\t Locality will change with the new plan: ");
       System.out.println(df.format(100 * deltaLocality[i] / regions.size()) + "%");
     }
     System.out.println("\t Baseline dispersion");
     printDispersionScores(table, snapshot, regions.size(), null, true);
     System.out.println("\t Projected dispersion");
     printDispersionScores(table, snapshot, regions.size(), newPlan, true);
   }
 }
 /**
  * Return the number of regions based on the position (primary/secondary/ tertiary) assigned to
  * their favored nodes
  *
  * @param position
  * @return the number of regions
  */
 int getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position position) {
   return favoredNodes[position.ordinal()];
 }
  public void fillUp(
      TableName tableName,
      SnapshotOfRegionAssignmentFromMeta snapshot,
      Map<String, Map<String, Float>> regionLocalityMap) {
    // Set the table name
    this.tableName = tableName;

    // Get all the regions for this table
    List<HRegionInfo> regionInfoList = snapshot.getTableToRegionMap().get(tableName);
    // Get the total region num for the current table
    this.totalRegions = regionInfoList.size();

    // Get the existing assignment plan
    FavoredNodesPlan favoredNodesAssignment = snapshot.getExistingAssignmentPlan();
    // Get the region to region server mapping
    Map<HRegionInfo, ServerName> currentAssignment = snapshot.getRegionToRegionServerMap();
    // Initialize the server to its hosing region counter map
    Map<ServerName, Integer> serverToHostingRegionCounterMap = new HashMap<ServerName, Integer>();

    Map<ServerName, Integer> primaryRSToRegionCounterMap = new HashMap<ServerName, Integer>();
    Map<ServerName, Set<ServerName>> primaryToSecTerRSMap =
        new HashMap<ServerName, Set<ServerName>>();

    // Check the favored nodes and its locality information
    // Also keep tracker of the most loaded and least loaded region servers
    for (HRegionInfo region : regionInfoList) {
      try {
        ServerName currentRS = currentAssignment.get(region);
        // Handle unassigned regions
        if (currentRS == null) {
          unAssignedRegionsList.add(region);
          continue;
        }

        // Keep updating the server to is hosting region counter map
        Integer hostRegionCounter = serverToHostingRegionCounterMap.get(currentRS);
        if (hostRegionCounter == null) {
          hostRegionCounter = Integer.valueOf(0);
        }
        hostRegionCounter = hostRegionCounter.intValue() + 1;
        serverToHostingRegionCounterMap.put(currentRS, hostRegionCounter);

        // Get the favored nodes from the assignment plan and verify it.
        List<ServerName> favoredNodes = favoredNodesAssignment.getFavoredNodes(region);
        if (favoredNodes == null
            || favoredNodes.size() != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) {
          regionsWithoutValidFavoredNodes.add(region);
          continue;
        }
        // Get the primary, secondary and tertiary region server
        ServerName primaryRS = favoredNodes.get(FavoredNodesPlan.Position.PRIMARY.ordinal());
        ServerName secondaryRS = favoredNodes.get(FavoredNodesPlan.Position.SECONDARY.ordinal());
        ServerName tertiaryRS = favoredNodes.get(FavoredNodesPlan.Position.TERTIARY.ordinal());

        // Update the primary rs to its region set map
        Integer regionCounter = primaryRSToRegionCounterMap.get(primaryRS);
        if (regionCounter == null) {
          regionCounter = Integer.valueOf(0);
        }
        regionCounter = regionCounter.intValue() + 1;
        primaryRSToRegionCounterMap.put(primaryRS, regionCounter);

        // Update the primary rs to secondary and tertiary rs map
        Set<ServerName> secAndTerSet = primaryToSecTerRSMap.get(primaryRS);
        if (secAndTerSet == null) {
          secAndTerSet = new HashSet<ServerName>();
        }
        secAndTerSet.add(secondaryRS);
        secAndTerSet.add(tertiaryRS);
        primaryToSecTerRSMap.put(primaryRS, secAndTerSet);

        // Get the position of the current region server in the favored nodes list
        FavoredNodesPlan.Position favoredNodePosition =
            FavoredNodesPlan.getFavoredServerPosition(favoredNodes, currentRS);

        // Handle the non favored assignment.
        if (favoredNodePosition == null) {
          nonFavoredAssignedRegionList.add(region);
          continue;
        }
        // Increase the favored nodes assignment.
        this.favoredNodes[favoredNodePosition.ordinal()]++;
        totalFavoredAssignments++;

        // Summary the locality information for each favored nodes
        if (regionLocalityMap != null) {
          // Set the enforce locality as true;
          this.enforceLocality = true;

          // Get the region degree locality map
          Map<String, Float> regionDegreeLocalityMap =
              regionLocalityMap.get(region.getEncodedName());
          if (regionDegreeLocalityMap == null) {
            continue; // ignore the region which doesn't have any store files.
          }

          // Get the locality summary for each favored nodes
          for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
            ServerName favoredNode = favoredNodes.get(p.ordinal());
            // Get the locality for the current favored nodes
            Float locality = regionDegreeLocalityMap.get(favoredNode.getHostname());
            if (locality != null) {
              this.favoredNodesLocalitySummary[p.ordinal()] += locality;
            }
          }

          // Get the locality summary for the current region server
          Float actualLocality = regionDegreeLocalityMap.get(currentRS.getHostname());
          if (actualLocality != null) {
            this.actualLocalitySummary += actualLocality;
          }
        }
      } catch (Exception e) {
        LOG.error(
            "Cannot verify the region assignment for region "
                + ((region == null) ? " null " : region.getRegionNameAsString())
                + "because of "
                + e);
      }
    }

    float dispersionScoreSummary = 0;
    float dispersionNumSummary = 0;
    // Calculate the secondary score for each primary region server
    for (Map.Entry<ServerName, Integer> entry : primaryRSToRegionCounterMap.entrySet()) {
      ServerName primaryRS = entry.getKey();
      Integer regionsOnPrimary = entry.getValue();

      // Process the dispersion number and score
      float dispersionScore = 0;
      int dispersionNum = 0;
      if (primaryToSecTerRSMap.get(primaryRS) != null && regionsOnPrimary.intValue() != 0) {
        dispersionNum = primaryToSecTerRSMap.get(primaryRS).size();
        dispersionScore = dispersionNum / ((float) regionsOnPrimary.intValue() * 2);
      }
      // Update the max dispersion score
      if (dispersionScore > this.maxDispersionScore) {
        this.maxDispersionScoreServerSet.clear();
        this.maxDispersionScoreServerSet.add(primaryRS);
        this.maxDispersionScore = dispersionScore;
      } else if (dispersionScore == this.maxDispersionScore) {
        this.maxDispersionScoreServerSet.add(primaryRS);
      }

      // Update the max dispersion num
      if (dispersionNum > this.maxDispersionNum) {
        this.maxDispersionNumServerSet.clear();
        this.maxDispersionNumServerSet.add(primaryRS);
        this.maxDispersionNum = dispersionNum;
      } else if (dispersionNum == this.maxDispersionNum) {
        this.maxDispersionNumServerSet.add(primaryRS);
      }

      // Update the min dispersion score
      if (dispersionScore < this.minDispersionScore) {
        this.minDispersionScoreServerSet.clear();
        this.minDispersionScoreServerSet.add(primaryRS);
        this.minDispersionScore = dispersionScore;
      } else if (dispersionScore == this.minDispersionScore) {
        this.minDispersionScoreServerSet.add(primaryRS);
      }

      // Update the min dispersion num
      if (dispersionNum < this.minDispersionNum) {
        this.minDispersionNumServerSet.clear();
        this.minDispersionNumServerSet.add(primaryRS);
        this.minDispersionNum = dispersionNum;
      } else if (dispersionNum == this.minDispersionNum) {
        this.minDispersionNumServerSet.add(primaryRS);
      }

      dispersionScoreSummary += dispersionScore;
      dispersionNumSummary += dispersionNum;
    }

    // Update the avg dispersion score
    if (primaryRSToRegionCounterMap.keySet().size() != 0) {
      this.avgDispersionScore =
          dispersionScoreSummary / (float) primaryRSToRegionCounterMap.keySet().size();
      this.avgDispersionNum =
          dispersionNumSummary / (float) primaryRSToRegionCounterMap.keySet().size();
    }

    // Fill up the most loaded and least loaded region server information
    for (Map.Entry<ServerName, Integer> entry : serverToHostingRegionCounterMap.entrySet()) {
      ServerName currentRS = entry.getKey();
      int hostRegionCounter = entry.getValue().intValue();

      // Update the most loaded region server list and maxRegionsOnRS
      if (hostRegionCounter > this.maxRegionsOnRS) {
        maxRegionsOnRS = hostRegionCounter;
        this.mostLoadedRSSet.clear();
        this.mostLoadedRSSet.add(currentRS);
      } else if (hostRegionCounter == this.maxRegionsOnRS) {
        this.mostLoadedRSSet.add(currentRS);
      }

      // Update the least loaded region server list and minRegionsOnRS
      if (hostRegionCounter < this.minRegionsOnRS) {
        this.minRegionsOnRS = hostRegionCounter;
        this.leastLoadedRSSet.clear();
        this.leastLoadedRSSet.add(currentRS);
      } else if (hostRegionCounter == this.minRegionsOnRS) {
        this.leastLoadedRSSet.add(currentRS);
      }
    }

    // and total region servers
    this.totalRegionServers = serverToHostingRegionCounterMap.keySet().size();
    this.avgRegionsOnRS =
        (totalRegionServers == 0) ? 0 : (totalRegions / (float) totalRegionServers);
    // Set the isFilledUp as true
    isFilledUp = true;
  }
  public void print(boolean isDetailMode) {
    if (!isFilledUp) {
      System.err.println("[Error] Region assignment verfication report" + "hasn't been filled up");
    }
    DecimalFormat df = new java.text.DecimalFormat("#.##");

    // Print some basic information
    System.out.println(
        "Region Assignment Verification for Table: "
            + tableName
            + "\n\tTotal regions : "
            + totalRegions);

    // Print the number of regions on each kinds of the favored nodes
    System.out.println("\tTotal regions on favored nodes " + totalFavoredAssignments);
    for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
      System.out.println(
          "\t\tTotal regions on " + p.toString() + " region servers: " + favoredNodes[p.ordinal()]);
    }
    // Print the number of regions in each kinds of invalid assignment
    System.out.println("\tTotal unassigned regions: " + unAssignedRegionsList.size());
    if (isDetailMode) {
      for (HRegionInfo region : unAssignedRegionsList) {
        System.out.println("\t\t" + region.getRegionNameAsString());
      }
    }

    System.out.println(
        "\tTotal regions NOT on favored nodes: " + nonFavoredAssignedRegionList.size());
    if (isDetailMode) {
      for (HRegionInfo region : nonFavoredAssignedRegionList) {
        System.out.println("\t\t" + region.getRegionNameAsString());
      }
    }

    System.out.println(
        "\tTotal regions without favored nodes: " + regionsWithoutValidFavoredNodes.size());
    if (isDetailMode) {
      for (HRegionInfo region : regionsWithoutValidFavoredNodes) {
        System.out.println("\t\t" + region.getRegionNameAsString());
      }
    }

    // Print the locality information if enabled
    if (this.enforceLocality && totalRegions != 0) {
      // Print the actual locality for this table
      float actualLocality = 100 * this.actualLocalitySummary / (float) totalRegions;
      System.out.println("\n\tThe actual avg locality is " + df.format(actualLocality) + " %");

      // Print the expected locality if regions are placed on the each kinds of
      // favored nodes
      for (FavoredNodesPlan.Position p : FavoredNodesPlan.Position.values()) {
        float avgLocality = 100 * (favoredNodesLocalitySummary[p.ordinal()] / (float) totalRegions);
        System.out.println(
            "\t\tThe expected avg locality if all regions"
                + " on the "
                + p.toString()
                + " region servers: "
                + df.format(avgLocality)
                + " %");
      }
    }

    // Print the region balancing information
    System.out.println("\n\tTotal hosting region servers: " + totalRegionServers);
    // Print the region balance information
    if (totalRegionServers != 0) {
      System.out.println(
          "\tAvg dispersion num: "
              + df.format(avgDispersionNum)
              + " hosts;\tMax dispersion num: "
              + df.format(maxDispersionNum)
              + " hosts;\tMin dispersion num: "
              + df.format(minDispersionNum)
              + " hosts;");

      System.out.println(
          "\t\tThe number of the region servers with the max"
              + " dispersion num: "
              + this.maxDispersionNumServerSet.size());
      if (isDetailMode) {
        printHServerAddressSet(maxDispersionNumServerSet);
      }

      System.out.println(
          "\t\tThe number of the region servers with the min"
              + " dispersion num: "
              + this.minDispersionNumServerSet.size());
      if (isDetailMode) {
        printHServerAddressSet(maxDispersionNumServerSet);
      }

      System.out.println(
          "\tAvg dispersion score: "
              + df.format(avgDispersionScore)
              + ";\tMax dispersion score: "
              + df.format(maxDispersionScore)
              + ";\tMin dispersion score: "
              + df.format(minDispersionScore)
              + ";");

      System.out.println(
          "\t\tThe number of the region servers with the max"
              + " dispersion score: "
              + this.maxDispersionScoreServerSet.size());
      if (isDetailMode) {
        printHServerAddressSet(maxDispersionScoreServerSet);
      }

      System.out.println(
          "\t\tThe number of the region servers with the min"
              + " dispersion score: "
              + this.minDispersionScoreServerSet.size());
      if (isDetailMode) {
        printHServerAddressSet(minDispersionScoreServerSet);
      }

      System.out.println(
          "\tAvg regions/region server: "
              + df.format(avgRegionsOnRS)
              + ";\tMax regions/region server: "
              + maxRegionsOnRS
              + ";\tMin regions/region server: "
              + minRegionsOnRS
              + ";");

      // Print the details about the most loaded region servers
      System.out.println(
          "\t\tThe number of the most loaded region servers: " + mostLoadedRSSet.size());
      if (isDetailMode) {
        printHServerAddressSet(mostLoadedRSSet);
      }

      // Print the details about the least loaded region servers
      System.out.println(
          "\t\tThe number of the least loaded region servers: " + leastLoadedRSSet.size());
      if (isDetailMode) {
        printHServerAddressSet(leastLoadedRSSet);
      }
    }
    System.out.println("==============================");
  }