You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by el...@apache.org on 2021/09/02 01:54:39 UTC
[hbase] branch master updated: HBASE-26147 Add a dry run mode to
the balancer, where moves are calculated but not actually executed
This is an automated email from the ASF dual-hosted git repository.
elserj 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 a15e94a HBASE-26147 Add a dry run mode to the balancer, where moves are calculated but not actually executed
a15e94a is described below
commit a15e94a47f06ae665a0c213d092761431e907eac
Author: Bryan Beaudreault <bb...@hubspot.com>
AuthorDate: Tue Jul 27 17:25:59 2021 -0400
HBASE-26147 Add a dry run mode to the balancer, where moves are calculated but not actually executed
Closes #3630
Signed-off-by: Duo Zhang <zh...@apache.org>
Signed-off-by: Josh Elser <elserj@apache.org
---
.../java/org/apache/hadoop/hbase/client/Admin.java | 40 ++++++-
.../hadoop/hbase/client/AdminOverAsyncAdmin.java | 9 +-
.../org/apache/hadoop/hbase/client/AsyncAdmin.java | 37 +++++-
.../hadoop/hbase/client/AsyncHBaseAdmin.java | 8 +-
.../apache/hadoop/hbase/client/BalanceRequest.java | 114 +++++++++++++++++++
.../hadoop/hbase/client/BalanceResponse.java | 126 +++++++++++++++++++++
.../hadoop/hbase/client/RawAsyncHBaseAdmin.java | 29 +++--
.../hadoop/hbase/shaded/protobuf/ProtobufUtil.java | 63 +++++++++++
.../hbase/shaded/protobuf/RequestConverter.java | 10 --
.../src/main/protobuf/server/master/Master.proto | 5 +-
.../protobuf/server/rsgroup/RSGroupAdmin.proto | 4 +
.../hadoop/hbase/coprocessor/MasterObserver.java | 16 ++-
.../org/apache/hadoop/hbase/master/HMaster.java | 54 +++++----
.../hadoop/hbase/master/MasterCoprocessorHost.java | 18 +--
.../hadoop/hbase/master/MasterRpcServices.java | 34 +++---
.../hbase/rsgroup/DisabledRSGroupInfoManager.java | 4 +-
.../hadoop/hbase/rsgroup/RSGroupAdminClient.java | 11 +-
.../hbase/rsgroup/RSGroupAdminServiceImpl.java | 23 ++--
.../hadoop/hbase/rsgroup/RSGroupInfoManager.java | 4 +-
.../hbase/rsgroup/RSGroupInfoManagerImpl.java | 29 +++--
.../hbase/security/access/AccessController.java | 5 +-
.../apache/hadoop/hbase/TestRegionRebalancing.java | 27 ++++-
.../client/TestAsyncTableGetMultiThreaded.java | 2 +-
.../hadoop/hbase/client/TestMultiParallel.java | 2 +-
.../hbase/client/TestSeparateClientZKCluster.java | 2 +-
.../hbase/coprocessor/TestMasterObserver.java | 13 ++-
.../hbase/master/TestMasterDryRunBalancer.java | 125 ++++++++++++++++++++
.../master/procedure/TestProcedurePriority.java | 3 +-
.../hadoop/hbase/rsgroup/TestRSGroupsBalance.java | 91 ++++++++++-----
.../hadoop/hbase/rsgroup/TestRSGroupsBase.java | 6 +-
.../hadoop/hbase/rsgroup/TestRSGroupsFallback.java | 4 +-
.../hbase/rsgroup/VerifyingRSGroupAdmin.java | 14 +--
.../security/access/TestAccessController.java | 8 +-
.../access/TestWithDisabledAuthorization.java | 6 +-
hbase-shell/src/main/ruby/hbase/admin.rb | 9 +-
hbase-shell/src/main/ruby/hbase/balancer_utils.rb | 57 ++++++++++
hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb | 7 +-
.../main/ruby/shell/commands/balance_rsgroup.rb | 22 +++-
.../src/main/ruby/shell/commands/balancer.rb | 33 +++---
hbase-shell/src/test/ruby/hbase/admin_test.rb | 8 +-
.../src/test/ruby/hbase/balancer_utils_test.rb | 78 +++++++++++++
.../src/test/ruby/shell/rsgroup_shell_test.rb | 2 +
.../hadoop/hbase/thrift2/client/ThriftAdmin.java | 9 +-
43 files changed, 966 insertions(+), 205 deletions(-)
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
index 1363605..48893cc 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
@@ -831,7 +831,20 @@ public interface Admin extends Abortable, Closeable {
* @return <code>true</code> if balancer ran, <code>false</code> otherwise.
* @throws IOException if a remote or network exception occurs
*/
- boolean balance() throws IOException;
+ default boolean balance() throws IOException {
+ return balance(BalanceRequest.defaultInstance())
+ .isBalancerRan();
+ }
+
+ /**
+ * Invoke the balancer with the given balance request. The BalanceRequest defines how the
+ * balancer will run. See {@link BalanceRequest} for more details.
+ *
+ * @param request defines how the balancer should run
+ * @return {@link BalanceResponse} with details about the results of the invocation.
+ * @throws IOException if a remote or network exception occurs
+ */
+ BalanceResponse balance(BalanceRequest request) throws IOException;
/**
* Invoke the balancer. Will run the balancer and if regions to move, it will
@@ -841,8 +854,17 @@ public interface Admin extends Abortable, Closeable {
* @param force whether we should force balance even if there is region in transition
* @return <code>true</code> if balancer ran, <code>false</code> otherwise.
* @throws IOException if a remote or network exception occurs
+ * @deprecated Since 2.5.0. Will be removed in 4.0.0.
+ * Use {@link #balance(BalanceRequest)} instead.
*/
- boolean balance(boolean force) throws IOException;
+ @Deprecated
+ default boolean balance(boolean force) throws IOException {
+ return balance(
+ BalanceRequest.newBuilder()
+ .setIgnoreRegionsInTransition(force)
+ .build()
+ ).isBalancerRan();
+ }
/**
* Query the current state of the balancer.
@@ -2494,10 +2516,20 @@ public interface Admin extends Abortable, Closeable {
/**
* Balance regions in the given RegionServer group
* @param groupName the group name
- * @return boolean Whether balance ran or not
+ * @return BalanceResponse details about the balancer run
* @throws IOException if a remote or network exception occurs
*/
- boolean balanceRSGroup(String groupName) throws IOException;
+ default BalanceResponse balanceRSGroup(String groupName) throws IOException {
+ return balanceRSGroup(groupName, BalanceRequest.defaultInstance());
+ }
+
+ /**
+ * Balance regions in the given RegionServer group, running based on
+ * the given {@link BalanceRequest}.
+ *
+ * @return BalanceResponse details about the balancer run
+ */
+ BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) throws IOException;
/**
* Rename rsgroup
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java
index 4a62f02..08de979 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java
@@ -374,6 +374,11 @@ class AdminOverAsyncAdmin implements Admin {
return get(admin.balancerSwitch(onOrOff, synchronous));
}
+
+ public BalanceResponse balance(BalanceRequest request) throws IOException {
+ return get(admin.balance(request));
+ }
+
@Override
public boolean balance() throws IOException {
return get(admin.balance());
@@ -1006,8 +1011,8 @@ class AdminOverAsyncAdmin implements Admin {
}
@Override
- public boolean balanceRSGroup(String groupName) throws IOException {
- return get(admin.balanceRSGroup(groupName));
+ public BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) throws IOException {
+ return get(admin.balanceRSGroup(groupName, request));
}
@Override
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
index a5b1510..c366d3e 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
@@ -1287,7 +1287,8 @@ public interface AsyncAdmin {
* {@link CompletableFuture}.
*/
default CompletableFuture<Boolean> balance() {
- return balance(false);
+ return balance(BalanceRequest.defaultInstance())
+ .thenApply(BalanceResponse::isBalancerRan);
}
/**
@@ -1297,8 +1298,25 @@ public interface AsyncAdmin {
* @param forcible whether we should force balance even if there is region in transition.
* @return True if balancer ran, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}.
+ * @deprecated Since 2.5.0. Will be removed in 4.0.0.
+ * Use {@link #balance(BalanceRequest)} instead.
+ */
+ default CompletableFuture<Boolean> balance(boolean forcible) {
+ return balance(
+ BalanceRequest.newBuilder()
+ .setIgnoreRegionsInTransition(forcible)
+ .build()
+ ).thenApply(BalanceResponse::isBalancerRan);
+ }
+
+ /**
+ * Invoke the balancer with the given balance request. The BalanceRequest defines how the
+ * balancer will run. See {@link BalanceRequest} for more details.
+ *
+ * @param request defines how the balancer should run
+ * @return {@link BalanceResponse} with details about the results of the invocation.
*/
- CompletableFuture<Boolean> balance(boolean forcible);
+ CompletableFuture<BalanceResponse> balance(BalanceRequest request);
/**
* Query the current state of the balancer.
@@ -1722,10 +1740,21 @@ public interface AsyncAdmin {
/**
* Balance regions in the given RegionServer group
* @param groupName the group name
- * @return boolean Whether balance ran or not
+ * @return BalanceResponse details about the balancer run
+ * @throws IOException if a remote or network exception occurs
+ */
+ default CompletableFuture<BalanceResponse> balanceRSGroup(String groupName) {
+ return balanceRSGroup(groupName, BalanceRequest.defaultInstance());
+ }
+
+ /**
+ * Balance regions in the given RegionServer group
+ * @param groupName the group name
+ * @param request options to define how the balancer should run
+ * @return BalanceResponse details about the balancer run
* @throws IOException if a remote or network exception occurs
*/
- CompletableFuture<Boolean> balanceRSGroup(String groupName);
+ CompletableFuture<BalanceResponse> balanceRSGroup(String groupName, BalanceRequest request);
/**
* Rename rsgroup
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
index 8caee48..f0f564b 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
@@ -694,8 +694,8 @@ class AsyncHBaseAdmin implements AsyncAdmin {
}
@Override
- public CompletableFuture<Boolean> balance(boolean forcible) {
- return wrap(rawAdmin.balance(forcible));
+ public CompletableFuture<BalanceResponse> balance(BalanceRequest request) {
+ return wrap(rawAdmin.balance(request));
}
@Override
@@ -883,8 +883,8 @@ class AsyncHBaseAdmin implements AsyncAdmin {
}
@Override
- public CompletableFuture<Boolean> balanceRSGroup(String groupName) {
- return wrap(rawAdmin.balanceRSGroup(groupName));
+ public CompletableFuture<BalanceResponse> balanceRSGroup(String groupName, BalanceRequest request) {
+ return wrap(rawAdmin.balanceRSGroup(groupName, request));
}
@Override
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/BalanceRequest.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/BalanceRequest.java
new file mode 100644
index 0000000..e464410
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/BalanceRequest.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * 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.client;
+
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Encapsulates options for executing a run of the Balancer.
+ */
+@InterfaceAudience.Public
+public final class BalanceRequest {
+ private static final BalanceRequest DEFAULT = BalanceRequest.newBuilder().build();
+
+ /**
+ * Builder for constructing a {@link BalanceRequest}
+ */
+ @InterfaceAudience.Public
+ public final static class Builder {
+ private boolean dryRun = false;
+ private boolean ignoreRegionsInTransition = false;
+
+ private Builder() {}
+
+ /**
+ * Creates a BalancerRequest which runs the balancer in dryRun mode.
+ * In this mode, the balancer will try to find a plan but WILL NOT
+ * execute any region moves or call any coprocessors.
+ *
+ * You can run in dryRun mode regardless of whether the balancer switch
+ * is enabled or disabled, but dryRun mode will not run over an existing
+ * request or chore.
+ *
+ * Dry run is useful for testing out new balance configs. See the logs
+ * on the active HMaster for the results of the dry run.
+ */
+ public Builder setDryRun(boolean dryRun) {
+ this.dryRun = dryRun;
+ return this;
+ }
+
+ /**
+ * Creates a BalancerRequest to cause the balancer to run even if there
+ * are regions in transition.
+ *
+ * WARNING: Advanced usage only, this could cause more issues than it fixes.
+ */
+ public Builder setIgnoreRegionsInTransition(boolean ignoreRegionsInTransition) {
+ this.ignoreRegionsInTransition = ignoreRegionsInTransition;
+ return this;
+ }
+
+ /**
+ * Build the {@link BalanceRequest}
+ */
+ public BalanceRequest build() {
+ return new BalanceRequest(dryRun, ignoreRegionsInTransition);
+ }
+ }
+
+ /**
+ * Create a builder to construct a custom {@link BalanceRequest}.
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Get a BalanceRequest for a default run of the balancer. The default mode executes
+ * any moves calculated and will not run if regions are already in transition.
+ */
+ public static BalanceRequest defaultInstance() {
+ return DEFAULT;
+ }
+
+ private final boolean dryRun;
+ private final boolean ignoreRegionsInTransition;
+
+ private BalanceRequest(boolean dryRun, boolean ignoreRegionsInTransition) {
+ this.dryRun = dryRun;
+ this.ignoreRegionsInTransition = ignoreRegionsInTransition;
+ }
+
+ /**
+ * Returns true if the balancer should run in dry run mode, otherwise false. In
+ * dry run mode, moves will be calculated but not executed.
+ */
+ public boolean isDryRun() {
+ return dryRun;
+ }
+
+ /**
+ * Returns true if the balancer should execute even if regions are in transition, otherwise
+ * false. This is an advanced usage feature, as it can cause more issues than it fixes.
+ */
+ public boolean isIgnoreRegionsInTransition() {
+ return ignoreRegionsInTransition;
+ }
+}
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/BalanceResponse.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/BalanceResponse.java
new file mode 100644
index 0000000..0d8e84b
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/BalanceResponse.java
@@ -0,0 +1,126 @@
+/*
+ *
+ * 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.client;
+
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Response returned from a balancer invocation
+ */
+@InterfaceAudience.Public
+public final class BalanceResponse {
+
+ /**
+ * Builds a {@link BalanceResponse} for returning results of a balance invocation to callers
+ */
+ @InterfaceAudience.Public
+ public final static class Builder {
+ private boolean balancerRan;
+ private int movesCalculated;
+ private int movesExecuted;
+
+ private Builder() {}
+
+ /**
+ * Set true if the balancer ran, otherwise false. The balancer may not run in some
+ * circumstances, such as if a balance is already running or there are regions already
+ * in transition.
+ *
+ * @param balancerRan true if balancer ran, false otherwise
+ */
+ public Builder setBalancerRan(boolean balancerRan) {
+ this.balancerRan = balancerRan;
+ return this;
+ }
+
+ /**
+ * Set how many moves were calculated by the balancer. This will be zero if the cluster is
+ * already balanced.
+ *
+ * @param movesCalculated moves calculated by the balance run
+ */
+ public Builder setMovesCalculated(int movesCalculated) {
+ this.movesCalculated = movesCalculated;
+ return this;
+ }
+
+ /**
+ * Set how many of the calculated moves were actually executed by the balancer. This should be
+ * zero if the balancer is run with {@link BalanceRequest#isDryRun()}. It may also not equal
+ * movesCalculated if the balancer ran out of time while executing the moves.
+ *
+ * @param movesExecuted moves executed by the balance run
+ */
+ public Builder setMovesExecuted(int movesExecuted) {
+ this.movesExecuted = movesExecuted;
+ return this;
+ }
+
+ /**
+ * Build the {@link BalanceResponse}
+ */
+ public BalanceResponse build() {
+ return new BalanceResponse(balancerRan, movesCalculated, movesExecuted);
+ }
+ }
+
+ /**
+ * Creates a new {@link BalanceResponse.Builder}
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ private final boolean balancerRan;
+ private final int movesCalculated;
+ private final int movesExecuted;
+
+ private BalanceResponse(boolean balancerRan, int movesCalculated, int movesExecuted) {
+ this.balancerRan = balancerRan;
+ this.movesCalculated = movesCalculated;
+ this.movesExecuted = movesExecuted;
+ }
+
+ /**
+ * Returns true if the balancer ran, otherwise false. The balancer may not run for a
+ * variety of reasons, such as: another balance is running, there are regions in
+ * transition, the cluster is in maintenance mode, etc.
+ */
+ public boolean isBalancerRan() {
+ return balancerRan;
+ }
+
+ /**
+ * The number of moves calculated by the balancer if {@link #isBalancerRan()} is true. This will
+ * be zero if no better balance could be found.
+ */
+ public int getMovesCalculated() {
+ return movesCalculated;
+ }
+
+ /**
+ * The number of moves actually executed by the balancer if it ran. This will be
+ * zero if {@link #getMovesCalculated()} is zero or if {@link BalanceRequest#isDryRun()}
+ * was true. It may also not be equal to {@link #getMovesCalculated()} if the balancer
+ * was interrupted midway through executing the moves due to max run time.
+ */
+ public int getMovesExecuted() {
+ return movesExecuted;
+ }
+}
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
index 1cbcf10..292c9cb 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
@@ -21,7 +21,6 @@ import static org.apache.hadoop.hbase.HConstants.HIGH_QOS;
import static org.apache.hadoop.hbase.TableName.META_TABLE_NAME;
import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
import static org.apache.hadoop.hbase.util.FutureUtils.unwrapCompletionException;
-
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
@@ -147,14 +146,13 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.NameStringP
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ProcedureDescription;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.TableSchema;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AbortProcedureRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AbortProcedureResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionResponse;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest;
@@ -3281,15 +3279,16 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
}
@Override
- public CompletableFuture<Boolean> balance(boolean forcible) {
+ public CompletableFuture<BalanceResponse> balance(BalanceRequest request) {
return this
- .<Boolean> newMasterCaller()
+ .<BalanceResponse> newMasterCaller()
.action(
- (controller, stub) -> this.<BalanceRequest, BalanceResponse, Boolean> call(controller,
- stub, RequestConverter.buildBalanceRequest(forcible),
- (s, c, req, done) -> s.balance(c, req, done), (resp) -> resp.getBalancerRan())).call();
+ (controller, stub) -> this.<MasterProtos.BalanceRequest, MasterProtos.BalanceResponse, BalanceResponse> call(controller,
+ stub, ProtobufUtil.toBalanceRequest(request),
+ (s, c, req, done) -> s.balance(c, req, done), (resp) -> ProtobufUtil.toBalanceResponse(resp))).call();
}
+
@Override
public CompletableFuture<Boolean> isBalancerEnabled() {
return this
@@ -3999,13 +3998,13 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
}
@Override
- public CompletableFuture<Boolean> balanceRSGroup(String groupName) {
- return this.<Boolean> newMasterCaller()
- .action((controller, stub) -> this.
- <BalanceRSGroupRequest, BalanceRSGroupResponse, Boolean> call(controller, stub,
- BalanceRSGroupRequest.newBuilder().setRSGroupName(groupName).build(),
- (s, c, req, done) -> s.balanceRSGroup(c, req, done), resp -> resp.getBalanceRan()))
- .call();
+ public CompletableFuture<BalanceResponse> balanceRSGroup(String groupName,
+ BalanceRequest request) {
+ return this.<BalanceResponse>newMasterCaller().action(
+ (controller, stub) -> this.<BalanceRSGroupRequest, BalanceRSGroupResponse, BalanceResponse>call(
+ controller, stub, ProtobufUtil.createBalanceRSGroupRequest(groupName, request),
+ MasterService.Interface::balanceRSGroup, ProtobufUtil::toBalanceResponse))
+ .call();
}
@Override
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
index 329894c..82da13e 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
@@ -47,6 +47,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.client.BalanceRequest;
import org.apache.hadoop.hbase.ByteBufferExtendedCell;
import org.apache.hadoop.hbase.CacheEvictionStats;
import org.apache.hadoop.hbase.CacheEvictionStatsBuilder;
@@ -68,6 +69,7 @@ import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Append;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.BalancerRejection;
import org.apache.hadoop.hbase.client.BalancerDecision;
import org.apache.hadoop.hbase.client.CheckAndMutate;
@@ -118,6 +120,7 @@ import org.apache.hadoop.hbase.replication.ReplicationLoadSource;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.visibility.Authorizations;
import org.apache.hadoop.hbase.security.visibility.CellVisibility;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos;
import org.apache.hadoop.hbase.util.Addressing;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.DynamicClassLoader;
@@ -3607,6 +3610,36 @@ public final class ProtobufUtil {
return clearSlowLogResponses.getIsCleaned();
}
+ public static void populateBalanceRSGroupResponse(RSGroupAdminProtos.BalanceRSGroupResponse.Builder responseBuilder, BalanceResponse response) {
+ responseBuilder
+ .setBalanceRan(response.isBalancerRan())
+ .setMovesCalculated(response.getMovesCalculated())
+ .setMovesExecuted(response.getMovesExecuted());
+ }
+
+ public static BalanceResponse toBalanceResponse(RSGroupAdminProtos.BalanceRSGroupResponse response) {
+ return BalanceResponse.newBuilder()
+ .setBalancerRan(response.getBalanceRan())
+ .setMovesExecuted(response.hasMovesExecuted() ? response.getMovesExecuted() : 0)
+ .setMovesCalculated(response.hasMovesCalculated() ? response.getMovesCalculated() : 0)
+ .build();
+ }
+
+ public static RSGroupAdminProtos.BalanceRSGroupRequest createBalanceRSGroupRequest(String groupName, BalanceRequest request) {
+ return RSGroupAdminProtos.BalanceRSGroupRequest.newBuilder()
+ .setRSGroupName(groupName)
+ .setDryRun(request.isDryRun())
+ .setIgnoreRit(request.isIgnoreRegionsInTransition())
+ .build();
+ }
+
+ public static BalanceRequest toBalanceRequest(RSGroupAdminProtos.BalanceRSGroupRequest request) {
+ return BalanceRequest.newBuilder()
+ .setDryRun(request.hasDryRun() && request.getDryRun())
+ .setIgnoreRegionsInTransition(request.hasIgnoreRit() && request.getIgnoreRit())
+ .build();
+ }
+
public static RSGroupInfo toGroupInfo(RSGroupProtos.RSGroupInfo proto) {
RSGroupInfo rsGroupInfo = new RSGroupInfo(proto.getName());
@@ -3835,4 +3868,34 @@ public final class ProtobufUtil {
.build();
}
+ public static MasterProtos.BalanceRequest toBalanceRequest(BalanceRequest request) {
+ return MasterProtos.BalanceRequest.newBuilder()
+ .setDryRun(request.isDryRun())
+ .setIgnoreRit(request.isIgnoreRegionsInTransition())
+ .build();
+ }
+
+ public static BalanceRequest toBalanceRequest(MasterProtos.BalanceRequest request) {
+ return BalanceRequest.newBuilder()
+ .setDryRun(request.hasDryRun() && request.getDryRun())
+ .setIgnoreRegionsInTransition(request.hasIgnoreRit() && request.getIgnoreRit())
+ .build();
+ }
+
+ public static MasterProtos.BalanceResponse toBalanceResponse(BalanceResponse response) {
+ return MasterProtos.BalanceResponse.newBuilder()
+ .setBalancerRan(response.isBalancerRan())
+ .setMovesCalculated(response.getMovesCalculated())
+ .setMovesExecuted(response.getMovesExecuted())
+ .build();
+ }
+
+ public static BalanceResponse toBalanceResponse(MasterProtos.BalanceResponse response) {
+ return BalanceResponse.newBuilder()
+ .setBalancerRan(response.hasBalancerRan() && response.getBalancerRan())
+ .setMovesCalculated(response.hasMovesCalculated() ? response.getMovesExecuted() : 0)
+ .setMovesExecuted(response.hasMovesExecuted() ? response.getMovesExecuted() : 0)
+ .build();
+ }
+
}
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java
index c5911ab..821f731 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java
@@ -105,7 +105,6 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionSpeci
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionRequest;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateTableRequest;
@@ -1327,15 +1326,6 @@ public final class RequestConverter {
}
/**
- * Creates a protocol buffer BalanceRequest
- *
- * @return a BalanceRequest
- */
- public static BalanceRequest buildBalanceRequest(boolean force) {
- return BalanceRequest.newBuilder().setForce(force).build();
- }
-
- /**
* Creates a protocol buffer SetBalancerRunningRequest
*
* @param on
diff --git a/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto b/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto
index 628b0ca..ea09e11 100644
--- a/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto
+++ b/hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto
@@ -293,11 +293,14 @@ message IsInMaintenanceModeResponse {
}
message BalanceRequest {
- optional bool force = 1;
+ optional bool ignore_rit = 1;
+ optional bool dry_run = 2;
}
message BalanceResponse {
required bool balancer_ran = 1;
+ optional uint32 moves_calculated = 2;
+ optional uint32 moves_executed = 3;
}
message SetBalancerRunningRequest {
diff --git a/hbase-protocol-shaded/src/main/protobuf/server/rsgroup/RSGroupAdmin.proto b/hbase-protocol-shaded/src/main/protobuf/server/rsgroup/RSGroupAdmin.proto
index 9f38d2b..7f6ba4d 100644
--- a/hbase-protocol-shaded/src/main/protobuf/server/rsgroup/RSGroupAdmin.proto
+++ b/hbase-protocol-shaded/src/main/protobuf/server/rsgroup/RSGroupAdmin.proto
@@ -85,10 +85,14 @@ message RemoveRSGroupResponse {
message BalanceRSGroupRequest {
required string r_s_group_name = 1;
+ optional bool ignore_rit = 2;
+ optional bool dry_run = 3;
}
message BalanceRSGroupResponse {
required bool balanceRan = 1;
+ optional uint32 moves_calculated = 2;
+ optional uint32 moves_executed = 3;
}
message ListRSGroupInfosRequest {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
index ac35caa..02607b7 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
@@ -28,6 +28,8 @@ import org.apache.hadoop.hbase.MetaMutationAnnotation;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.MasterSwitchType;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.RegionInfo;
@@ -540,18 +542,20 @@ public interface MasterObserver {
* Called prior to requesting rebalancing of the cluster regions, though after
* the initial checks for regions in transition and the balance switch flag.
* @param ctx the environment to interact with the framework and master
+ * @param request the request used to trigger the balancer
*/
- default void preBalance(final ObserverContext<MasterCoprocessorEnvironment> ctx)
+ default void preBalance(final ObserverContext<MasterCoprocessorEnvironment> ctx, BalanceRequest request)
throws IOException {}
/**
* Called after the balancing plan has been submitted.
* @param ctx the environment to interact with the framework and master
+ * @param request the request used to trigger the balance
* @param plans the RegionPlans which master has executed. RegionPlan serves as hint
* as for the final destination for the underlying region but may not represent the
* final state of assignment
*/
- default void postBalance(final ObserverContext<MasterCoprocessorEnvironment> ctx, List<RegionPlan> plans)
+ default void postBalance(final ObserverContext<MasterCoprocessorEnvironment> ctx, BalanceRequest request, List<RegionPlan> plans)
throws IOException {}
/**
@@ -1249,15 +1253,19 @@ public interface MasterObserver {
* @param groupName group name
*/
default void preBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
- String groupName) throws IOException {}
+ String groupName, BalanceRequest request) throws IOException {
+ }
/**
* Called after a region server group is removed
* @param ctx the environment to interact with the framework and master
* @param groupName group name
+ * @param request the request sent to the balancer
+ * @param response the response returned by the balancer
*/
default void postBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
- String groupName, boolean balancerRan) throws IOException {}
+ String groupName, BalanceRequest request, BalanceResponse response) throws IOException {
+ }
/**
* Called before servers are removed from rsgroup
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index 0bf160b..2815809 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -60,6 +60,7 @@ import org.apache.hadoop.hbase.CatalogFamilyFormat;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellBuilderFactory;
import org.apache.hadoop.hbase.CellBuilderType;
+import org.apache.hadoop.hbase.client.BalanceRequest;
import org.apache.hadoop.hbase.ClusterId;
import org.apache.hadoop.hbase.ClusterMetrics;
import org.apache.hadoop.hbase.ClusterMetrics.Option;
@@ -82,6 +83,7 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotDisabledException;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.UnknownRegionException;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.CompactionState;
import org.apache.hadoop.hbase.client.MasterSwitchType;
@@ -1771,8 +1773,8 @@ public class HMaster extends HRegionServer implements MasterServices {
if (interrupted) Thread.currentThread().interrupt();
}
- public boolean balance() throws IOException {
- return balance(false);
+ public BalanceResponse balance() throws IOException {
+ return balance(BalanceRequest.defaultInstance());
}
/**
@@ -1798,12 +1800,16 @@ public class HMaster extends HRegionServer implements MasterServices {
return false;
}
- public boolean balance(boolean force) throws IOException {
- if (loadBalancerTracker == null || !loadBalancerTracker.isBalancerOn()) {
- return false;
+ public BalanceResponse balance(BalanceRequest request) throws IOException {
+ BalanceResponse.Builder responseBuilder = BalanceResponse.newBuilder();
+
+ if (loadBalancerTracker == null
+ || !(loadBalancerTracker.isBalancerOn() || request.isDryRun())) {
+ return responseBuilder.build();
}
+
if (skipRegionManagementAction("balancer")) {
- return false;
+ return responseBuilder.build();
}
synchronized (this.balancer) {
@@ -1820,28 +1826,29 @@ public class HMaster extends HRegionServer implements MasterServices {
toPrint = regionsInTransition.subList(0, max);
truncated = true;
}
- if (!force || metaInTransition) {
- LOG.info("Not running balancer (force=" + force + ", metaRIT=" + metaInTransition +
- ") because " + regionsInTransition.size() + " region(s) in transition: " + toPrint +
- (truncated? "(truncated list)": ""));
- return false;
+
+ if (!request.isIgnoreRegionsInTransition() || metaInTransition) {
+ LOG.info("Not running balancer (ignoreRIT=false" + ", metaRIT=" + metaInTransition +
+ ") because " + regionsInTransition.size() + " region(s) in transition: " + toPrint
+ + (truncated? "(truncated list)": ""));
+ return responseBuilder.build();
}
}
if (this.serverManager.areDeadServersInProgress()) {
LOG.info("Not running balancer because processing dead regionserver(s): " +
this.serverManager.getDeadServers());
- return false;
+ return responseBuilder.build();
}
if (this.cpHost != null) {
try {
- if (this.cpHost.preBalance()) {
+ if (this.cpHost.preBalance(request)) {
LOG.debug("Coprocessor bypassing balancer request");
- return false;
+ return responseBuilder.build();
}
} catch (IOException ioe) {
LOG.error("Error invoking master coprocessor preBalance()", ioe);
- return false;
+ return responseBuilder.build();
}
}
@@ -1857,25 +1864,34 @@ public class HMaster extends HRegionServer implements MasterServices {
List<RegionPlan> plans = this.balancer.balanceCluster(assignments);
+ responseBuilder.setBalancerRan(true).setMovesCalculated(plans == null ? 0 : plans.size());
+
if (skipRegionManagementAction("balancer")) {
// make one last check that the cluster isn't shutting down before proceeding.
- return false;
+ return responseBuilder.build();
}
- List<RegionPlan> sucRPs = executeRegionPlansWithThrottling(plans);
+ // For dry run we don't actually want to execute the moves, but we do want
+ // to execute the coprocessor below
+ List<RegionPlan> sucRPs = request.isDryRun()
+ ? Collections.emptyList()
+ : executeRegionPlansWithThrottling(plans);
if (this.cpHost != null) {
try {
- this.cpHost.postBalance(sucRPs);
+ this.cpHost.postBalance(request, sucRPs);
} catch (IOException ioe) {
// balancing already succeeded so don't change the result
LOG.error("Error invoking master coprocessor postBalance()", ioe);
}
}
+
+ responseBuilder.setMovesExecuted(sucRPs.size());
}
+
// If LoadBalancer did not generate any plans, it means the cluster is already balanced.
// Return true indicating a success.
- return true;
+ return responseBuilder.build();
}
/**
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
index 01d1a62..3c1fcec 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
@@ -29,6 +29,8 @@ import org.apache.hadoop.hbase.MetaMutationAnnotation;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.MasterSwitchType;
import org.apache.hadoop.hbase.client.Mutation;
@@ -732,20 +734,20 @@ public class MasterCoprocessorHost
});
}
- public boolean preBalance() throws IOException {
+ public boolean preBalance(final BalanceRequest request) throws IOException {
return execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {
- observer.preBalance(this);
+ observer.preBalance(this, request);
}
});
}
- public void postBalance(final List<RegionPlan> plans) throws IOException {
+ public void postBalance(final BalanceRequest request, final List<RegionPlan> plans) throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {
- observer.postBalance(this, plans);
+ observer.postBalance(this, request, plans);
}
});
}
@@ -1428,22 +1430,22 @@ public class MasterCoprocessorHost
});
}
- public void preBalanceRSGroup(final String name)
+ public void preBalanceRSGroup(final String name, final BalanceRequest request)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {
- observer.preBalanceRSGroup(this, name);
+ observer.preBalanceRSGroup(this, name, request);
}
});
}
- public void postBalanceRSGroup(final String name, final boolean balanceRan)
+ public void postBalanceRSGroup(final String name, final BalanceRequest request, final BalanceResponse response)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {
- observer.postBalanceRSGroup(this, name, balanceRan);
+ observer.postBalanceRSGroup(this, name, request, response);
}
});
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
index 2a26fa0..a8446c3 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
@@ -18,7 +18,6 @@
package org.apache.hadoop.hbase.master;
import static org.apache.hadoop.hbase.master.MasterWalManager.META_FILTER;
-
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@@ -48,6 +47,8 @@ import org.apache.hadoop.hbase.ServerMetricsBuilder;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.UnknownRegionException;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.MasterSwitchType;
import org.apache.hadoop.hbase.client.NormalizeTableFilterParams;
import org.apache.hadoop.hbase.client.Put;
@@ -127,7 +128,6 @@ import org.apache.yetus.audience.InterfaceAudience;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
import org.apache.hbase.thirdparty.com.google.protobuf.ByteString;
import org.apache.hbase.thirdparty.com.google.protobuf.Descriptors.MethodDescriptor;
@@ -137,7 +137,6 @@ import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
import org.apache.hbase.thirdparty.com.google.protobuf.Service;
import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
-
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.ResponseConverter;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
@@ -176,8 +175,6 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnR
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionResponse;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest;
@@ -696,11 +693,10 @@ public class MasterRpcServices extends RSRpcServices implements
@Override
- public BalanceResponse balance(RpcController controller,
- BalanceRequest request) throws ServiceException {
+ public MasterProtos.BalanceResponse balance(RpcController controller,
+ MasterProtos.BalanceRequest request) throws ServiceException {
try {
- return BalanceResponse.newBuilder().setBalancerRan(master.balance(
- request.hasForce()? request.getForce(): false)).build();
+ return ProtobufUtil.toBalanceResponse(master.balance(ProtobufUtil.toBalanceRequest(request)));
} catch (IOException ex) {
throw new ServiceException(ex);
}
@@ -3141,18 +3137,24 @@ public class MasterRpcServices extends RSRpcServices implements
@Override
public BalanceRSGroupResponse balanceRSGroup(RpcController controller,
BalanceRSGroupRequest request) throws ServiceException {
- BalanceRSGroupResponse.Builder builder = BalanceRSGroupResponse.newBuilder();
+ BalanceRequest balanceRequest = ProtobufUtil.toBalanceRequest(request);
+
+ BalanceRSGroupResponse.Builder builder = BalanceRSGroupResponse.newBuilder()
+ .setBalanceRan(false);
+
LOG.info(
- master.getClientIdAuditPrefix() + " balance rsgroup, group=" + request.getRSGroupName());
+ master.getClientIdAuditPrefix() + " balance rsgroup, group=" + request.getRSGroupName());
try {
if (master.getMasterCoprocessorHost() != null) {
- master.getMasterCoprocessorHost().preBalanceRSGroup(request.getRSGroupName());
+ master.getMasterCoprocessorHost()
+ .preBalanceRSGroup(request.getRSGroupName(), balanceRequest);
}
- boolean balancerRan =
- master.getRSGroupInfoManager().balanceRSGroup(request.getRSGroupName());
- builder.setBalanceRan(balancerRan);
+ BalanceResponse response =
+ master.getRSGroupInfoManager().balanceRSGroup(request.getRSGroupName(), balanceRequest);
+ ProtobufUtil.populateBalanceRSGroupResponse(builder, response);
if (master.getMasterCoprocessorHost() != null) {
- master.getMasterCoprocessorHost().postBalanceRSGroup(request.getRSGroupName(), balancerRan);
+ master.getMasterCoprocessorHost()
+ .postBalanceRSGroup(request.getRSGroupName(), balanceRequest, response);
}
} catch (IOException e) {
throw new ServiceException(e);
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/DisabledRSGroupInfoManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/DisabledRSGroupInfoManager.java
index 3323acd..8ed2505 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/DisabledRSGroupInfoManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/DisabledRSGroupInfoManager.java
@@ -27,6 +27,8 @@ import java.util.TreeSet;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.net.Address;
import org.apache.yetus.audience.InterfaceAudience;
@@ -108,7 +110,7 @@ class DisabledRSGroupInfoManager implements RSGroupInfoManager {
}
@Override
- public boolean balanceRSGroup(String groupName) throws IOException {
+ public BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) throws IOException {
throw new DoNotRetryIOException("RSGroup is disabled");
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java
index 0fe42f3..4c29154 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java
@@ -24,6 +24,8 @@ import java.util.Set;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.net.Address;
import org.apache.yetus.audience.InterfaceAudience;
@@ -161,13 +163,12 @@ public class RSGroupAdminClient {
/**
* Balance regions in the given RegionServer group.
- * @return boolean Whether balance ran or not
+ * @return BalanceResponse details about the balancer run
*/
- public boolean balanceRSGroup(String groupName) throws IOException {
- BalanceRSGroupRequest request =
- BalanceRSGroupRequest.newBuilder().setRSGroupName(groupName).build();
+ public BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) throws IOException {
try {
- return stub.balanceRSGroup(null, request).getBalanceRan();
+ BalanceRSGroupRequest req = ProtobufUtil.createBalanceRSGroupRequest(groupName, request);
+ return ProtobufUtil.toBalanceResponse(stub.balanceRSGroup(null, req));
} catch (ServiceException e) {
throw ProtobufUtil.handleRemoteException(e);
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServiceImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServiceImpl.java
index 241fd65..b8b2a4f 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServiceImpl.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServiceImpl.java
@@ -28,6 +28,8 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
@@ -37,11 +39,9 @@ import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.procedure2.Procedure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
-
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos;
@@ -265,21 +265,28 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
@Override
public void balanceRSGroup(RpcController controller, BalanceRSGroupRequest request,
RpcCallback<BalanceRSGroupResponse> done) {
- BalanceRSGroupResponse.Builder builder = BalanceRSGroupResponse.newBuilder();
+ BalanceRequest balanceRequest = ProtobufUtil.toBalanceRequest(request);
+ BalanceRSGroupResponse.Builder builder = BalanceRSGroupResponse.newBuilder()
+ .setBalanceRan(false);
+
LOG.info(
master.getClientIdAuditPrefix() + " balance rsgroup, group=" + request.getRSGroupName());
try {
if (master.getMasterCoprocessorHost() != null) {
- master.getMasterCoprocessorHost().preBalanceRSGroup(request.getRSGroupName());
+ master.getMasterCoprocessorHost()
+ .preBalanceRSGroup(request.getRSGroupName(), balanceRequest);
}
- boolean balancerRan = rsGroupInfoManager.balanceRSGroup(request.getRSGroupName());
- builder.setBalanceRan(balancerRan);
+
+ BalanceResponse response =
+ rsGroupInfoManager.balanceRSGroup(request.getRSGroupName(), balanceRequest);
+ ProtobufUtil.populateBalanceRSGroupResponse(builder, response);
+
if (master.getMasterCoprocessorHost() != null) {
- master.getMasterCoprocessorHost().postBalanceRSGroup(request.getRSGroupName(), balancerRan);
+ master.getMasterCoprocessorHost()
+ .postBalanceRSGroup(request.getRSGroupName(), balanceRequest, response);
}
} catch (IOException e) {
CoprocessorRpcUtils.setControllerException(controller, e);
- builder.setBalanceRan(false);
}
done.run(builder.build());
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java
index 350f2b4..9d73a52 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java
@@ -22,6 +22,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.net.Address;
import org.apache.yetus.audience.InterfaceAudience;
@@ -93,7 +95,7 @@ public interface RSGroupInfoManager {
/**
* Balance a region server group.
*/
- boolean balanceRSGroup(String groupName) throws IOException;
+ BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) throws IOException;
/**
* Set group for tables.
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java
index 3ef9365..03a31e3 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java
@@ -46,6 +46,8 @@ import org.apache.hadoop.hbase.TableDescriptors;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.AsyncClusterConnection;
import org.apache.hadoop.hbase.client.AsyncTable;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.CoprocessorDescriptorBuilder;
import org.apache.hadoop.hbase.client.Delete;
@@ -1146,29 +1148,33 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
}
@Override
- public boolean balanceRSGroup(String groupName) throws IOException {
+ public BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) throws IOException {
ServerManager serverManager = masterServices.getServerManager();
LoadBalancer balancer = masterServices.getLoadBalancer();
getRSGroupInfo(groupName);
+ BalanceResponse.Builder responseBuilder = BalanceResponse.newBuilder();
+
synchronized (balancer) {
// If balance not true, don't run balancer.
- if (!masterServices.isBalancerOn()) {
- return false;
+ if (!masterServices.isBalancerOn() && !request.isDryRun()) {
+ return responseBuilder.build();
}
+
// Only allow one balance run at at time.
Map<String, RegionState> groupRIT = rsGroupGetRegionsInTransition(groupName);
- if (groupRIT.size() > 0) {
+ if (groupRIT.size() > 0 && !request.isIgnoreRegionsInTransition()) {
LOG.debug("Not running balancer because {} region(s) in transition: {}", groupRIT.size(),
StringUtils.abbreviate(masterServices.getAssignmentManager().getRegionStates()
.getRegionsInTransition().toString(),
256));
- return false;
+ return responseBuilder.build();
}
+
if (serverManager.areDeadServersInProgress()) {
LOG.debug("Not running balancer because processing dead regionserver(s): {}",
serverManager.getDeadServers());
- return false;
+ return responseBuilder.build();
}
// We balance per group instead of per table
@@ -1176,12 +1182,17 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
getRSGroupAssignmentsByTable(masterServices.getTableStateManager(), groupName);
List<RegionPlan> plans = balancer.balanceCluster(assignmentsByTable);
boolean balancerRan = !plans.isEmpty();
- if (balancerRan) {
+
+ responseBuilder.setBalancerRan(balancerRan).setMovesCalculated(plans.size());
+
+ if (balancerRan && !request.isDryRun()) {
LOG.info("RSGroup balance {} starting with plan count: {}", groupName, plans.size());
- masterServices.executeRegionPlansWithThrottling(plans);
+ List<RegionPlan> executed = masterServices.executeRegionPlansWithThrottling(plans);
+ responseBuilder.setMovesExecuted(executed.size());
LOG.info("RSGroup balance " + groupName + " completed");
}
- return balancerRan;
+
+ return responseBuilder.build();
}
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
index ec5a1b8..5ed12c4 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
@@ -53,6 +53,7 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Append;
+import org.apache.hadoop.hbase.client.BalanceRequest;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Delete;
@@ -1000,7 +1001,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
}
@Override
- public void preBalance(ObserverContext<MasterCoprocessorEnvironment> c)
+ public void preBalance(ObserverContext<MasterCoprocessorEnvironment> c, BalanceRequest request)
throws IOException {
requirePermission(c, "balance", Action.ADMIN);
}
@@ -2554,7 +2555,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
@Override
public void preBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx,
- String groupName) throws IOException {
+ String groupName, BalanceRequest request) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "balanceRSGroup",
null, Permission.Action.ADMIN);
}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java
index c9ac60d..4f23bc0 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.hbase;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
@@ -27,6 +28,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
@@ -132,14 +134,21 @@ public class TestRegionRebalancing {
assertRegionsAreBalanced();
// On a balanced cluster, calling balance() should return true
- assert(UTIL.getHBaseCluster().getMaster().balance() == true);
+ BalanceResponse response = UTIL.getHBaseCluster().getMaster().balance();
+ assertTrue(response.isBalancerRan());
+ assertEquals(0, response.getMovesCalculated());
+ assertEquals(0, response.getMovesExecuted());
// if we add a server, then the balance() call should return true
// add a region server - total of 3
LOG.info("Started third server=" +
UTIL.getHBaseCluster().startRegionServer().getRegionServer().getServerName());
waitForAllRegionsAssigned();
- assert(UTIL.getHBaseCluster().getMaster().balance() == true);
+
+ response = UTIL.getHBaseCluster().getMaster().balance();
+ assertTrue(response.isBalancerRan());
+ assertTrue(response.getMovesCalculated() > 0);
+ assertEquals(response.getMovesCalculated(), response.getMovesExecuted());
assertRegionsAreBalanced();
// kill a region server - total of 2
@@ -156,14 +165,24 @@ public class TestRegionRebalancing {
UTIL.getHBaseCluster().startRegionServer().getRegionServer().getServerName());
waitOnCrashProcessing();
waitForAllRegionsAssigned();
- assert(UTIL.getHBaseCluster().getMaster().balance() == true);
+
+ response = UTIL.getHBaseCluster().getMaster().balance();
+ assertTrue(response.isBalancerRan());
+ assertTrue(response.getMovesCalculated() > 0);
+ assertEquals(response.getMovesCalculated(), response.getMovesExecuted());
+
assertRegionsAreBalanced();
for (int i = 0; i < 6; i++){
LOG.info("Adding " + (i + 5) + "th region server");
UTIL.getHBaseCluster().startRegionServer();
}
waitForAllRegionsAssigned();
- assert(UTIL.getHBaseCluster().getMaster().balance() == true);
+
+ response = UTIL.getHBaseCluster().getMaster().balance();
+ assertTrue(response.isBalancerRan());
+ assertTrue(response.getMovesCalculated() > 0);
+ assertEquals(response.getMovesCalculated(), response.getMovesExecuted());
+
assertRegionsAreBalanced();
regionLocator.close();
}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableGetMultiThreaded.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableGetMultiThreaded.java
index ca11ea6..107d59e 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableGetMultiThreaded.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableGetMultiThreaded.java
@@ -196,7 +196,7 @@ public class TestAsyncTableGetMultiThreaded {
}
Thread.sleep(5000);
LOG.info("====== Balancing cluster ======");
- admin.balance(true);
+ admin.balance(BalanceRequest.newBuilder().setIgnoreRegionsInTransition(true).build());
LOG.info("====== Balance cluster done ======");
Thread.sleep(5000);
ServerName metaServer = TEST_UTIL.getHBaseCluster().getServerHoldingMeta();
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestMultiParallel.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestMultiParallel.java
index 038635b..bb878ca 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestMultiParallel.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestMultiParallel.java
@@ -679,7 +679,7 @@ public class TestMultiParallel {
@Override
public void postBalance(final ObserverContext<MasterCoprocessorEnvironment> ctx,
- List<RegionPlan> plans) throws IOException {
+ BalanceRequest request, List<RegionPlan> plans) throws IOException {
if (!plans.isEmpty()) {
postBalanceCount.incrementAndGet();
}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestSeparateClientZKCluster.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestSeparateClientZKCluster.java
index 24a9c51..5274813 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestSeparateClientZKCluster.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestSeparateClientZKCluster.java
@@ -144,7 +144,7 @@ public class TestSeparateClientZKCluster {
}
LOG.info("Got master {}", cluster.getMaster().getServerName());
// confirm client access still works
- assertTrue(admin.balance(false));
+ assertTrue(admin.balance(BalanceRequest.defaultInstance()).isBalancerRan());
}
}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
index c60c55f..8efc4dc 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
@@ -38,6 +38,8 @@ import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.SingleProcessHBaseCluster;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
@@ -690,13 +692,14 @@ public class TestMasterObserver {
}
@Override
- public void preBalance(ObserverContext<MasterCoprocessorEnvironment> env)
- throws IOException {
+ public void preBalance(ObserverContext<MasterCoprocessorEnvironment> env,
+ BalanceRequest request) throws IOException {
preBalanceCalled = true;
}
@Override
public void postBalance(ObserverContext<MasterCoprocessorEnvironment> env,
+ BalanceRequest request,
List<RegionPlan> plans) throws IOException {
postBalanceCalled = true;
}
@@ -1162,12 +1165,12 @@ public class TestMasterObserver {
@Override
public void preBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx,
- String groupName) throws IOException {
+ String groupName, BalanceRequest request) throws IOException {
}
@Override
public void postBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx,
- String groupName, boolean balancerRan) throws IOException {
+ String groupName, BalanceRequest request, BalanceResponse response) throws IOException {
}
@Override
@@ -1621,7 +1624,7 @@ public class TestMasterObserver {
UTIL.waitUntilNoRegionsInTransition();
// now trigger a balance
master.balanceSwitch(true);
- boolean balanceRun = master.balance();
+ master.balance();
assertTrue("Coprocessor should be called on region rebalancing",
cp.wasBalanceCalled());
} finally {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterDryRunBalancer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterDryRunBalancer.java
new file mode 100644
index 0000000..5b41e0a
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterDryRunBalancer.java
@@ -0,0 +1,125 @@
+/**
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import java.io.IOException;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.Waiter;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
+import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.regionserver.HRegionServer;
+import org.apache.hadoop.hbase.testclassification.MasterTests;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.After;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.mockito.Mockito;
+
+@Category({ MasterTests.class, MediumTests.class})
+public class TestMasterDryRunBalancer {
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestMasterDryRunBalancer.class);
+
+ private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
+ private static final byte[] FAMILYNAME = Bytes.toBytes("fam");
+
+ @After
+ public void shutdown() throws Exception {
+ TEST_UTIL.shutdownMiniCluster();
+ }
+
+ @Test
+ public void testDryRunBalancer() throws Exception {
+ TEST_UTIL.startMiniCluster(2);
+
+ int numRegions = 100;
+ int regionsPerRs = numRegions / 2;
+ TableName tableName = createTable("testDryRunBalancer", numRegions);
+ HMaster master = Mockito.spy(TEST_UTIL.getHBaseCluster().getMaster());
+
+ // dry run should be possible with balancer disabled
+ // disabling it will ensure the chore does not mess with our forced unbalance below
+ master.balanceSwitch(false);
+ assertFalse(master.isBalancerOn());
+
+ HRegionServer biasedServer = unbalance(master, tableName);
+
+ BalanceResponse response = master.balance(BalanceRequest.newBuilder().setDryRun(true).build());
+ assertTrue(response.isBalancerRan());
+ // we don't know for sure that it will be exactly half the regions
+ assertTrue(
+ response.getMovesCalculated() >= (regionsPerRs - 1)
+ && response.getMovesCalculated() <= (regionsPerRs + 1));
+ // but we expect no moves executed due to dry run
+ assertEquals(0, response.getMovesExecuted());
+
+ // sanity check that we truly don't try to execute any plans
+ Mockito.verify(master, Mockito.never()).executeRegionPlansWithThrottling(Mockito.anyList());
+
+ // should still be unbalanced post dry run
+ assertServerContainsAllRegions(biasedServer.getServerName(), tableName);
+
+ TEST_UTIL.deleteTable(tableName);
+ }
+
+ private TableName createTable(String table, int numRegions) throws IOException {
+ TableName tableName = TableName.valueOf(table);
+ TEST_UTIL.createMultiRegionTable(tableName, FAMILYNAME, numRegions);
+ return tableName;
+ }
+
+
+ private HRegionServer unbalance(HMaster master, TableName tableName) throws Exception {
+ waitForRegionsToSettle(master);
+
+ HRegionServer biasedServer = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
+
+ for (RegionInfo regionInfo : TEST_UTIL.getAdmin().getRegions(tableName)) {
+ master.move(regionInfo.getEncodedNameAsBytes(),
+ Bytes.toBytes(biasedServer.getServerName().getServerName()));
+ }
+
+ waitForRegionsToSettle(master);
+
+ assertServerContainsAllRegions(biasedServer.getServerName(), tableName);
+
+ return biasedServer;
+ }
+
+ private void assertServerContainsAllRegions(ServerName serverName, TableName tableName)
+ throws IOException {
+ int numRegions = TEST_UTIL.getAdmin().getRegions(tableName).size();
+ assertEquals(numRegions,
+ TEST_UTIL.getMiniHBaseCluster().getRegionServer(serverName).getRegions(tableName).size());
+ }
+
+ private void waitForRegionsToSettle(HMaster master) {
+ Waiter.waitFor(TEST_UTIL.getConfiguration(), 60_000,
+ () -> master.getAssignmentManager().getRegionStates().getRegionsInTransitionCount() <= 0);
+ }
+}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedurePriority.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedurePriority.java
index f1b7d57..49c7d28 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedurePriority.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestProcedurePriority.java
@@ -30,6 +30,7 @@ import org.apache.hadoop.hbase.HBaseTestingUtil;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter.ExplainingPredicate;
import org.apache.hadoop.hbase.client.AsyncAdmin;
+import org.apache.hadoop.hbase.client.BalanceRequest;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Get;
@@ -126,7 +127,7 @@ public class TestProcedurePriority {
for (Future<?> future : futures) {
future.get(3, TimeUnit.MINUTES);
}
- UTIL.getAdmin().balance(true);
+ UTIL.getAdmin().balance(BalanceRequest.newBuilder().setIgnoreRegionsInTransition(true).build());
UTIL.waitUntilNoRegionsInTransition();
}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBalance.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBalance.java
index 5137b35..12b8378 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBalance.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBalance.java
@@ -30,6 +30,8 @@ import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.Waiter.Predicate;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.client.TableDescriptor;
@@ -79,12 +81,65 @@ public class TestRSGroupsBalance extends TestRSGroupsBase {
@Test
public void testGroupBalance() throws Exception {
- LOG.info(name.getMethodName());
- String newGroupName = getGroupName(name.getMethodName());
+ String methodName = name.getMethodName();
+
+ LOG.info(methodName);
+ String newGroupName = getGroupName(methodName);
+ TableName tableName = TableName.valueOf(TABLE_PREFIX + "_ns", methodName);
+
+ ServerName first = setupBalanceTest(newGroupName, tableName);
+
+ // balance the other group and make sure it doesn't affect the new group
+ ADMIN.balancerSwitch(true, true);
+ ADMIN.balanceRSGroup(RSGroupInfo.DEFAULT_GROUP);
+ assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
+
+ // disable balance, balancer will not be run and return false
+ ADMIN.balancerSwitch(false, true);
+ assertFalse(ADMIN.balanceRSGroup(newGroupName).isBalancerRan());
+ assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
+
+ // enable balance
+ ADMIN.balancerSwitch(true, true);
+ ADMIN.balanceRSGroup(newGroupName);
+ TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+ @Override
+ public boolean evaluate() throws Exception {
+ for (List<String> regions : getTableServerRegionMap().get(tableName).values()) {
+ if (2 != regions.size()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+ ADMIN.balancerSwitch(false, true);
+ }
+
+ @Test
+ public void testGroupDryRunBalance() throws Exception {
+ String methodName = name.getMethodName();
+
+ LOG.info(methodName);
+ String newGroupName = getGroupName(methodName);
+ final TableName tableName = TableName.valueOf(TABLE_PREFIX + "_ns", methodName);
+
+ ServerName first = setupBalanceTest(newGroupName, tableName);
+
+ // run the balancer in dry run mode. it should return true, but should not actually move any regions
+ ADMIN.balancerSwitch(true, true);
+ BalanceResponse response = ADMIN.balanceRSGroup(newGroupName,
+ BalanceRequest.newBuilder().setDryRun(true).build());
+ assertTrue(response.isBalancerRan());
+ assertTrue(response.getMovesCalculated() > 0);
+ assertEquals(0, response.getMovesExecuted());
+ // validate imbalance still exists.
+ assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
+ }
+
+ private ServerName setupBalanceTest(String newGroupName, TableName tableName) throws Exception {
addGroup(newGroupName, 3);
- final TableName tableName =
- TableName.valueOf(TABLE_PREFIX + "_ns", getNameWithoutIndex(name.getMethodName()));
ADMIN.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString())
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, newGroupName).build());
final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
@@ -126,31 +181,7 @@ public class TestRSGroupsBalance extends TestRSGroupsBase {
}
});
- // balance the other group and make sure it doesn't affect the new group
- ADMIN.balancerSwitch(true, true);
- ADMIN.balanceRSGroup(RSGroupInfo.DEFAULT_GROUP);
- assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
-
- // disable balance, balancer will not be run and return false
- ADMIN.balancerSwitch(false, true);
- assertFalse(ADMIN.balanceRSGroup(newGroupName));
- assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
-
- // enable balance
- ADMIN.balancerSwitch(true, true);
- ADMIN.balanceRSGroup(newGroupName);
- TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
- @Override
- public boolean evaluate() throws Exception {
- for (List<String> regions : getTableServerRegionMap().get(tableName).values()) {
- if (2 != regions.size()) {
- return false;
- }
- }
- return true;
- }
- });
- ADMIN.balancerSwitch(false, true);
+ return first;
}
@Test
@@ -168,7 +199,7 @@ public class TestRSGroupsBalance extends TestRSGroupsBase {
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, rsGroupInfo.getName()).build());
ADMIN.balancerSwitch(true, true);
- assertTrue(ADMIN.balanceRSGroup(rsGroupInfo.getName()));
+ assertTrue(ADMIN.balanceRSGroup(rsGroupInfo.getName()).isBalancerRan());
ADMIN.balancerSwitch(false, true);
assertTrue(OBSERVER.preBalanceRSGroupCalled);
assertTrue(OBSERVER.postBalanceRSGroupCalled);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
index 418aaf9..10bd386 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
@@ -43,6 +43,8 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.client.AbstractTestUpdateConfiguration;
import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
@@ -453,13 +455,13 @@ public abstract class TestRSGroupsBase extends AbstractTestUpdateConfiguration {
@Override
public void preBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
- String groupName) throws IOException {
+ String groupName, BalanceRequest request) throws IOException {
preBalanceRSGroupCalled = true;
}
@Override
public void postBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
- String groupName, boolean balancerRan) throws IOException {
+ String groupName, BalanceRequest request, BalanceResponse response) throws IOException {
postBalanceRSGroupCalled = true;
}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsFallback.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsFallback.java
index 4478d37..9b78d4c 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsFallback.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsFallback.java
@@ -106,7 +106,7 @@ public class TestRSGroupsFallback extends TestRSGroupsBase {
// add a new server to default group, regions move to default group
TEST_UTIL.getMiniHBaseCluster().startRegionServerAndWait(60000);
- assertTrue(MASTER.balance());
+ assertTrue(MASTER.balance().isBalancerRan());
assertRegionsInGroup(tableName, RSGroupInfo.DEFAULT_GROUP);
// add a new server to test group, regions move back
@@ -114,7 +114,7 @@ public class TestRSGroupsFallback extends TestRSGroupsBase {
TEST_UTIL.getMiniHBaseCluster().startRegionServerAndWait(60000);
ADMIN.moveServersToRSGroup(
Collections.singleton(t.getRegionServer().getServerName().getAddress()), groupName);
- assertTrue(MASTER.balance());
+ assertTrue(MASTER.balance().isBalancerRan());
assertRegionsInGroup(tableName, groupName);
TEST_UTIL.deleteTable(tableName);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java
index 57b87e5..c5911f2 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdmin.java
@@ -44,6 +44,8 @@ import org.apache.hadoop.hbase.TableExistsException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.BalanceRequest;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.CompactType;
import org.apache.hadoop.hbase.client.CompactionState;
@@ -329,12 +331,8 @@ public class VerifyingRSGroupAdmin implements Admin, Closeable {
return admin.balancerSwitch(onOrOff, synchronous);
}
- public boolean balance() throws IOException {
- return admin.balance();
- }
-
- public boolean balance(boolean force) throws IOException {
- return admin.balance(force);
+ public BalanceResponse balance(BalanceRequest request) throws IOException {
+ return admin.balance(request);
}
public boolean isBalancerEnabled() throws IOException {
@@ -829,8 +827,8 @@ public class VerifyingRSGroupAdmin implements Admin, Closeable {
verify();
}
- public boolean balanceRSGroup(String groupName) throws IOException {
- return admin.balanceRSGroup(groupName);
+ public BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) throws IOException {
+ return admin.balanceRSGroup(groupName, request);
}
@Override
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
index 5f2c6ac..721497a 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
@@ -24,7 +24,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-
import java.io.IOException;
import java.security.PrivilegedAction;
import java.util.ArrayList;
@@ -34,7 +33,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.fs.FileStatus;
@@ -56,6 +54,7 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Append;
+import org.apache.hadoop.hbase.client.BalanceRequest;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Connection;
@@ -130,13 +129,11 @@ import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.apache.hbase.thirdparty.com.google.protobuf.BlockingRpcChannel;
import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
import org.apache.hbase.thirdparty.com.google.protobuf.Service;
import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
-
import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.CountRequest;
import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.CountResponse;
import org.apache.hadoop.hbase.shaded.coprocessor.protobuf.generated.PingProtos.HelloRequest;
@@ -789,7 +786,8 @@ public class TestAccessController extends SecureTestUtil {
AccessTestAction action = new AccessTestAction() {
@Override
public Object run() throws Exception {
- ACCESS_CONTROLLER.preBalance(ObserverContextImpl.createAndPrepare(CP_ENV));
+ ACCESS_CONTROLLER.preBalance(ObserverContextImpl.createAndPrepare(CP_ENV),
+ BalanceRequest.defaultInstance());
return null;
}
};
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java
index 2b50ea4..749b3de 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java
@@ -18,7 +18,6 @@
package org.apache.hadoop.hbase.security.access;
import static org.junit.Assert.assertEquals;
-
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
@@ -33,6 +32,7 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNameTestRule;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.Append;
+import org.apache.hadoop.hbase.client.BalanceRequest;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
@@ -78,7 +78,6 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
@Category({SecurityTests.class, LargeTests.class})
@@ -574,7 +573,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil {
verifyAllowed(new AccessTestAction() {
@Override
public Object run() throws Exception {
- ACCESS_CONTROLLER.preBalance(ObserverContextImpl.createAndPrepare(CP_ENV));
+ ACCESS_CONTROLLER.preBalance(ObserverContextImpl.createAndPrepare(CP_ENV),
+ BalanceRequest.defaultInstance());
return null;
}
}, SUPERUSER, USER_ADMIN, USER_RW, USER_RO, USER_OWNER, USER_CREATE, USER_QUAL, USER_NONE);
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb
index ee9a449..0d02dba 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -30,6 +30,8 @@ java_import org.apache.hadoop.hbase.client.CoprocessorDescriptorBuilder
java_import org.apache.hadoop.hbase.client.TableDescriptorBuilder
java_import org.apache.hadoop.hbase.HConstants
+require 'hbase/balancer_utils'
+
# Wrapper for org.apache.hadoop.hbase.client.HBaseAdmin
module Hbase
@@ -230,9 +232,10 @@ module Hbase
#----------------------------------------------------------------------------------------------
# Requests a cluster balance
- # Returns true if balancer ran
- def balancer(force)
- @admin.balance(java.lang.Boolean.valueOf(force))
+ # Returns BalanceResponse with details of the balancer run
+ def balancer(*args)
+ request = ::Hbase::BalancerUtils.create_balance_request(args)
+ @admin.balance(request)
end
#----------------------------------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/hbase/balancer_utils.rb b/hbase-shell/src/main/ruby/hbase/balancer_utils.rb
new file mode 100644
index 0000000..9948c0f
--- /dev/null
+++ b/hbase-shell/src/main/ruby/hbase/balancer_utils.rb
@@ -0,0 +1,57 @@
+#
+#
+# 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.
+#
+
+include Java
+
+java_import org.apache.hadoop.hbase.client.BalanceRequest
+
+module Hbase
+ class BalancerUtils
+ def self.create_balance_request(args)
+ args = args.first if args.first.is_a?(Array) and args.size == 1
+ if args.nil? or args.empty?
+ return BalanceRequest.defaultInstance()
+ elsif args.size > 2
+ raise ArgumentError, "Illegal arguments #{args}. Expected between 0 and 2 arguments, but got #{args.size}."
+ end
+
+ builder = BalanceRequest.newBuilder()
+
+ index = 0
+ args.each do |arg|
+ if !arg.is_a?(String)
+ raise ArgumentError, "Illegal argument in index #{index}: #{arg}. All arguments must be strings, but got #{arg.class}."
+ end
+
+ case arg
+ when 'force', 'ignore_rit'
+ builder.setIgnoreRegionsInTransition(true)
+ when 'dry_run'
+ builder.setDryRun(true)
+ else
+ raise ArgumentError, "Illegal argument in index #{index}: #{arg}. Unknown option #{arg}, expected 'force', 'ignore_rit', or 'dry_run'."
+ end
+
+ index += 1
+ end
+
+ return builder.build()
+ end
+ end
+end
diff --git a/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb b/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb
index dfffb56..074ef45 100644
--- a/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb
@@ -18,6 +18,8 @@
include Java
java_import org.apache.hadoop.hbase.util.Pair
+require 'hbase/balancer_utils'
+
# Wrapper for org.apache.hadoop.hbase.group.GroupAdminClient
# Which is an API to manage region server groups
@@ -60,8 +62,9 @@ module Hbase
#--------------------------------------------------------------------------
# balance a group
- def balance_rs_group(group_name)
- @admin.balanceRSGroup(group_name)
+ def balance_rs_group(group_name, *args)
+ request = ::Hbase::BalancerUtils.create_balance_request(args)
+ @admin.balanceRSGroup(group_name, request)
end
#--------------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/shell/commands/balance_rsgroup.rb b/hbase-shell/src/main/ruby/shell/commands/balance_rsgroup.rb
index a223e05..aff9fa7 100644
--- a/hbase-shell/src/main/ruby/shell/commands/balance_rsgroup.rb
+++ b/hbase-shell/src/main/ruby/shell/commands/balance_rsgroup.rb
@@ -22,22 +22,32 @@ module Shell
<<-EOF
Balance a RegionServer group
+Parameter can be "force" or "dry_run":
+ - "dry_run" will run the balancer to generate a plan, but will not actually execute that plan.
+ This is useful for testing out new balance configurations. See the active HMaster logs for the results of the dry_run.
+ - "ignore_rit" tells master whether we should force the balancer to run even if there is region in transition.
+ WARNING: For experts only. Forcing a balance may do more damage than repair when assignment is confused
+
Example:
hbase> balance_rsgroup 'my_group'
+ hbase> balance_rsgroup 'my_group', 'ignore_rit'
+ hbase> balance_rsgroup 'my_group', 'dry_run'
+ hbase> balance_rsgroup 'my_group', 'dry_run', 'ignore_rit'
EOF
end
- def command(group_name)
+ def command(group_name, *args)
# Returns true if balancer was run, otherwise false.
- ret = rsgroup_admin.balance_rs_group(group_name)
- if ret
- puts 'Ran the balancer.'
+ resp = rsgroup_admin.balance_rs_group(group_name, args)
+ if resp.isBalancerRan
+ formatter.row(["Balancer ran"])
+ formatter.row(["Moves calculated: #{resp.getMovesCalculated}, moves executed: #{resp.getMovesExecuted}"])
else
- puts "Couldn't run the balancer."
+ formatter.row(["Balancer did not run. See logs for details."])
end
- ret
+ resp.isBalancerRan
end
end
end
diff --git a/hbase-shell/src/main/ruby/shell/commands/balancer.rb b/hbase-shell/src/main/ruby/shell/commands/balancer.rb
index c4acdc0..d5304e0 100644
--- a/hbase-shell/src/main/ruby/shell/commands/balancer.rb
+++ b/hbase-shell/src/main/ruby/shell/commands/balancer.rb
@@ -22,31 +22,32 @@ module Shell
class Balancer < Command
def help
<<-EOF
-Trigger the cluster balancer. Returns true if balancer ran and was able to
-tell the region servers to unassign all the regions to balance (the re-assignment itself is async).
-Otherwise false (Will not run if regions in transition).
-Parameter tells master whether we should force balance even if there is region in transition.
+Trigger the cluster balancer. Returns true if balancer ran, otherwise false (Will not run if regions in transition).
-WARNING: For experts only. Forcing a balance may do more damage than repair
-when assignment is confused
+Parameter can be "force" or "dry_run":
+ - "dry_run" will run the balancer to generate a plan, but will not actually execute that plan.
+ This is useful for testing out new balance configurations. See the active HMaster logs for the results of the dry_run.
+ - "ignore_rit" tells master whether we should force the balancer to run even if there is region in transition.
+ WARNING: For experts only. Forcing a balance may do more damage than repair when assignment is confused
Examples:
hbase> balancer
- hbase> balancer "force"
+ hbase> balancer "ignore_rit"
+ hbase> balancer "dry_run"
+ hbase> balancer "dry_run", "ignore_rit"
EOF
end
- def command(force = nil)
- force_balancer = 'false'
- if force == 'force'
- force_balancer = 'true'
- elsif !force.nil?
- raise ArgumentError, "Invalid argument #{force}."
+ def command(*args)
+ resp = admin.balancer(args)
+ if resp.isBalancerRan
+ formatter.row(["Balancer ran"])
+ formatter.row(["Moves calculated: #{resp.getMovesCalculated}, moves executed: #{resp.getMovesExecuted}"])
+ else
+ formatter.row(["Balancer did not run. See logs for details."])
end
- did_balancer_run = !!admin.balancer(force_balancer)
- formatter.row([did_balancer_run.to_s])
- did_balancer_run
+ resp.isBalancerRan
end
end
end
diff --git a/hbase-shell/src/test/ruby/hbase/admin_test.rb b/hbase-shell/src/test/ruby/hbase/admin_test.rb
index 9e7096d..957c018 100644
--- a/hbase-shell/src/test/ruby/hbase/admin_test.rb
+++ b/hbase-shell/src/test/ruby/hbase/admin_test.rb
@@ -202,7 +202,13 @@ module Hbase
did_balancer_run = command(:balancer)
assert(did_balancer_run == true)
output = capture_stdout { command(:balancer, 'force') }
- assert(output.include?('true'))
+ assert(output.include?('Balancer ran'))
+
+ command(:balance_switch, false)
+ output = capture_stdout { command(:balancer) }
+ assert(output.include?('Balancer did not run'))
+ output = capture_stdout { command(:balancer, 'dry_run') }
+ assert(output.include?('Balancer ran'))
end
#-------------------------------------------------------------------------------
diff --git a/hbase-shell/src/test/ruby/hbase/balancer_utils_test.rb b/hbase-shell/src/test/ruby/hbase/balancer_utils_test.rb
new file mode 100644
index 0000000..9d70540
--- /dev/null
+++ b/hbase-shell/src/test/ruby/hbase/balancer_utils_test.rb
@@ -0,0 +1,78 @@
+#
+#
+# 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.
+#
+
+java_import org.apache.hadoop.hbase.client.BalanceRequest
+
+module Hbase
+ class BalancerUtilsTest < Test::Unit::TestCase
+ include TestHelpers
+
+ def create_balance_request(*args)
+ ::Hbase::BalancerUtils.create_balance_request(args)
+ end
+
+ define_test "should raise ArgumentError on unknown string argument" do
+ assert_raise(ArgumentError) do
+ request = create_balance_request('foo')
+ end
+ end
+
+ define_test "should raise ArgumentError on non-array argument" do
+ assert_raise(ArgumentError) do
+ request = create_balance_request({foo: 'bar' })
+ end
+ end
+
+ define_test "should raise ArgumentError on non-string array item" do
+ assert_raise(ArgumentError) do
+ request = create_balance_request('force', true)
+ end
+ end
+
+ define_test "should parse empty args" do
+ request = create_balance_request()
+ assert(!request.isDryRun())
+ assert(!request.isIgnoreRegionsInTransition())
+ end
+
+ define_test "should parse 'force' string" do
+ request = create_balance_request('force')
+ assert(!request.isDryRun())
+ assert(request.isIgnoreRegionsInTransition())
+ end
+
+ define_test "should parse 'ignore_rit' string" do
+ request = create_balance_request('ignore_rit')
+ assert(!request.isDryRun())
+ assert(request.isIgnoreRegionsInTransition())
+ end
+
+ define_test "should parse 'dry_run' string" do
+ request = create_balance_request('dry_run')
+ assert(request.isDryRun())
+ assert(!request.isIgnoreRegionsInTransition())
+ end
+
+ define_test "should parse multiple string args" do
+ request = create_balance_request('dry_run', 'ignore_rit')
+ assert(request.isDryRun())
+ assert(request.isIgnoreRegionsInTransition())
+ end
+ end
+end
diff --git a/hbase-shell/src/test/ruby/shell/rsgroup_shell_test.rb b/hbase-shell/src/test/ruby/shell/rsgroup_shell_test.rb
index f93d364..56b6a8e 100644
--- a/hbase-shell/src/test/ruby/shell/rsgroup_shell_test.rb
+++ b/hbase-shell/src/test/ruby/shell/rsgroup_shell_test.rb
@@ -89,6 +89,8 @@ module Hbase
# just run it to verify jruby->java api binding
@hbase.rsgroup_admin.balance_rs_group(group_name)
+ @hbase.rsgroup_admin.balance_rs_group(group_name, 'force')
+ @hbase.rsgroup_admin.balance_rs_group(group_name, 'dry_run')
@shell.command(:disable, table_name)
@shell.command(:drop, table_name)
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
index 86f4268..2b54525 100644
--- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
@@ -27,6 +27,7 @@ import java.util.concurrent.Future;
import java.util.regex.Pattern;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.client.BalanceRequest;
import org.apache.hadoop.hbase.CacheEvictionStats;
import org.apache.hadoop.hbase.ClusterMetrics;
import org.apache.hadoop.hbase.HConstants;
@@ -38,6 +39,7 @@ import org.apache.hadoop.hbase.TableExistsException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.BalanceResponse;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.CompactType;
import org.apache.hadoop.hbase.client.CompactionState;
@@ -630,6 +632,11 @@ public class ThriftAdmin implements Admin {
}
@Override
+ public BalanceResponse balance(BalanceRequest request) throws IOException {
+ throw new NotImplementedException("balance not supported in ThriftAdmin");
+ }
+
+ @Override
public boolean isBalancerEnabled() {
throw new NotImplementedException("isBalancerEnabled not supported in ThriftAdmin");
}
@@ -1228,7 +1235,7 @@ public class ThriftAdmin implements Admin {
}
@Override
- public boolean balanceRSGroup(String groupName) {
+ public BalanceResponse balanceRSGroup(String groupName, BalanceRequest request) {
throw new NotImplementedException("balanceRSGroup not supported in ThriftAdmin");
}