/** * Return how many regions will move per table since their primary RS will change * * @param newPlan - new AssignmentPlan * @return how many primaries will move per table */ public Map<TableName, Integer> getRegionsMovement(FavoredNodesPlan newPlan) throws IOException { Map<TableName, Integer> movesPerTable = new HashMap<TableName, Integer>(); SnapshotOfRegionAssignmentFromMeta snapshot = this.getRegionAssignmentSnapshot(); Map<TableName, List<HRegionInfo>> tableToRegions = snapshot.getTableToRegionMap(); FavoredNodesPlan oldPlan = snapshot.getExistingAssignmentPlan(); Set<TableName> tables = snapshot.getTableSet(); for (TableName table : tables) { int movedPrimaries = 0; if (!this.targetTableSet.isEmpty() && !this.targetTableSet.contains(table)) { continue; } List<HRegionInfo> regions = tableToRegions.get(table); for (HRegionInfo region : regions) { List<ServerName> oldServers = oldPlan.getFavoredNodes(region); List<ServerName> newServers = newPlan.getFavoredNodes(region); if (oldServers != null && newServers != null) { ServerName oldPrimary = oldServers.get(0); ServerName newPrimary = newServers.get(0); if (oldPrimary.compareTo(newPrimary) != 0) { movedPrimaries++; } } } movesPerTable.put(table, movedPrimaries); } return movesPerTable; }
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); } }
/** * 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()); } } }
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; }
/** * Use this to project the dispersion scores * * @param tableName * @param snapshot * @param newPlan */ public void fillUpDispersion( TableName tableName, SnapshotOfRegionAssignmentFromMeta snapshot, FavoredNodesPlan newPlan) { // 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(); FavoredNodesPlan plan = null; if (newPlan == null) { plan = snapshot.getExistingAssignmentPlan(); } else { plan = newPlan; } // Get the region to region server mapping 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 { // Get the favored nodes from the assignment plan and verify it. List<ServerName> favoredNodes = plan.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); } 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 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(); } }