This is an automated email from the ASF dual-hosted git repository.

zhangduo pushed a commit to branch branch-2.5
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2.5 by this push:
     new bba2eda1a1c HBASE-28913 LoadBalancerPerformanceEvaluation fails with 
NPE (#7789) (#7799)
bba2eda1a1c is described below

commit bba2eda1a1cf590f60fb48585e124b06bec8a8a1
Author: Liu Xiao <[email protected]>
AuthorDate: Thu Feb 26 15:08:27 2026 +0800

    HBASE-28913 LoadBalancerPerformanceEvaluation fails with NPE (#7789) (#7799)
    
    Signed-off-by: Duo Zhang <[email protected]>
---
 .../master/balancer/StochasticLoadBalancer.java    |  9 +-
 .../LoadBalancerPerformanceEvaluation.java         | 25 ++++--
 .../TestLoadBalancerPerformanceEvaluation.java     | 98 ++++++++++++++++++++++
 3 files changed, 122 insertions(+), 10 deletions(-)

diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
index 1237d2c899d..ee5475d6fe6 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
@@ -282,10 +282,11 @@ public class StochasticLoadBalancer extends 
BaseLoadBalancer {
       this.namedQueueRecorder = NamedQueueRecorder.getInstance(conf);
     }
 
-    LOG.info("Loaded config; maxSteps=" + maxSteps + ", runMaxSteps=" + 
runMaxSteps
-      + ", stepsPerRegion=" + stepsPerRegion + ", maxRunningTime=" + 
maxRunningTime + ", isByTable="
-      + isByTable + ", CostFunctions=" + 
Arrays.toString(getCostFunctionNames())
-      + " , sum of multiplier of cost functions = " + sumMultiplier + " etc.");
+    LOG.info(
+      "Loaded config: maxSteps={}, runMaxSteps={}, stepsPerRegion={}, 
maxRunningTime={}, "
+        + "isByTable={}, CostFunctions={}, sum of multiplier of cost functions 
= {} etc.",
+      maxSteps, runMaxSteps, stepsPerRegion, maxRunningTime, isByTable,
+      Arrays.toString(getCostFunctionNames()), sumMultiplier);
   }
 
   @Override
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadBalancerPerformanceEvaluation.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadBalancerPerformanceEvaluation.java
index d5c66828bb2..0058fff02f7 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadBalancerPerformanceEvaluation.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadBalancerPerformanceEvaluation.java
@@ -17,6 +17,9 @@
  */
 package org.apache.hadoop.hbase.master.balancer;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -32,6 +35,7 @@ import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.RegionInfo;
 import org.apache.hadoop.hbase.client.RegionInfoBuilder;
 import org.apache.hadoop.hbase.master.LoadBalancer;
+import org.apache.hadoop.hbase.master.MasterServices;
 import org.apache.hadoop.hbase.util.AbstractHBaseTool;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.yetus.audience.InterfaceAudience;
@@ -57,16 +61,16 @@ public class LoadBalancerPerformanceEvaluation extends 
AbstractHBaseTool {
   protected static final HBaseCommonTestingUtility UTIL = new 
HBaseCommonTestingUtility();
 
   private static final int DEFAULT_NUM_REGIONS = 1000000;
-  private static Option NUM_REGIONS_OPT = new Option("regions", true,
+  private static final Option NUM_REGIONS_OPT = new Option("regions", true,
     "Number of regions to consider by load balancer. Default: " + 
DEFAULT_NUM_REGIONS);
 
   private static final int DEFAULT_NUM_SERVERS = 1000;
-  private static Option NUM_SERVERS_OPT = new Option("servers", true,
+  private static final Option NUM_SERVERS_OPT = new Option("servers", true,
     "Number of servers to consider by load balancer. Default: " + 
DEFAULT_NUM_SERVERS);
 
   private static final String DEFAULT_LOAD_BALANCER =
     "org.apache.hadoop.hbase.master.balancer.StochasticLoadBalancer";
-  private static Option LOAD_BALANCER_OPT = new Option("load_balancer", true,
+  private static final Option LOAD_BALANCER_OPT = new Option("load_balancer", 
true,
     "Type of Load Balancer to use. Default: " + DEFAULT_LOAD_BALANCER);
 
   private int numRegions;
@@ -87,6 +91,15 @@ public class LoadBalancerPerformanceEvaluation extends 
AbstractHBaseTool {
     conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, 
loadBalancerClazz,
       LoadBalancer.class);
     loadBalancer = LoadBalancerFactory.getLoadBalancer(conf);
+    MasterServices services = mock(MasterServices.class);
+    when(services.getConfiguration()).thenReturn(conf);
+    loadBalancer.setMasterServices(services);
+    try {
+      loadBalancer.initialize();
+    } catch (IOException e) {
+      LOG.error("Failed to initialize load balancer", e);
+      throw new RuntimeException("Failed to initialize load balancer", e);
+    }
   }
 
   private void generateRegionsAndServers() {
@@ -154,19 +167,19 @@ public class LoadBalancerPerformanceEvaluation extends 
AbstractHBaseTool {
     generateRegionsAndServers();
 
     String methodName = "roundRobinAssignment";
-    LOG.info("Calling " + methodName);
+    LOG.info("Calling {}", methodName);
     Stopwatch watch = Stopwatch.createStarted();
     loadBalancer.roundRobinAssignment(regions, servers);
     System.out.print(formatResults(methodName, 
watch.elapsed(TimeUnit.MILLISECONDS)));
 
     methodName = "retainAssignment";
-    LOG.info("Calling " + methodName);
+    LOG.info("Calling {}", methodName);
     watch.reset().start();
     loadBalancer.retainAssignment(regionServerMap, servers);
     System.out.print(formatResults(methodName, 
watch.elapsed(TimeUnit.MILLISECONDS)));
 
     methodName = "balanceCluster";
-    LOG.info("Calling " + methodName);
+    LOG.info("Calling {}", methodName);
     watch.reset().start();
 
     loadBalancer.balanceCluster(tableServerRegionMap);
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestLoadBalancerPerformanceEvaluation.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestLoadBalancerPerformanceEvaluation.java
new file mode 100644
index 00000000000..b39907e9bf1
--- /dev/null
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestLoadBalancerPerformanceEvaluation.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master.balancer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.master.LoadBalancer;
+import org.apache.hadoop.hbase.testclassification.LargeTests;
+import org.apache.hadoop.hbase.testclassification.MasterTests;
+import org.apache.hadoop.hbase.util.AbstractHBaseTool;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+@Tag(MasterTests.TAG)
+@Tag(LargeTests.TAG)
+public class TestLoadBalancerPerformanceEvaluation {
+
+  private static final LoadBalancerPerformanceEvaluation tool =
+    new LoadBalancerPerformanceEvaluation();
+
+  @BeforeEach
+  public void setUpBeforeEach() {
+    tool.setConf(HBaseConfiguration.create());
+  }
+
+  @AfterEach
+  public void tearDownAfterEach() {
+    DefaultMetricsSystem.shutdown();
+  }
+
+  @Test
+  public void testLoadBalancerWithDefaultParams() throws IOException {
+    int ret = tool.run(new String[0]);
+    assertEquals(AbstractHBaseTool.EXIT_SUCCESS, ret);
+  }
+
+  @Test
+  public void testStochasticLoadBalancer() throws Exception {
+    testLoadBalancer(StochasticLoadBalancer.class);
+  }
+
+  @Test
+  public void testSimpleLoadBalancer() throws Exception {
+    testLoadBalancer(SimpleLoadBalancer.class);
+  }
+
+  private void testLoadBalancer(Class<? extends LoadBalancer> 
loadBalancerClass) throws Exception {
+    String[] args =
+      { "-regions", "1000", "-servers", "100", "-load_balancer", 
loadBalancerClass.getName() };
+    int ret = tool.run(args);
+    assertEquals(AbstractHBaseTool.EXIT_SUCCESS, ret);
+  }
+
+  @Test
+  public void testInvalidRegions() {
+    String[] args = { "-regions", "-100" };
+    IllegalArgumentException exception =
+      assertThrows(IllegalArgumentException.class, () -> tool.run(args));
+    assertEquals("Invalid number of regions!", exception.getMessage());
+  }
+
+  @Test
+  public void testInvalidServers() {
+    String[] args = { "-servers", "0" };
+    IllegalArgumentException exception =
+      assertThrows(IllegalArgumentException.class, () -> tool.run(args));
+    assertEquals("Invalid number of servers!", exception.getMessage());
+  }
+
+  @Test
+  public void testEmptyLoadBalancer() {
+    String[] args = { "-load_balancer", "" };
+    IllegalArgumentException exception =
+      assertThrows(IllegalArgumentException.class, () -> tool.run(args));
+    assertEquals("Invalid load balancer type!", exception.getMessage());
+  }
+}

Reply via email to