Skip to content

Commit 111552c

Browse files
committed
HBASE-24627 Normalize one table at a time
Introduce an additional method to our Admin interface that allow an operator to selectivly run the normalizer. The IPC protocol supports general table name select via compound filter.
1 parent d2afda3 commit 111552c

File tree

17 files changed

+410
-69
lines changed

17 files changed

+410
-69
lines changed

hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,11 +856,23 @@ void unassign(byte[] regionName, boolean force)
856856
* the request was submitted successfully. We need to check logs for the details of which regions
857857
* were split/merged.
858858
*
859-
* @return <code>true</code> if region normalizer ran, <code>false</code> otherwise.
859+
* @return {@code true} if region normalizer ran, {@code false} otherwise.
860860
* @throws IOException if a remote or network exception occurs
861861
*/
862862
boolean normalize() throws IOException;
863863

864+
/**
865+
* Invoke region normalizer. Can NOT run for various reasons. Check logs.
866+
* This is a non-blocking invocation to region normalizer. If return value is true, it means
867+
* the request was submitted successfully. We need to check logs for the details of which regions
868+
* were split/merged.
869+
*
870+
* @param ntfp limit to tables matching the specified filter.
871+
* @return {@code true} if region normalizer ran, {@code false} otherwise.
872+
* @throws IOException if a remote or network exception occurs
873+
*/
874+
boolean normalize(NormalizeTableFilterParams ntfp) throws IOException;
875+
864876
/**
865877
* Query the current state of the region normalizer.
866878
*

hbase-client/src/main/java/org/apache/hadoop/hbase/client/AdminOverAsyncAdmin.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,11 @@ public boolean normalize() throws IOException {
399399
return get(admin.normalize());
400400
}
401401

402+
@Override
403+
public boolean normalize(NormalizeTableFilterParams ntfp) throws IOException {
404+
return get(admin.normalize(ntfp));
405+
}
406+
402407
@Override
403408
public boolean isNormalizerEnabled() throws IOException {
404409
return get(admin.isNormalizerEnabled());

hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*
22
* Licensed to the Apache Software Foundation (ASF) under one
33
* or more contributor license agreements. See the NOTICE file
44
* distributed with this work for additional information
@@ -1281,6 +1281,14 @@ default CompletableFuture<Boolean> balance() {
12811281
*/
12821282
CompletableFuture<Boolean> normalize();
12831283

1284+
/**
1285+
* Invoke region normalizer. Can NOT run for various reasons. Check logs.
1286+
* @param ntfp limit to tables matching the specified filter.
1287+
* @return true if region normalizer ran, false otherwise. The return value will be wrapped by a
1288+
* {@link CompletableFuture}
1289+
*/
1290+
CompletableFuture<Boolean> normalize(NormalizeTableFilterParams ntfp);
1291+
12841292
/**
12851293
* Turn the cleaner chore on/off.
12861294
* @param on

hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*
22
* Licensed to the Apache Software Foundation (ASF) under one
33
* or more contributor license agreements. See the NOTICE file
44
* distributed with this work for additional information
@@ -713,6 +713,11 @@ public CompletableFuture<Boolean> normalize() {
713713
return wrap(rawAdmin.normalize());
714714
}
715715

716+
@Override
717+
public CompletableFuture<Boolean> normalize(NormalizeTableFilterParams ntfp) {
718+
return wrap(rawAdmin.normalize(ntfp));
719+
}
720+
716721
@Override
717722
public CompletableFuture<Boolean> cleanerChoreSwitch(boolean enabled) {
718723
return wrap(rawAdmin.cleanerChoreSwitch(enabled));
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.client;
19+
20+
import java.util.List;
21+
import org.apache.hadoop.hbase.TableName;
22+
import org.apache.yetus.audience.InterfaceAudience;
23+
import org.apache.yetus.audience.InterfaceStability;
24+
25+
/**
26+
* A collection of criteria used for table selection. The logic of table selection is as follows:
27+
* <ul>
28+
* <li>
29+
* When no parameter values are provided, an unfiltered list of all user tables is returned.
30+
* </li>
31+
* <li>
32+
* When a list of {@link TableName TableNames} are provided, the filter starts with any of
33+
* these tables that exist.
34+
* </li>
35+
* <li>
36+
* When a {@code namespace} name is provided, the filter starts with all the tables present in
37+
* that namespace.
38+
* </li>
39+
* <li>
40+
* If both a list of {@link TableName TableNames} and a {@code namespace} name are provided,
41+
* the {@link TableName} list is honored and the {@code namespace} name is ignored.
42+
* </li>
43+
* <li>
44+
* If a {@code regex} is provided, this subset of {@link TableName TableNames} is further
45+
* reduced to those that match the provided regular expression.
46+
* </li>
47+
* </ul>
48+
*/
49+
@InterfaceAudience.Public
50+
@InterfaceStability.Evolving
51+
public class NormalizeTableFilterParams {
52+
private final List<TableName> tableNames;
53+
private final String regex;
54+
private final String namespace;
55+
56+
private NormalizeTableFilterParams(final List<TableName> tableNames, final String regex,
57+
final String namespace) {
58+
this.tableNames = tableNames;
59+
this.regex = regex;
60+
this.namespace = namespace;
61+
}
62+
63+
public List<TableName> getTableNames() {
64+
return tableNames;
65+
}
66+
67+
public String getRegex() {
68+
return regex;
69+
}
70+
71+
public String getNamespace() {
72+
return namespace;
73+
}
74+
75+
/**
76+
* Used to instantiate an instance of {@link NormalizeTableFilterParams}.
77+
*/
78+
public static class Builder {
79+
private List<TableName> tableNames;
80+
private String regex;
81+
private String namespace;
82+
83+
public Builder tableFilterParams(final NormalizeTableFilterParams ntfp) {
84+
this.tableNames = ntfp.getTableNames();
85+
this.regex = ntfp.getRegex();
86+
this.namespace = ntfp.getNamespace();
87+
return this;
88+
}
89+
90+
public Builder tableNames(final List<TableName> tableNames) {
91+
this.tableNames = tableNames;
92+
return this;
93+
}
94+
95+
public Builder regex(final String regex) {
96+
this.regex = regex;
97+
return this;
98+
}
99+
100+
public Builder namespace(final String namespace) {
101+
this.namespace = namespace;
102+
return this;
103+
}
104+
105+
public NormalizeTableFilterParams build() {
106+
return new NormalizeTableFilterParams(tableNames, regex, namespace);
107+
}
108+
}
109+
}

hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,13 +3287,22 @@ public CompletableFuture<Boolean> isNormalizerEnabled() {
32873287

32883288
@Override
32893289
public CompletableFuture<Boolean> normalize() {
3290+
return normalize(RequestConverter.buildNormalizeRequest());
3291+
}
3292+
3293+
@Override
3294+
public CompletableFuture<Boolean> normalize(NormalizeTableFilterParams ntfp) {
3295+
return normalize(RequestConverter.buildNormalizeRequest(ntfp));
3296+
}
3297+
3298+
private CompletableFuture<Boolean> normalize(NormalizeRequest request) {
32903299
return this
3291-
.<Boolean> newMasterCaller()
3292-
.action(
3293-
(controller, stub) -> this.<NormalizeRequest, NormalizeResponse, Boolean> call(
3294-
controller, stub, RequestConverter.buildNormalizeRequest(),
3295-
(s, c, req, done) -> s.normalize(c, req, done), (resp) -> resp.getNormalizerRan()))
3296-
.call();
3300+
.<Boolean> newMasterCaller()
3301+
.action(
3302+
(controller, stub) -> this.call(
3303+
controller, stub, request, MasterService.Interface::normalize,
3304+
NormalizeResponse::getNormalizerRan))
3305+
.call();
32973306
}
32983307

32993308
@Override

hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,6 +2293,13 @@ public static HBaseProtos.TableName toProtoTableName(TableName tableName) {
22932293
.setQualifier(UnsafeByteOperations.unsafeWrap(tableName.getQualifier())).build();
22942294
}
22952295

2296+
public static List<HBaseProtos.TableName> toProtoTableNameList(List<TableName> tableNameList) {
2297+
if (tableNameList == null) {
2298+
return new ArrayList<>();
2299+
}
2300+
return tableNameList.stream().map(ProtobufUtil::toProtoTableName).collect(Collectors.toList());
2301+
}
2302+
22962303
public static List<TableName> toTableNameList(List<HBaseProtos.TableName> tableNamesList) {
22972304
if (tableNamesList == null) {
22982305
return new ArrayList<>();

hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*
22
* Licensed to the Apache Software Foundation (ASF) under one
33
* or more contributor license agreements. See the NOTICE file
44
* distributed with this work for additional information
@@ -46,6 +46,7 @@
4646
import org.apache.hadoop.hbase.client.LogQueryFilter;
4747
import org.apache.hadoop.hbase.client.MasterSwitchType;
4848
import org.apache.hadoop.hbase.client.Mutation;
49+
import org.apache.hadoop.hbase.client.NormalizeTableFilterParams;
4950
import org.apache.hadoop.hbase.client.Put;
5051
import org.apache.hadoop.hbase.client.RegionCoprocessorServiceExec;
5152
import org.apache.hadoop.hbase.client.RegionInfo;
@@ -1480,6 +1481,25 @@ public static NormalizeRequest buildNormalizeRequest() {
14801481
return NormalizeRequest.newBuilder().build();
14811482
}
14821483

1484+
/**
1485+
* Creates a protocol buffer NormalizeRequest
1486+
*
1487+
* @return a NormalizeRequest
1488+
*/
1489+
public static NormalizeRequest buildNormalizeRequest(NormalizeTableFilterParams ntfp) {
1490+
final NormalizeRequest.Builder builder = NormalizeRequest.newBuilder();
1491+
if (ntfp.getTableNames() != null) {
1492+
builder.addAllTableNames(ProtobufUtil.toProtoTableNameList(ntfp.getTableNames()));
1493+
}
1494+
if (ntfp.getRegex() != null) {
1495+
builder.setRegex(ntfp.getRegex());
1496+
}
1497+
if (ntfp.getNamespace() != null) {
1498+
builder.setNamespace(ntfp.getNamespace());
1499+
}
1500+
return builder.build();
1501+
}
1502+
14831503
/**
14841504
* Creates a protocol buffer IsNormalizerEnabledRequest
14851505
*

hbase-protocol-shaded/src/main/protobuf/server/master/Master.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ message IsSplitOrMergeEnabledResponse {
354354
}
355355

356356
message NormalizeRequest {
357+
repeated TableName table_names = 1;
358+
optional string regex = 2;
359+
optional string namespace = 3;
357360
}
358361

359362
message NormalizeResponse {

hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import static org.apache.hadoop.hbase.HConstants.HBASE_MASTER_LOGCLEANER_PLUGINS;
2222
import static org.apache.hadoop.hbase.HConstants.HBASE_SPLIT_WAL_COORDINATED_BY_ZK;
2323
import static org.apache.hadoop.hbase.util.DNS.MASTER_HOSTNAME_KEY;
24-
2524
import java.io.IOException;
2625
import java.io.InterruptedIOException;
2726
import java.lang.reflect.Constructor;
@@ -38,6 +37,7 @@
3837
import java.util.EnumSet;
3938
import java.util.HashMap;
4039
import java.util.Iterator;
40+
import java.util.LinkedList;
4141
import java.util.List;
4242
import java.util.Map;
4343
import java.util.Objects;
@@ -80,9 +80,9 @@
8080
import org.apache.hadoop.hbase.TableNotDisabledException;
8181
import org.apache.hadoop.hbase.TableNotFoundException;
8282
import org.apache.hadoop.hbase.UnknownRegionException;
83-
import org.apache.hadoop.hbase.client.Admin;
8483
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
8584
import org.apache.hadoop.hbase.client.MasterSwitchType;
85+
import org.apache.hadoop.hbase.client.NormalizeTableFilterParams;
8686
import org.apache.hadoop.hbase.client.RegionInfo;
8787
import org.apache.hadoop.hbase.client.RegionInfoBuilder;
8888
import org.apache.hadoop.hbase.client.RegionStatesCount;
@@ -227,14 +227,13 @@
227227
import org.eclipse.jetty.webapp.WebAppContext;
228228
import org.slf4j.Logger;
229229
import org.slf4j.LoggerFactory;
230-
231230
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
232231
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
233232
import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
233+
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
234234
import org.apache.hbase.thirdparty.com.google.protobuf.Descriptors;
235235
import org.apache.hbase.thirdparty.com.google.protobuf.Service;
236236
import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUtils;
237-
238237
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
239238
import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
240239
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.GetRegionInfoResponse.CompactionState;
@@ -1910,14 +1909,18 @@ public RegionNormalizer getRegionNormalizer() {
19101909
return this.normalizer;
19111910
}
19121911

1912+
public boolean normalizeRegions() throws IOException {
1913+
return normalizeRegions(new NormalizeTableFilterParams.Builder().build());
1914+
}
1915+
19131916
/**
1914-
* Perform normalization of cluster (invoked by {@link RegionNormalizerChore}).
1917+
* Perform normalization of cluster.
19151918
*
19161919
* @return true if an existing normalization was already in progress, or if a new normalization
19171920
* was performed successfully; false otherwise (specifically, if HMaster finished initializing
19181921
* or normalization is globally disabled).
19191922
*/
1920-
public boolean normalizeRegions() throws IOException {
1923+
public boolean normalizeRegions(final NormalizeTableFilterParams ntfp) throws IOException {
19211924
final long startTime = EnvironmentEdgeManager.currentTime();
19221925
if (regionNormalizerTracker == null || !regionNormalizerTracker.isNormalizerOn()) {
19231926
LOG.debug("Region normalization is disabled, don't run region normalizer.");
@@ -1938,12 +1941,19 @@ public boolean normalizeRegions() throws IOException {
19381941

19391942
int affectedTables = 0;
19401943
try {
1941-
final List<TableName> allEnabledTables =
1942-
new ArrayList<>(tableStateManager.getTablesInStates(TableState.State.ENABLED));
1943-
Collections.shuffle(allEnabledTables);
1944+
final Set<TableName> matchingTables = getTableDescriptors(new LinkedList<>(),
1945+
ntfp.getNamespace(), ntfp.getRegex(), ntfp.getTableNames(), false)
1946+
.stream()
1947+
.map(TableDescriptor::getTableName)
1948+
.collect(Collectors.toSet());
1949+
final Set<TableName> allEnabledTables =
1950+
tableStateManager.getTablesInStates(TableState.State.ENABLED);
1951+
final List<TableName> targetTables =
1952+
new ArrayList<>(Sets.intersection(matchingTables, allEnabledTables));
1953+
Collections.shuffle(targetTables);
19441954

19451955
final List<Long> submittedPlanProcIds = new ArrayList<>();
1946-
for (TableName table : allEnabledTables) {
1956+
for (TableName table : targetTables) {
19471957
if (table.isSystemTable()) {
19481958
continue;
19491959
}
@@ -3407,9 +3417,9 @@ public List<TableName> listTableNames(final String namespace, final String regex
34073417
}
34083418

34093419
/**
3410-
* @return list of table table descriptors after filtering by regex and whether to include system
3411-
* tables, etc.
3412-
* @throws IOException
3420+
* Return a list of table table descriptors after applying any provided filter parameters. Note
3421+
* that the user-facing description of this filter logic is presented on the class-level javadoc
3422+
* of {@link NormalizeTableFilterParams}.
34133423
*/
34143424
private List<TableDescriptor> getTableDescriptors(final List<TableDescriptor> htds,
34153425
final String namespace, final String regex, final List<TableName> tableNameList,

0 commit comments

Comments
 (0)