This is an automated email from the ASF dual-hosted git repository.
rmattingly pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/master by this push:
new 8ce58c8ba1b HBASE-29071 StochasticLoadBalancer candidate generators
should use a Map, rather than ordinal based indexing (#6598)
8ce58c8ba1b is described below
commit 8ce58c8ba1b23295651d45005e755c02b5476acc
Author: Ray Mattingly <[email protected]>
AuthorDate: Tue Jan 21 12:54:24 2025 -0500
HBASE-29071 StochasticLoadBalancer candidate generators should use a Map,
rather than ordinal based indexing (#6598)
Co-authored-by: Ray Mattingly <[email protected]>
---
.../master/balancer/CacheAwareLoadBalancer.java | 20 ++--
.../hadoop/hbase/master/balancer/CostFunction.java | 5 +-
.../master/balancer/FavoredStochasticBalancer.java | 13 ++-
.../master/balancer/LocalityBasedCostFunction.java | 5 +-
.../balancer/RegionCountSkewCostFunction.java | 5 +-
.../RegionReplicaGroupingCostFunction.java | 5 +-
.../master/balancer/StochasticLoadBalancer.java | 125 ++++++++++++++-------
.../balancer/TestStochasticLoadBalancer.java | 2 +-
.../TestStochasticLoadBalancerBalanceCluster.java | 2 +-
...ochasticLoadBalancerRegionReplicaWithRacks.java | 2 +-
.../LoadOnlyFavoredStochasticBalancer.java | 11 +-
11 files changed, 126 insertions(+), 69 deletions(-)
diff --git
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CacheAwareLoadBalancer.java
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CacheAwareLoadBalancer.java
index bc31a317aeb..385ed564c7d 100644
---
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CacheAwareLoadBalancer.java
+++
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CacheAwareLoadBalancer.java
@@ -68,12 +68,13 @@ public class CacheAwareLoadBalancer extends
StochasticLoadBalancer {
}
@Override
- protected List<CandidateGenerator> createCandidateGenerators() {
- List<CandidateGenerator> candidateGenerators = new ArrayList<>(2);
- candidateGenerators.add(GeneratorFunctionType.LOAD.ordinal(),
+ protected Map<Class<? extends CandidateGenerator>, CandidateGenerator>
+ createCandidateGenerators() {
+ Map<Class<? extends CandidateGenerator>, CandidateGenerator>
candidateGenerators =
+ new HashMap<>(2);
+ candidateGenerators.put(CacheAwareSkewnessCandidateGenerator.class,
new CacheAwareSkewnessCandidateGenerator());
- candidateGenerators.add(GeneratorFunctionType.CACHE_RATIO.ordinal(),
- new CacheAwareCandidateGenerator());
+ candidateGenerators.put(CacheAwareCandidateGenerator.class, new
CacheAwareCandidateGenerator());
return candidateGenerators;
}
@@ -409,8 +410,9 @@ public class CacheAwareLoadBalancer extends
StochasticLoadBalancer {
});
}
- public final void updateWeight(double[] weights) {
- weights[GeneratorFunctionType.LOAD.ordinal()] += cost();
+ @Override
+ public final void updateWeight(Map<Class<? extends CandidateGenerator>,
Double> weights) {
+ weights.merge(LoadCandidateGenerator.class, cost(), Double::sum);
}
}
@@ -478,8 +480,8 @@ public class CacheAwareLoadBalancer extends
StochasticLoadBalancer {
}
@Override
- public final void updateWeight(double[] weights) {
- weights[GeneratorFunctionType.CACHE_RATIO.ordinal()] += cost();
+ public void updateWeight(Map<Class<? extends CandidateGenerator>, Double>
weights) {
+ weights.merge(LoadCandidateGenerator.class, cost(), Double::sum);
}
}
}
diff --git
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CostFunction.java
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CostFunction.java
index 91e1ec61552..1dcd4580b1a 100644
---
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CostFunction.java
+++
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/CostFunction.java
@@ -17,6 +17,7 @@
*/
package org.apache.hadoop.hbase.master.balancer;
+import java.util.Map;
import org.apache.yetus.audience.InterfaceAudience;
/**
@@ -91,8 +92,8 @@ abstract class CostFunction {
* Called once per init or after postAction.
* @param weights the weights for every generator.
*/
- public void updateWeight(double[] weights) {
- weights[StochasticLoadBalancer.GeneratorType.RANDOM.ordinal()] += cost();
+ public void updateWeight(Map<Class<? extends CandidateGenerator>, Double>
weights) {
+ weights.merge(RandomCandidateGenerator.class, cost(), Double::sum);
}
/**
diff --git
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/FavoredStochasticBalancer.java
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/FavoredStochasticBalancer.java
index fbe91a921da..8668e7cae3c 100644
---
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/FavoredStochasticBalancer.java
+++
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/FavoredStochasticBalancer.java
@@ -80,17 +80,20 @@ public class FavoredStochasticBalancer extends
StochasticLoadBalancer
}
@Override
- protected List<CandidateGenerator> createCandidateGenerators() {
- List<CandidateGenerator> fnPickers = new ArrayList<>(2);
- fnPickers.add(new FavoredNodeLoadPicker());
- fnPickers.add(new FavoredNodeLocalityPicker());
+ protected Map<Class<? extends CandidateGenerator>, CandidateGenerator>
+ createCandidateGenerators() {
+ Map<Class<? extends CandidateGenerator>, CandidateGenerator> fnPickers =
new HashMap<>(2);
+ fnPickers.put(FavoredNodeLoadPicker.class, new FavoredNodeLoadPicker());
+ fnPickers.put(FavoredNodeLocalityPicker.class, new
FavoredNodeLocalityPicker());
return fnPickers;
}
/** Returns any candidate generator in random */
@Override
protected CandidateGenerator getRandomGenerator() {
- return
candidateGenerators.get(ThreadLocalRandom.current().nextInt(candidateGenerators.size()));
+ Class<? extends CandidateGenerator> clazz = shuffledGeneratorClasses.get()
+ .get(ThreadLocalRandom.current().nextInt(candidateGenerators.size()));
+ return candidateGenerators.get(clazz);
}
/**
diff --git
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/LocalityBasedCostFunction.java
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/LocalityBasedCostFunction.java
index 678c9a3e9ad..fc2d6cc12fb 100644
---
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/LocalityBasedCostFunction.java
+++
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/LocalityBasedCostFunction.java
@@ -17,6 +17,7 @@
*/
package org.apache.hadoop.hbase.master.balancer;
+import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import
org.apache.hadoop.hbase.master.balancer.BalancerClusterState.LocalityType;
import org.apache.yetus.audience.InterfaceAudience;
@@ -89,7 +90,7 @@ abstract class LocalityBasedCostFunction extends CostFunction
{
}
@Override
- public final void updateWeight(double[] weights) {
- weights[StochasticLoadBalancer.GeneratorType.LOCALITY.ordinal()] += cost();
+ public final void updateWeight(Map<Class<? extends CandidateGenerator>,
Double> weights) {
+ weights.merge(LocalityBasedCandidateGenerator.class, cost(), Double::sum);
}
}
diff --git
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionCountSkewCostFunction.java
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionCountSkewCostFunction.java
index 442bbc9b7bc..669f1df8f4f 100644
---
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionCountSkewCostFunction.java
+++
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionCountSkewCostFunction.java
@@ -17,6 +17,7 @@
*/
package org.apache.hadoop.hbase.master.balancer;
+import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import org.apache.yetus.audience.InterfaceAudience;
@@ -61,7 +62,7 @@ class RegionCountSkewCostFunction extends CostFunction {
}
@Override
- public final void updateWeight(double[] weights) {
- weights[StochasticLoadBalancer.GeneratorType.LOAD.ordinal()] += cost();
+ public final void updateWeight(Map<Class<? extends CandidateGenerator>,
Double> weights) {
+ weights.merge(LoadCandidateGenerator.class, cost(), Double::sum);
}
}
diff --git
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionReplicaGroupingCostFunction.java
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionReplicaGroupingCostFunction.java
index f482ada22b2..43eaceb4f77 100644
---
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionReplicaGroupingCostFunction.java
+++
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/RegionReplicaGroupingCostFunction.java
@@ -17,6 +17,7 @@
*/
package org.apache.hadoop.hbase.master.balancer;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.agrona.collections.Hashing;
import org.agrona.collections.Int2IntCounterMap;
@@ -73,8 +74,8 @@ abstract class RegionReplicaGroupingCostFunction extends
CostFunction {
}
@Override
- public final void updateWeight(double[] weights) {
- weights[StochasticLoadBalancer.GeneratorType.RACK.ordinal()] += cost();
+ public final void updateWeight(Map<Class<? extends CandidateGenerator>,
Double> weights) {
+ weights.merge(RegionReplicaRackCandidateGenerator.class, cost(),
Double::sum);
}
/**
diff --git
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
index 8405130c1c4..dce77c07bd4 100644
---
a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
+++
b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
@@ -22,11 +22,14 @@ import java.lang.reflect.Constructor;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.StringJoiner;
import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ClusterMetrics;
@@ -48,6 +51,9 @@ import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
+import org.apache.hbase.thirdparty.com.google.common.base.Suppliers;
+
/**
* <p>
* This is a best effort load balancer. Given a Cost function F(C) => x It
will randomly try and
@@ -147,7 +153,6 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
private double curOverallCost = 0d;
private double[] tempFunctionCosts;
private double[] curFunctionCosts;
- private double[] weightsOfGenerators;
// Keep locality based picker and cost function to alert them
// when new services are offered
@@ -157,14 +162,16 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
private RegionReplicaHostCostFunction regionReplicaHostCostFunction;
private RegionReplicaRackCostFunction regionReplicaRackCostFunction;
- protected List<CandidateGenerator> candidateGenerators;
-
- public enum GeneratorType {
- RANDOM,
- LOAD,
- LOCALITY,
- RACK
- }
+ private final Map<Class<? extends CandidateGenerator>, Double>
weightsOfGenerators =
+ new HashMap<>();
+ protected Map<Class<? extends CandidateGenerator>, CandidateGenerator>
candidateGenerators;
+ protected final Supplier<List<Class<? extends CandidateGenerator>>>
shuffledGeneratorClasses =
+ Suppliers.memoizeWithExpiration(() -> {
+ List<Class<? extends CandidateGenerator>> shuffled =
+ new ArrayList<>(candidateGenerators.keySet());
+ Collections.shuffle(shuffled);
+ return shuffled;
+ }, 5, TimeUnit.SECONDS);
/**
* The constructor that pass a MetricsStochasticBalancer to BaseLoadBalancer
to replace its
@@ -213,16 +220,20 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
@RestrictedApi(explanation = "Should only be called in tests", link = "",
allowedOnPath = ".*/src/test/.*")
- List<CandidateGenerator> getCandidateGenerators() {
+ Map<Class<? extends CandidateGenerator>, CandidateGenerator>
getCandidateGenerators() {
return this.candidateGenerators;
}
- protected List<CandidateGenerator> createCandidateGenerators() {
- List<CandidateGenerator> candidateGenerators = new
ArrayList<CandidateGenerator>(4);
- candidateGenerators.add(GeneratorType.RANDOM.ordinal(), new
RandomCandidateGenerator());
- candidateGenerators.add(GeneratorType.LOAD.ordinal(), new
LoadCandidateGenerator());
- candidateGenerators.add(GeneratorType.LOCALITY.ordinal(),
localityCandidateGenerator);
- candidateGenerators.add(GeneratorType.RACK.ordinal(),
+ protected Map<Class<? extends CandidateGenerator>, CandidateGenerator>
+ createCandidateGenerators() {
+ Map<Class<? extends CandidateGenerator>, CandidateGenerator>
candidateGenerators =
+ new HashMap<>(5);
+ candidateGenerators.put(RandomCandidateGenerator.class, new
RandomCandidateGenerator());
+ candidateGenerators.put(LoadCandidateGenerator.class, new
LoadCandidateGenerator());
+ candidateGenerators.put(LocalityBasedCandidateGenerator.class,
localityCandidateGenerator);
+ candidateGenerators.put(RegionReplicaCandidateGenerator.class,
+ new RegionReplicaCandidateGenerator());
+ candidateGenerators.put(RegionReplicaRackCandidateGenerator.class,
new RegionReplicaRackCandidateGenerator());
return candidateGenerators;
}
@@ -409,34 +420,54 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
@RestrictedApi(explanation = "Should only be called in tests", link = "",
allowedOnPath = ".*(/src/test/.*|StochasticLoadBalancer).java")
- BalanceAction nextAction(BalancerClusterState cluster) {
- return getRandomGenerator().generate(cluster);
+ Pair<CandidateGenerator, BalanceAction> nextAction(BalancerClusterState
cluster) {
+ CandidateGenerator generator = getRandomGenerator();
+ return Pair.newPair(generator, generator.generate(cluster));
}
/**
* Select the candidate generator to use based on the cost of cost
functions. The chance of
- * selecting a candidate generator is propotional to the share of cost of
all cost functions among
- * all cost functions that benefit from it.
+ * selecting a candidate generator is proportional to the share of cost of
all cost functions
+ * among all cost functions that benefit from it.
*/
protected CandidateGenerator getRandomGenerator() {
- double sum = 0;
- for (int i = 0; i < weightsOfGenerators.length; i++) {
- sum += weightsOfGenerators[i];
- weightsOfGenerators[i] = sum;
- }
- if (sum == 0) {
- return candidateGenerators.get(0);
+ Preconditions.checkState(!candidateGenerators.isEmpty(), "No candidate
generators available.");
+ List<Class<? extends CandidateGenerator>> generatorClasses =
shuffledGeneratorClasses.get();
+ List<Double> partialSums = new ArrayList<>(generatorClasses.size());
+ double sum = 0.0;
+ for (Class<? extends CandidateGenerator> clazz : generatorClasses) {
+ double weight = weightsOfGenerators.getOrDefault(clazz, 0.0);
+ sum += weight;
+ partialSums.add(sum);
}
- for (int i = 0; i < weightsOfGenerators.length; i++) {
- weightsOfGenerators[i] /= sum;
+
+ // If the sum of all weights is zero, fall back to any generator
+ if (sum == 0.0) {
+ return pickAnyGenerator(generatorClasses);
}
+
double rand = ThreadLocalRandom.current().nextDouble();
- for (int i = 0; i < weightsOfGenerators.length; i++) {
- if (rand <= weightsOfGenerators[i]) {
- return candidateGenerators.get(i);
+ // Normalize partial sums so that the last one should be exactly 1.0
+ for (int i = 0; i < partialSums.size(); i++) {
+ partialSums.set(i, partialSums.get(i) / sum);
+ }
+
+ // Generate a random number and pick the first generator whose partial sum
is >= rand
+ for (int i = 0; i < partialSums.size(); i++) {
+ if (rand <= partialSums.get(i)) {
+ return candidateGenerators.get(generatorClasses.get(i));
}
}
- return candidateGenerators.get(candidateGenerators.size() - 1);
+
+ // Fallback: if for some reason we didn't return above, return any
generator
+ return pickAnyGenerator(generatorClasses);
+ }
+
+ private CandidateGenerator
+ pickAnyGenerator(List<Class<? extends CandidateGenerator>>
generatorClasses) {
+ Class<? extends CandidateGenerator> randomClass =
+
generatorClasses.get(ThreadLocalRandom.current().nextInt(candidateGenerators.size()));
+ return candidateGenerators.get(randomClass);
}
@RestrictedApi(explanation = "Should only be called in tests", link = "",
@@ -521,9 +552,12 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
final String initFunctionTotalCosts = totalCostsPerFunc();
// Perform a stochastic walk to see if we can get a good fit.
long step;
-
+ Map<Class<? extends CandidateGenerator>, Long> generatorToStepCount = new
HashMap<>();
+ Map<Class<? extends CandidateGenerator>, Long>
generatorToApprovedActionCount = new HashMap<>();
for (step = 0; step < computedMaxSteps; step++) {
- BalanceAction action = nextAction(cluster);
+ Pair<CandidateGenerator, BalanceAction> nextAction = nextAction(cluster);
+ CandidateGenerator generator = nextAction.getFirst();
+ BalanceAction action = nextAction.getSecond();
if (action.getType() == BalanceAction.Type.NULL) {
continue;
@@ -531,12 +565,14 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
cluster.doAction(action);
updateCostsAndWeightsWithAction(cluster, action);
+ generatorToStepCount.merge(generator.getClass(), 1L, Long::sum);
newCost = computeCost(cluster, currentCost);
// Should this be kept?
if (newCost < currentCost) {
currentCost = newCost;
+ generatorToApprovedActionCount.merge(generator.getClass(), 1L,
Long::sum);
// save for JMX
curOverallCost = currentCost;
@@ -555,6 +591,15 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
}
long endTime = EnvironmentEdgeManager.currentTime();
+ StringJoiner joiner = new StringJoiner("\n");
+ joiner.add("CandidateGenerator activity summary:");
+ generatorToStepCount.forEach((generator, count) -> {
+ long approvals = generatorToApprovedActionCount.getOrDefault(generator,
0L);
+ joiner.add(String.format(" - %s: %d steps, %d approvals",
generator.getSimpleName(), count,
+ approvals));
+ });
+ LOG.debug(joiner.toString());
+
metricsBalancer.balanceCluster(endTime - startTime);
if (initCost > currentCost) {
@@ -747,8 +792,10 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
@RestrictedApi(explanation = "Should only be called in tests", link = "",
allowedOnPath = ".*(/src/test/.*|StochasticLoadBalancer).java")
void initCosts(BalancerClusterState cluster) {
- // Initialize the weights of generator every time
- weightsOfGenerators = new double[this.candidateGenerators.size()];
+ weightsOfGenerators.clear();
+ for (Class<? extends CandidateGenerator> clazz :
candidateGenerators.keySet()) {
+ weightsOfGenerators.put(clazz, 0.0);
+ }
for (CostFunction c : costFunctions) {
c.prepare(cluster);
c.updateWeight(weightsOfGenerators);
@@ -762,8 +809,8 @@ public class StochasticLoadBalancer extends
BaseLoadBalancer {
allowedOnPath = ".*(/src/test/.*|StochasticLoadBalancer).java")
void updateCostsAndWeightsWithAction(BalancerClusterState cluster,
BalanceAction action) {
// Reset all the weights to 0
- for (int i = 0; i < weightsOfGenerators.length; i++) {
- weightsOfGenerators[i] = 0;
+ for (Class<? extends CandidateGenerator> clazz :
candidateGenerators.keySet()) {
+ weightsOfGenerators.put(clazz, 0.0);
}
for (CostFunction c : costFunctions) {
if (c.isNeeded()) {
diff --git
a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
index cc16cfe2ec8..d20d003b5ff 100644
---
a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
+++
b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
@@ -488,7 +488,7 @@ public class TestStochasticLoadBalancer extends
StochasticBalancerTestBase {
loadBalancer.initCosts(cluster);
for (int i = 0; i != runs; ++i) {
final double expectedCost = loadBalancer.computeCost(cluster,
Double.MAX_VALUE);
- BalanceAction action = loadBalancer.nextAction(cluster);
+ BalanceAction action = loadBalancer.nextAction(cluster).getSecond();
cluster.doAction(action);
loadBalancer.updateCostsAndWeightsWithAction(cluster, action);
BalanceAction undoAction = action.undoAction();
diff --git
a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerBalanceCluster.java
b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerBalanceCluster.java
index 2b2c56aa99a..50d1b0e84cf 100644
---
a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerBalanceCluster.java
+++
b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerBalanceCluster.java
@@ -52,7 +52,7 @@ public class TestStochasticLoadBalancerBalanceCluster extends
StochasticBalancer
*/
@Test
public void testBalanceCluster() throws Exception {
- setMaxRunTime(Duration.ofMillis(1500));
+ setMaxRunTime(Duration.ofMillis(2500));
loadBalancer.onConfigurationChange(conf);
for (int[] mockCluster : clusterStateMocks) {
Map<ServerName, List<RegionInfo>> servers =
mockClusterServers(mockCluster);
diff --git
a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerRegionReplicaWithRacks.java
b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerRegionReplicaWithRacks.java
index f57c4264adb..bc7ddef3648 100644
---
a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerRegionReplicaWithRacks.java
+++
b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancerRegionReplicaWithRacks.java
@@ -80,7 +80,7 @@ public class TestStochasticLoadBalancerRegionReplicaWithRacks
extends Stochastic
public void testRegionReplicationOnLargeClusterWithRacks() {
conf.setBoolean("hbase.master.balancer.stochastic.runMaxSteps", true);
conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 100000000L);
- setMaxRunTime(Duration.ofSeconds(5));
+ setMaxRunTime(Duration.ofSeconds(10));
loadBalancer.onConfigurationChange(conf);
int numNodes = 100;
int numRegions = numNodes * 30;
diff --git
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadOnlyFavoredStochasticBalancer.java
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadOnlyFavoredStochasticBalancer.java
index ba6ee4af843..d658f7cfa16 100644
---
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadOnlyFavoredStochasticBalancer.java
+++
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadOnlyFavoredStochasticBalancer.java
@@ -17,8 +17,8 @@
*/
package org.apache.hadoop.hbase.master.balancer;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
/**
* Used for FavoredNode unit tests
@@ -26,9 +26,10 @@ import java.util.List;
public class LoadOnlyFavoredStochasticBalancer extends
FavoredStochasticBalancer {
@Override
- protected List<CandidateGenerator> createCandidateGenerators() {
- List<CandidateGenerator> fnPickers = new ArrayList<>(1);
- fnPickers.add(new FavoredNodeLoadPicker());
+ protected Map<Class<? extends CandidateGenerator>, CandidateGenerator>
+ createCandidateGenerators() {
+ Map<Class<? extends CandidateGenerator>, CandidateGenerator> fnPickers =
new HashMap<>(1);
+ fnPickers.put(FavoredNodeLoadPicker.class, new FavoredNodeLoadPicker());
return fnPickers;
}
}