//Balances two rows in a way that primary need to lose some weight to get the resultant weight. //As secondary is always higher weight then primary, so primary cant lose weight. This makes it //straight forward. private static RowsBalanceResult RowBalanceLoseWeight(Tuple rowPair, long weightToLose, DistributionMatrix bMatrix) { int[] primaryIndicies = new int[bMatrix.MatrixDimension.Cols]; RowsBalanceResult rbResult = new RowsBalanceResult(); //lets first populated indicies list for each row.This would help in geting the final set of indicies. for (int i = 0; i < bMatrix.MatrixDimension.Cols; i++) primaryIndicies[i] = (rowPair.First * bMatrix.MatrixDimension.Cols) + i; rbResult.ResultIndicies = primaryIndicies; rbResult.TargetDistance = weightToLose; return rbResult; }
//Backbone to be written now.//Two arrays ....both need to give a right combination against required weight. private static RowsBalanceResult BalanceWeight(Tuple rowPair, DistributionMatrix bMatrix) { BalanceAction balAction = new BalanceAction(); long weightToMove = 0; long primaryRowWeight = bMatrix.WeightPercentMatrix[rowPair.First, 0]; long secondaryRowWeight = bMatrix.WeightPercentMatrix[rowPair.Second, 0]; if (primaryRowWeight < bMatrix.PercentWeightToSacrifice) // { weightToMove = bMatrix.PercentWeightToSacrifice - primaryRowWeight; weightToMove = (weightToMove * bMatrix.TotalWeight) / 100; balAction = BalanceAction.GainWeight; } else { weightToMove = primaryRowWeight - bMatrix.PercentWeightToSacrifice; weightToMove = (weightToMove * bMatrix.TotalWeight) / 100; balAction = BalanceAction.LoseWeight; } long[] primaryRowData = new long[bMatrix.MatrixDimension.Cols]; long[] secondaryRowData = new long[bMatrix.MatrixDimension.Cols]; //Fills the local copy of two rows to be manipulated for (int i = 0; i < bMatrix.MatrixDimension.Cols; i++) { primaryRowData[i] = bMatrix.Matrix[rowPair.First, i]; secondaryRowData[i] = bMatrix.Matrix[rowPair.Second, i]; } RowsBalanceResult rbResult = null; switch (balAction) { case BalanceAction.GainWeight: rbResult = RowBalanceGainWeight(rowPair, primaryRowData, secondaryRowData, weightToMove, bMatrix); break; case BalanceAction.LoseWeight: rbResult = RowBalanceLoseWeight(rowPair, weightToMove, bMatrix); break; default: break; } return(rbResult); }
//returns selected array of indicies that are the resultant set to be sacrificed public static RowsBalanceResult CompareAndSelect(DistributionMatrix bMatrix) { //First Pass:: Check if any individual row can fulfill the reqs . int rowNum = IndividualSelect(bMatrix); if (rowNum >= 0) { int[] selectedBuckets = new int[bMatrix.MatrixDimension.Cols]; for (int i = 0; i < bMatrix.MatrixDimension.Cols; i++) { selectedBuckets[i] = (rowNum * bMatrix.MatrixDimension.Cols) + i; } RowsBalanceResult rbResult = new RowsBalanceResult(); rbResult.ResultIndicies = selectedBuckets; rbResult.TargetDistance = Math.Abs(bMatrix.WeightPercentMatrix[rowNum, 1] - bMatrix.WeightToSacrifice); return(rbResult); } else //Second pass Compare all pairs. { ArrayList allTuples = CandidateTuples(bMatrix); RowsBalanceResult rbResultCurr, rbResultToKeep; rbResultCurr = null; rbResultToKeep = null; foreach (Tuple pair in allTuples) { rbResultCurr = BalanceWeight(pair, bMatrix); if (rbResultToKeep == null) { rbResultToKeep = rbResultCurr; } //If the current result is more optimized then previous then current is the candidate. if (rbResultCurr.TargetDistance < rbResultToKeep.TargetDistance) { rbResultToKeep = rbResultCurr; } } return(rbResultToKeep); } }
//We have the matrix. We need no weight balancing, but we need shuffled indexes to be selected. Here comes the routine and algo. // Shuffle works the way of moving diagonally within a matrix. If we reach end column, move to first row but extended column. public static RowsBalanceResult ShuffleSelect(DistributionMatrix bMatrix) { RowsBalanceResult rbResult = new RowsBalanceResult(); int[] selectedBuckets = new int[bMatrix.MatrixDimension.Cols]; for (int i = 0; i < bMatrix.MatrixDimension.Cols; ) { for (int j = 0; j < bMatrix.MatrixDimension.Rows && i < bMatrix.MatrixDimension.Cols; j++, i++) { if (bMatrix.Matrix[j, i] == -1) { break; } else { selectedBuckets[i] = (j * bMatrix.MatrixDimension.Cols) + i; } } } rbResult.ResultIndicies = selectedBuckets; rbResult.TargetDistance = 0; return rbResult; }
//Balances two rows in a way that primary need to add some more weight to get the resultant weight. private static RowsBalanceResult RowBalanceGainWeight(Tuple rowPair, long[] primaryRowData, long[] secondaryRowData, long weightToGain, DistributionMatrix bMatrix) { int[] primaryIndicies = new int[bMatrix.MatrixDimension.Cols]; int[] secondaryIndicies = new int[bMatrix.MatrixDimension.Cols]; int tmpIndex, primaryLockAt, secondaryLockAt; long primaryRowWeight = bMatrix.WeightPercentMatrix[rowPair.First, 1]; long secondaryRowWeight = bMatrix.WeightPercentMatrix[rowPair.Second, 1]; long weightToAchieve, primaryDistance, secondaryDistance, tmpWeightPri, tmpWeightSec, weightDifference; bool primarySelect = false; primaryLockAt = -1; secondaryLockAt = -1; primaryDistance = 0; secondaryDistance = 0; bool bSecondaryNeedsToLoose = true; //total weight to be made weightToAchieve = primaryRowWeight + weightToGain; RowsBalanceResult rbResult = new RowsBalanceResult(); // for example first-row weight = 1000, second-row weight = 2000, required weight = 3000, // in this case second row need not to lose weight, so no need to keep it as a candidate. if (secondaryRowWeight < weightToAchieve) bSecondaryNeedsToLoose = false; //lets first populated indicies list for each row.This would help in geting the final set of indicies. for (int i = 0; i < bMatrix.MatrixDimension.Cols; i++) { primaryIndicies[i] = (rowPair.First * bMatrix.MatrixDimension.Cols) + i; secondaryIndicies[i] = (rowPair.Second * bMatrix.MatrixDimension.Cols) + i; } //in this loop I am checking both ways. The one that needs to gain weight and the one that looses //weight in result. So any row can match the required weight. After each loop, each swap I check //for the criteria against both rows. In the end I get two indexes against both rows along with //possible extra/deficient count. //In Loose weight, primary is already high from the target,so no chance of secondary for (int i = 0; i < bMatrix.MatrixDimension.Cols; i++) { tmpWeightPri = primaryRowData[i]; tmpWeightSec = secondaryRowData[i]; weightDifference = tmpWeightSec - tmpWeightPri; primaryRowWeight += weightDifference; secondaryRowWeight -= weightDifference; if (primaryRowWeight > weightToAchieve && primaryLockAt == -1) { long diffAfterSwap = primaryRowWeight - weightToAchieve; long diffBeforeSwap = weightToAchieve - (primaryRowWeight - weightDifference); if (diffAfterSwap >= diffBeforeSwap) { primaryLockAt = i - 1; primaryDistance = diffBeforeSwap; } else { primaryLockAt = i; primaryDistance = diffAfterSwap; } } //Do secondary really needs to loose weight ?? Not all the time. if (secondaryRowWeight < weightToAchieve && secondaryLockAt == -1 && bSecondaryNeedsToLoose) { long diffAfterSwap = weightToAchieve - secondaryRowWeight; long diffBeforeSwap = (secondaryRowWeight + weightDifference) - weightToAchieve; if (diffAfterSwap >= diffBeforeSwap) { secondaryLockAt = i - 1; secondaryDistance = diffBeforeSwap; } else { secondaryLockAt = i; secondaryDistance = diffAfterSwap; } } } if (primaryLockAt != -1 && secondaryLockAt != -1) //if we found both rows be candidates then select one with less error { if (primaryDistance <= secondaryDistance) primarySelect = true; else primarySelect = false; } else { if (primaryLockAt != -1) primarySelect = true; if (secondaryLockAt != -1) primarySelect = false; } //unfortunately we found nothing ... So give the first row back with overhead value if (primaryLockAt == -1 && secondaryLockAt == -1) { primarySelect = true; primaryDistance = weightToAchieve - primaryRowWeight; } int swapCount = (primarySelect == true) ? primaryLockAt : secondaryLockAt; //do the items swapping according to swap count value for (int i = 0; i <= swapCount; i++) { tmpIndex = primaryIndicies[i]; primaryIndicies[i] = secondaryIndicies[i]; secondaryIndicies[i] = tmpIndex; } if (primarySelect == true) { rbResult.ResultIndicies = primaryIndicies; rbResult.TargetDistance = primaryDistance; } else { rbResult.ResultIndicies = secondaryIndicies; rbResult.TargetDistance = secondaryDistance; } return rbResult; }
//returns selected array of indicies that are the resultant set to be sacrificed public static RowsBalanceResult CompareAndSelect(DistributionMatrix bMatrix) { //First Pass:: Check if any individual row can fulfill the reqs . int rowNum = IndividualSelect(bMatrix); if (rowNum >= 0) { int[] selectedBuckets = new int[bMatrix.MatrixDimension.Cols]; for (int i = 0; i < bMatrix.MatrixDimension.Cols; i++) { selectedBuckets[i] = (rowNum * bMatrix.MatrixDimension.Cols) + i; } RowsBalanceResult rbResult = new RowsBalanceResult(); rbResult.ResultIndicies = selectedBuckets; rbResult.TargetDistance = Math.Abs(bMatrix.WeightPercentMatrix[rowNum, 1] - bMatrix.WeightToSacrifice); return rbResult; } else //Second pass Compare all pairs. { ArrayList allTuples = CandidateTuples(bMatrix); RowsBalanceResult rbResultCurr, rbResultToKeep; rbResultCurr = null; rbResultToKeep = null; foreach (Tuple pair in allTuples) { rbResultCurr = BalanceWeight(pair, bMatrix); if (rbResultToKeep == null) rbResultToKeep = rbResultCurr; //If the current result is more optimized then previous then current is the candidate. if (rbResultCurr.TargetDistance < rbResultToKeep.TargetDistance) rbResultToKeep = rbResultCurr; } return rbResultToKeep; } }
/* public static ArrayList CandidateSelection(ArrayList sortedBucketsForNode, int nodesToSacrifice, int weightToSacrifice) { int _matrixWidth = nodesToSacrifice; double _matrixHeightDbl = sortedBucketsForNode.Count / nodesToSacrifice; int _matrixHeight = Convert.ToInt32(Math.Ceiling(_matrixHeightDbl)); int _matrixItemsCount = _matrixHeight * _matrixWidth; int _ignoreItems = _matrixItemsCount - sortedBucketsForNode.Count; BucketMatrix _bMatrix = GetMatrix(_matrixHeight, _matrixWidth, sortedBucketsForNode, weightToSacrifice); CompareAndSelect(_bMatrix); return null; }*/ /* private static BucketMatrix GetMatrix(int matrixH, int matrixW, ArrayList sortedBucketsForNode, int weightToSacrifice) { int[,] bucketMatrix = new int[matrixH, matrixW]; int indexCount = 0; int itemsCount = sortedBucketsForNode.Count; //Fill up the Matrix with buckets for THIS node. for (int width = 0; width < matrixW; width++) { for (int height = 0; height < matrixH; height++) { if (indexCount < itemsCount) bucketMatrix[width, height] = Convert.ToInt32(sortedBucketsForNode[indexCount++]); else { bucketMatrix[width, height] = -1; indexCount++; } } } BucketMatrix bMatrix = new BucketMatrix(bucketMatrix, matrixH, matrixW, weightToSacrifice); return bMatrix; }*/ //We have the matrix. We need no weight balancing, but we need shuffled indexes to be selected. Here comes the routine and algo. // Shuffle works the way of moving diagonally within a matrix. If we reach end column, move to first row but extended column. public static RowsBalanceResult ShuffleSelect(DistributionMatrix bMatrix) { RowsBalanceResult rbResult = new RowsBalanceResult(); int[] selectedBuckets = new int[bMatrix.MatrixDimension.Cols]; for (int i = 0; i < bMatrix.MatrixDimension.Cols; ) { for (int j = 0; j < bMatrix.MatrixDimension.Rows && i < bMatrix.MatrixDimension.Cols; j++, i++) { if (bMatrix.Matrix[j, i] == -1) { break; } else { selectedBuckets[i] = (j * bMatrix.MatrixDimension.Cols) + i; } } } rbResult.ResultIndicies = selectedBuckets; rbResult.TargetDistance = 0; return rbResult; }
public static ArrayList BalanceBuckets(DistributionInfoData distInfo, ArrayList hashMap, Hashtable bucketStats, ArrayList members, long cacheSizePerNode, ILogger NCacheLog) { DistributionData distData = new DistributionData(hashMap, bucketStats, members, NCacheLog, cacheSizePerNode); Boolean bShouldBalanceWeight = false; if (distInfo.DistribMode == DistributionMode.AvgWeightTime) //If weight and time to move has to be avg. Cut the weight to half. { if (NCacheLog.IsInfoEnabled) { NCacheLog.Info("DistributionImpl.BalanceBuckets()", "Request comes with DistributionMode.AvgWeightTime"); } distData.WeightPerNode /= 2; } ArrayList distMatrix = distData.DistributionMatrixForNodes; ArrayList finalBuckets = new ArrayList(); //We need to cater for the cases where we don't need to actually balance the data over nodes, as cluster itself is starting //and no actual load is present within a cluster and on each node. foreach (DistributionMatrix dMatrix in distMatrix) { if (dMatrix.DoWeightBalance == true) { bShouldBalanceWeight = true; break; } } //If cluster is not loaded only shuffled distribution is required. No need to balance any weight. if (bShouldBalanceWeight == false) { if (NCacheLog.IsInfoEnabled) { NCacheLog.Info("DistributionImpl.BalanceBuckets()", "Cluster is not loaded only shuffled distribution is required. No need to balance any weight."); } distInfo.DistribMode = DistributionMode.ShuffleBuckets; } //For cases below we also need to calculate Weight to be balanced along with buckets sacrifices. switch (distInfo.DistribMode) { case DistributionMode.OptimalTime: foreach (DistributionMatrix dMatrix in distMatrix) { int [,] IdMatrix = dMatrix.IdMatrix; for (int i = 0; i < dMatrix.MatrixDimension.Cols; i++) { finalBuckets.Add(IdMatrix[0, i]); //Always first row of the matrix to be given } } if (NCacheLog.IsInfoEnabled) { NCacheLog.Info("DistributionImpl.BalanceBuckets()", "Request is DistributionMode.OptimalTime"); NCacheLog.Info("Selected Buckets are: -"); for (int i = 0; i < finalBuckets.Count; i++) { NCacheLog.Info(finalBuckets[i].ToString()); } } return(finalBuckets); case DistributionMode.ShuffleBuckets: //Although code replication is observed here. Still I prefer to make its copy rather putting fewer if-else to control. I need some time efficiency here. foreach (DistributionMatrix dMatrix in distMatrix) { int[,] IdMatrix = dMatrix.IdMatrix; int[] resultIndices; RowsBalanceResult rbResult = DistributionCore.ShuffleSelect(dMatrix); resultIndices = rbResult.ResultIndicies; for (int i = 0, j = 0; i < resultIndices.Length; i++) { int index = resultIndices[i]; //Index would never be zero, rather the value corresponding in the Matrix be zero. //Get row and col on the basis of matrix index (index of one-D array). int row = index / dMatrix.MatrixDimension.Cols; int col = index % dMatrix.MatrixDimension.Cols; if (IdMatrix[row, col] == -1) //dealing with exceptional case when last row is selected and it got few non-indices.So replace those with lowest most indices in the matrix. { finalBuckets.Add(IdMatrix[0, j]); j++; } else { finalBuckets.Add(IdMatrix[row, col]); } } } if (NCacheLog.IsInfoEnabled) { NCacheLog.Info("DistributionImpl.BalanceBuckets()", "Request is DistributionMode.ShuffleBuckets"); NCacheLog.Info("Selected Buckets are: -"); for (int i = 0; i < finalBuckets.Count; i++) { NCacheLog.Info(finalBuckets[i].ToString()); } } return(finalBuckets); case DistributionMode.OptimalWeight: //For both same code works. Change is only in weight that is modified above . it is called FallThrough in switch statements. case DistributionMode.AvgWeightTime: foreach (DistributionMatrix dMatrix in distMatrix) { int[,] IdMatrix = dMatrix.IdMatrix; int[] resultIndices; RowsBalanceResult rbResult = DistributionCore.CompareAndSelect(dMatrix); resultIndices = rbResult.ResultIndicies; for (int i = 0, j = 0; i < resultIndices.Length; i++) { int index = resultIndices[i]; //Index would never be zero, rather the value corresponding in the Matrix be zero. //Get row and col on the basis of matrix index (index of one-D array). int row = index / dMatrix.MatrixDimension.Cols; int col = index % dMatrix.MatrixDimension.Cols; if (IdMatrix[row, col] == -1) //dealing with exceptional case when last row is selected and it got few non-indices.So replace those with lowest most indices in the matrix. { finalBuckets.Add(IdMatrix[0, j]); j++; } else { finalBuckets.Add(IdMatrix[row, col]); } } } if (NCacheLog.IsInfoEnabled) { NCacheLog.Info("DistributionImpl.BalanceBuckets()", "Request is DistributionMode.AvgWeightTime/ DistributionMode.OptimalWeight"); NCacheLog.Info("Selected Buckets are: -"); for (int i = 0; i < finalBuckets.Count; i++) { NCacheLog.Info(finalBuckets[i].ToString()); } } return(finalBuckets); default: break; } //end switch return(null); } //end func.