You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by vj...@apache.org on 2020/06/27 19:42:12 UTC
[hbase] branch branch-2.3 updated: HBASE-24588 : Submit task for
NormalizationPlan (#1933) (#1985)
This is an automated email from the ASF dual-hosted git repository.
vjasani pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-2.3 by this push:
new 66489bb HBASE-24588 : Submit task for NormalizationPlan (#1933) (#1985)
66489bb is described below
commit 66489bb5b09ceab5ba86e5f06f29621220c23c1d
Author: Viraj Jasani <vj...@apache.org>
AuthorDate: Sun Jun 28 01:12:00 2020 +0530
HBASE-24588 : Submit task for NormalizationPlan (#1933) (#1985)
Signed-off-by: Nick Dimiduk <nd...@apache.org>
---
.../java/org/apache/hadoop/hbase/client/Admin.java | 3 +
.../hadoop/hbase/client/RawAsyncHBaseAdmin.java | 12 ++--
.../org/apache/hadoop/hbase/master/HMaster.java | 72 ++++++++++++----------
.../master/normalizer/EmptyNormalizationPlan.java | 54 ----------------
.../master/normalizer/MergeNormalizationPlan.java | 33 +++++-----
.../hbase/master/normalizer/NormalizationPlan.java | 12 ++--
.../master/normalizer/SplitNormalizationPlan.java | 24 ++++----
.../TestSimpleRegionNormalizerOnCluster.java | 46 +++++++++++---
8 files changed, 120 insertions(+), 136 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 7311055..d34f56f 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
@@ -1269,6 +1269,9 @@ public interface Admin extends Abortable, Closeable {
/**
* Invoke region normalizer. Can NOT run for various reasons. Check logs.
+ * This is a non-blocking invocation to region normalizer. If return value is true, it means
+ * the request was submitted successfully. We need to check logs for the details of which regions
+ * were split/merged.
*
* @return <code>true</code> if region normalizer ran, <code>false</code> otherwise.
* @throws IOException if a remote or network exception occurs
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 9792c9f..023e8fc 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
@@ -1284,7 +1284,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
return;
}
- MergeTableRegionsRequest request = null;
+ final MergeTableRegionsRequest request;
try {
request = RequestConverter.buildMergeTableRegionsRequest(encodedNameOfRegionsToMerge,
forcible, ng.getNonceGroup(), ng.newNonce());
@@ -1294,8 +1294,8 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
}
addListener(
- this.<MergeTableRegionsRequest, MergeTableRegionsResponse> procedureCall(tableName, request,
- (s, c, req, done) -> s.mergeTableRegions(c, req, done), (resp) -> resp.getProcId(),
+ this.procedureCall(tableName, request,
+ MasterService.Interface::mergeTableRegions, MergeTableRegionsResponse::getProcId,
new MergeTableRegionProcedureBiConsumer(tableName)),
(ret, err2) -> {
if (err2 != null) {
@@ -1470,7 +1470,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
private CompletableFuture<Void> split(final RegionInfo hri, byte[] splitPoint) {
CompletableFuture<Void> future = new CompletableFuture<>();
TableName tableName = hri.getTable();
- SplitTableRegionRequest request = null;
+ final SplitTableRegionRequest request;
try {
request = RequestConverter.buildSplitTableRegionRequest(hri, splitPoint, ng.getNonceGroup(),
ng.newNonce());
@@ -1480,8 +1480,8 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
}
addListener(
- this.<SplitTableRegionRequest, SplitTableRegionResponse> procedureCall(tableName,
- request, (s, c, req, done) -> s.splitRegion(c, req, done), (resp) -> resp.getProcId(),
+ this.procedureCall(tableName,
+ request, MasterService.Interface::splitRegion, SplitTableRegionResponse::getProcId,
new SplitTableRegionProcedureBiConsumer(tableName)),
(ret, err2) -> {
if (err2 != null) {
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 211f157..54d0b4e 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
@@ -1904,44 +1904,50 @@ public class HMaster extends HRegionServer implements MasterServices {
}
try {
- final List<TableName> allEnabledTables = new ArrayList<>(
- tableStateManager.getTablesInStates(TableState.State.ENABLED));
+ final List<TableName> allEnabledTables =
+ new ArrayList<>(tableStateManager.getTablesInStates(TableState.State.ENABLED));
Collections.shuffle(allEnabledTables);
- try (final Admin admin = clusterConnection.getAdmin()) {
- for (TableName table : allEnabledTables) {
- if (table.isSystemTable()) {
- continue;
- }
- final TableDescriptor tblDesc = getTableDescriptors().get(table);
- if (tblDesc != null && !tblDesc.isNormalizationEnabled()) {
- LOG.debug("Skipping table {} because normalization is disabled in its"
- + " table properties.", table);
- continue;
- }
+ final List<Long> submittedPlanProcIds = new ArrayList<>();
+ for (TableName table : allEnabledTables) {
+ if (table.isSystemTable()) {
+ continue;
+ }
+ final TableDescriptor tblDesc = getTableDescriptors().get(table);
+ if (tblDesc != null && !tblDesc.isNormalizationEnabled()) {
+ LOG.debug(
+ "Skipping table {} because normalization is disabled in its table properties.", table);
+ continue;
+ }
- // make one last check that the cluster isn't shutting down before proceeding.
- if (skipRegionManagementAction("region normalizer")) {
- return false;
- }
+ // make one last check that the cluster isn't shutting down before proceeding.
+ if (skipRegionManagementAction("region normalizer")) {
+ return false;
+ }
- final List<NormalizationPlan> plans = normalizer.computePlansForTable(table);
- if (CollectionUtils.isEmpty(plans)) {
- LOG.debug("No normalization required for table {}.", table);
- continue;
- }
+ final List<NormalizationPlan> plans = normalizer.computePlansForTable(table);
+ if (CollectionUtils.isEmpty(plans)) {
+ LOG.debug("No normalization required for table {}.", table);
+ continue;
+ }
- // as of this writing, `plan.execute()` is non-blocking, so there's no artificial rate-
- // limiting of merge requests due to this serial loop.
- for (NormalizationPlan plan : plans) {
- plan.execute(admin);
- if (plan.getType() == PlanType.SPLIT) {
- splitPlanCount++;
- } else if (plan.getType() == PlanType.MERGE) {
- mergePlanCount++;
- }
+ // as of this writing, `plan.submit()` is non-blocking and uses Async Admin APIs to
+ // submit task , so there's no artificial rate-
+ // limiting of merge/split requests due to this serial loop.
+ for (NormalizationPlan plan : plans) {
+ long procId = plan.submit(this);
+ submittedPlanProcIds.add(procId);
+ if (plan.getType() == PlanType.SPLIT) {
+ splitPlanCount++;
+ } else if (plan.getType() == PlanType.MERGE) {
+ mergePlanCount++;
}
}
+ int totalPlansSubmitted = submittedPlanProcIds.size();
+ if (totalPlansSubmitted > 0 && LOG.isDebugEnabled()) {
+ LOG.debug("Normalizer plans submitted. Total plans count: {} , procID list: {}",
+ totalPlansSubmitted, submittedPlanProcIds);
+ }
}
} finally {
normalizationInProgressLock.unlock();
@@ -1983,8 +1989,8 @@ public class HMaster extends HRegionServer implements MasterServices {
" failed because merge switch is off");
}
- final String mergeRegionsStr = Arrays.stream(regionsToMerge).map(r -> r.getEncodedName()).
- collect(Collectors.joining(", "));
+ final String mergeRegionsStr = Arrays.stream(regionsToMerge).map(RegionInfo::getEncodedName)
+ .collect(Collectors.joining(", "));
return MasterProcedureUtil.submitProcedure(new NonceProcedureRunnable(this, ng, nonce) {
@Override
protected void run() throws IOException {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java
deleted file mode 100644
index a199838..0000000
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- *
- * 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.normalizer;
-
-import org.apache.yetus.audience.InterfaceAudience;
-import org.apache.hadoop.hbase.client.Admin;
-import org.apache.hadoop.hbase.master.normalizer.NormalizationPlan.PlanType;
-
-/**
- * Plan which signifies that no normalization is required,
- * or normalization of this table isn't allowed, this is singleton.
- */
-@InterfaceAudience.Private
-public final class EmptyNormalizationPlan implements NormalizationPlan {
- private static final EmptyNormalizationPlan instance = new EmptyNormalizationPlan();
-
- private EmptyNormalizationPlan() {
- }
-
- /**
- * @return singleton instance
- */
- public static EmptyNormalizationPlan getInstance(){
- return instance;
- }
-
- /**
- * No-op for empty plan.
- */
- @Override
- public void execute(Admin admin) {
- }
-
- @Override
- public PlanType getType() {
- return PlanType.NONE;
- }
-}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java
index a2938a9..8f8a43f 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java
@@ -20,8 +20,9 @@ package org.apache.hadoop.hbase.master.normalizer;
import java.io.IOException;
-import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,6 +42,20 @@ public class MergeNormalizationPlan implements NormalizationPlan {
this.secondRegion = secondRegion;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long submit(MasterServices masterServices) throws IOException {
+ LOG.info("Executing merging normalization plan: " + this);
+ // Do not use force=true as corner cases can happen, non adjacent regions,
+ // merge with a merged child region with no GC done yet, it is going to
+ // cause all different issues.
+ return masterServices
+ .mergeRegions(new RegionInfo[] { firstRegion, secondRegion }, false, HConstants.NO_NONCE,
+ HConstants.NO_NONCE);
+ }
+
@Override
public PlanType getType() {
return PlanType.MERGE;
@@ -62,20 +77,4 @@ public class MergeNormalizationPlan implements NormalizationPlan {
'}';
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void execute(Admin admin) {
- LOG.info("Executing merging normalization plan: " + this);
- try {
- // Do not use force=true as corner cases can happen, non adjacent regions,
- // merge with a merged child region with no GC done yet, it is going to
- // cause all different issues.
- admin.mergeRegionsAsync(firstRegion.getEncodedNameAsBytes(),
- secondRegion.getEncodedNameAsBytes(), false);
- } catch (IOException ex) {
- LOG.error("Error during region merge: ", ex);
- }
- }
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java
index b0541d0..cd13f69 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java
@@ -18,8 +18,9 @@
*/
package org.apache.hadoop.hbase.master.normalizer;
+import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.yetus.audience.InterfaceAudience;
-import org.apache.hadoop.hbase.client.Admin;
+import java.io.IOException;
/**
* Interface for normalization plan.
@@ -33,10 +34,13 @@ public interface NormalizationPlan {
}
/**
- * Executes normalization plan on cluster (does actual splitting/merging work).
- * @param admin instance of Admin
+ * Submits normalization plan on cluster (does actual splitting/merging work) and
+ * returns proc Id to caller.
+ * @param masterServices instance of {@link MasterServices}
+ * @return Proc Id for the submitted task
+ * @throws IOException If plan submission to Admin fails
*/
- void execute(Admin admin);
+ long submit(MasterServices masterServices) throws IOException;
/**
* @return the type of this plan
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java
index 04e11d1..67008b8 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java
@@ -18,9 +18,11 @@
*/
package org.apache.hadoop.hbase.master.normalizer;
+import java.io.IOException;
import java.util.Arrays;
-import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,6 +42,14 @@ public class SplitNormalizationPlan implements NormalizationPlan {
this.splitPoint = splitPoint;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long submit(MasterServices masterServices) throws IOException {
+ return masterServices.splitRegion(regionInfo, null, HConstants.NO_NONCE, HConstants.NO_NONCE);
+ }
+
@Override
public PlanType getType() {
return PlanType.SPLIT;
@@ -69,16 +79,4 @@ public class SplitNormalizationPlan implements NormalizationPlan {
'}';
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void execute(Admin admin) {
- LOG.info("Executing splitting normalization plan: " + this);
- try {
- admin.splitRegionAsync(regionInfo.getRegionName()).get();
- } catch (Exception ex) {
- LOG.error("Error during region split: ", ex);
- }
- }
}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java
index fdaaab0..da4c52e 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java
@@ -130,15 +130,23 @@ public class TestSimpleRegionNormalizerOnCluster {
public void testHonorsNormalizerTableSetting() throws Exception {
final TableName tn1 = TableName.valueOf(name.getMethodName() + "1");
final TableName tn2 = TableName.valueOf(name.getMethodName() + "2");
+ final TableName tn3 = TableName.valueOf(name.getMethodName() + "3");
try {
- final int tn1RegionCount = createTableBegsSplit(tn1, true);
- final int tn2RegionCount = createTableBegsSplit(tn2, false);
+ final int tn1RegionCount = createTableBegsSplit(tn1, true, false);
+ final int tn2RegionCount = createTableBegsSplit(tn2, false, false);
+ final int tn3RegionCount = createTableBegsSplit(tn3, true, true);
assertFalse(admin.normalizerSwitch(true));
assertTrue(admin.normalize());
waitForTableSplit(tn1, tn1RegionCount + 1);
+ // confirm that tn1 has (tn1RegionCount + 1) number of regions.
+ // tn2 has tn2RegionCount number of regions because normalizer has not been enabled on it.
+ // tn3 has tn3RegionCount number of regions because two plans are run:
+ // 1. split one region to two
+ // 2. merge two regions into one
+ // and hence, total number of regions for tn3 remains same
assertEquals(
tn1 + " should have split.",
tn1RegionCount + 1,
@@ -147,9 +155,11 @@ public class TestSimpleRegionNormalizerOnCluster {
tn2 + " should not have split.",
tn2RegionCount,
MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tn2));
+ waitForTableRegionCount(tn3, tn3RegionCount);
} finally {
dropIfExists(tn1);
dropIfExists(tn2);
+ dropIfExists(tn3);
}
}
@@ -170,7 +180,7 @@ public class TestSimpleRegionNormalizerOnCluster {
? buildTableNameForQuotaTest(name.getMethodName())
: TableName.valueOf(name.getMethodName());
- final int currentRegionCount = createTableBegsSplit(tableName, true);
+ final int currentRegionCount = createTableBegsSplit(tableName, true, false);
final long existingSkippedSplitCount = master.getRegionNormalizer()
.getSkippedCount(PlanType.SPLIT);
assertFalse(admin.normalizerSwitch(true));
@@ -200,7 +210,7 @@ public class TestSimpleRegionNormalizerOnCluster {
final int currentRegionCount = createTableBegsMerge(tableName);
assertFalse(admin.normalizerSwitch(true));
assertTrue(admin.normalize());
- waitforTableMerge(tableName, currentRegionCount - 1);
+ waitForTableMerge(tableName, currentRegionCount - 1);
assertEquals(
tableName + " should have merged.",
currentRegionCount - 1,
@@ -233,8 +243,24 @@ public class TestSimpleRegionNormalizerOnCluster {
});
}
+ private static void waitForTableRegionCount(final TableName tableName,
+ final int targetRegionCount) throws IOException {
+ TEST_UTIL.waitFor(TimeUnit.MINUTES.toMillis(5), new ExplainingPredicate<IOException>() {
+ @Override
+ public String explainFailure() {
+ return "expected " + targetRegionCount + " number of regions for table " + tableName;
+ }
+ @Override
+ public boolean evaluate() throws IOException {
+ final int currentRegionCount =
+ MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tableName);
+ return currentRegionCount == targetRegionCount;
+ }
+ });
+ }
+
private static void waitForTableSplit(final TableName tableName, final int targetRegionCount)
- throws IOException {
+ throws IOException {
TEST_UTIL.waitFor(TimeUnit.MINUTES.toMillis(5), new ExplainingPredicate<IOException>() {
@Override public String explainFailure() {
return "expected normalizer to split region.";
@@ -247,8 +273,8 @@ public class TestSimpleRegionNormalizerOnCluster {
});
}
- private static void waitforTableMerge(final TableName tableName, final int targetRegionCount)
- throws IOException {
+ private static void waitForTableMerge(final TableName tableName, final int targetRegionCount)
+ throws IOException {
TEST_UTIL.waitFor(TimeUnit.MINUTES.toMillis(5), new ExplainingPredicate<IOException>() {
@Override public String explainFailure() {
return "expected normalizer to merge regions.";
@@ -319,14 +345,16 @@ public class TestSimpleRegionNormalizerOnCluster {
* <li>split threshold: 2.4 * 2 = 4.8</li>
* </ul>
*/
- private static int createTableBegsSplit(final TableName tableName, final boolean balancerEnabled)
+ private static int createTableBegsSplit(final TableName tableName,
+ final boolean normalizerEnabled, final boolean isMergeEnabled)
throws IOException {
final List<HRegion> generatedRegions = generateTestData(tableName, 1, 1, 2, 3, 5);
assertEquals(5, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tableName));
admin.flush(tableName);
final TableDescriptor td = TableDescriptorBuilder.newBuilder(admin.getDescriptor(tableName))
- .setNormalizationEnabled(balancerEnabled)
+ .setNormalizationEnabled(normalizerEnabled)
+ .setMergeEnabled(isMergeEnabled)
.build();
admin.modifyTable(td);