From 5fcffae5db8ba6d3afb2c4292fbac4b9795fc53d Mon Sep 17 00:00:00 2001 From: XinSun Date: Wed, 8 Jul 2020 14:39:41 +0800 Subject: [PATCH] HBASE-24431 RSGroupInfo add configuration map to store something extra (#2031) Signed-off-by: Guanghao Zhang --- .../hadoop/hbase/rsgroup/RSGroupInfo.java | 34 ++++++- .../src/main/protobuf/RSGroup.proto | 1 + .../hadoop/hbase/rsgroup/RSGroupAdmin.java | 9 ++ .../hbase/rsgroup/RSGroupAdminClient.java | 20 ++++ .../hbase/rsgroup/RSGroupAdminEndpoint.java | 28 ++++++ .../hbase/rsgroup/RSGroupAdminServer.java | 8 ++ .../hbase/rsgroup/RSGroupInfoManager.java | 9 ++ .../hbase/rsgroup/RSGroupInfoManagerImpl.java | 11 +++ .../hbase/rsgroup/RSGroupProtobufUtil.java | 19 ++-- .../src/main/protobuf/RSGroupAdmin.proto | 11 +++ .../hbase/rsgroup/TestRSGroupConfig.java | 94 +++++++++++++++++++ .../rsgroup/VerifyingRSGroupAdminClient.java | 7 ++ .../hbase/coprocessor/MasterObserver.java | 19 ++++ .../hbase/master/MasterCoprocessorHost.java | 21 +++++ .../src/main/ruby/hbase/rsgroup_admin.rb | 37 ++++++++ hbase-shell/src/main/ruby/shell.rb | 2 + .../shell/commands/alter_rsgroup_config.rb | 38 ++++++++ .../shell/commands/show_rsgroup_config.rb | 41 ++++++++ .../src/test/ruby/shell/rsgroup_shell_test.rb | 14 +++ 19 files changed, 416 insertions(+), 7 deletions(-) create mode 100644 hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupConfig.java create mode 100644 hbase-shell/src/main/ruby/shell/commands/alter_rsgroup_config.rb create mode 100644 hbase-shell/src/main/ruby/shell/commands/show_rsgroup_config.rb diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfo.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfo.java index 25e827de052..2fe2ba987f6 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfo.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfo.java @@ -19,6 +19,10 @@ package org.apache.hadoop.hbase.rsgroup; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -41,18 +45,22 @@ public class RSGroupInfo { // Keep tables sorted too. private final SortedSet tables; + private final Map configuration; + public RSGroupInfo(String name) { - this(name, new TreeSet
(), new TreeSet()); + this(name, new TreeSet<>(), new TreeSet<>()); } RSGroupInfo(String name, SortedSet
servers, SortedSet tables) { this.name = name; this.servers = (servers == null) ? new TreeSet<>() : new TreeSet<>(servers); this.tables = (tables == null) ? new TreeSet<>() : new TreeSet<>(tables); + configuration = new HashMap<>(); } public RSGroupInfo(RSGroupInfo src) { this(src.name, src.servers, src.tables); + src.configuration.forEach(this::setConfiguration); } /** @@ -121,6 +129,30 @@ public class RSGroupInfo { return tables.remove(table); } + /** + * Getter for fetching an unmodifiable {@link #configuration} map. + */ + public Map getConfiguration() { + // shallow pointer copy + return Collections.unmodifiableMap(configuration); + } + + /** + * Setter for storing a configuration setting in {@link #configuration} map. + * @param key Config key. + * @param value String value. + */ + public void setConfiguration(String key, String value) { + configuration.put(key, Objects.requireNonNull(value)); + } + + /** + * Remove a config setting represented by the key from the {@link #configuration} map + */ + public void removeConfiguration(final String key) { + configuration.remove(key); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/hbase-protocol/src/main/protobuf/RSGroup.proto b/hbase-protocol/src/main/protobuf/RSGroup.proto index ba8217515ec..5ab949c844e 100644 --- a/hbase-protocol/src/main/protobuf/RSGroup.proto +++ b/hbase-protocol/src/main/protobuf/RSGroup.proto @@ -31,5 +31,6 @@ message RSGroupInfo { required string name = 1; repeated ServerName servers = 4; repeated TableName tables = 3; + repeated NameStringPair configuration = 5; } diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdmin.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdmin.java index c389dc5d6cf..15daf1450de 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdmin.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdmin.java @@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.rsgroup; import java.io.IOException; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.hbase.TableName; @@ -105,4 +106,12 @@ public interface RSGroupAdmin { * @param newName new rsgroup name */ void renameRSGroup(String oldName, String newName) throws IOException; + + /** + * Update RSGroup configuration + * @param groupName the group name + * @param configuration new configuration of the group name to be set + * @throws IOException if a remote or network exception occurs + */ + void updateRSGroupConfig(String groupName, Map configuration) throws IOException; } diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java index bcfe3a4865b..b4e5e80d272 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminClient.java @@ -22,6 +22,7 @@ import com.google.protobuf.ServiceException; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.hbase.TableName; @@ -31,6 +32,7 @@ import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.AddRSGroupRequest; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupRequest; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.GetRSGroupInfoOfServerRequest; @@ -47,6 +49,7 @@ import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RSGroupAdmi import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupRequest; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupRequest; +import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigRequest; import org.apache.hadoop.hbase.protobuf.generated.RSGroupProtos; import org.apache.yetus.audience.InterfaceAudience; @@ -249,4 +252,21 @@ public class RSGroupAdminClient implements RSGroupAdmin { throw ProtobufUtil.handleRemoteException(e); } } + + @Override + public void updateRSGroupConfig(String groupName, Map configuration) + throws IOException { + UpdateRSGroupConfigRequest.Builder builder = UpdateRSGroupConfigRequest.newBuilder() + .setGroupName(groupName); + if (configuration != null) { + configuration.entrySet().forEach(e -> + builder.addConfiguration(NameStringPair.newBuilder().setName(e.getKey()) + .setValue(e.getValue()).build())); + } + try { + stub.updateRSGroupConfig(null, builder.build()); + } catch (ServiceException e) { + throw ProtobufUtil.handleRemoteException(e); + } + } } diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java index ad4c1af5516..0a05c85439b 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminEndpoint.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -81,6 +82,8 @@ import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServe import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupRequest; import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RenameRSGroupResponse; +import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigRequest; +import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.UpdateRSGroupConfigResponse; import org.apache.hadoop.hbase.protobuf.generated.TableProtos; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.UserProvider; @@ -90,6 +93,8 @@ import org.apache.hadoop.util.Shell.ShellCommandExecutor; import org.apache.yetus.audience.InterfaceAudience; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import org.apache.hbase.thirdparty.com.google.common.collect.Maps; import org.apache.hbase.thirdparty.com.google.common.collect.Sets; // TODO: Encapsulate MasterObserver functions into separate subclass. @@ -425,6 +430,29 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor, MasterObserver { } done.run(builder.build()); } + + @Override + public void updateRSGroupConfig(RpcController controller, UpdateRSGroupConfigRequest request, + RpcCallback done) { + UpdateRSGroupConfigResponse.Builder builder = UpdateRSGroupConfigResponse.newBuilder(); + String groupName = request.getGroupName(); + Map configuration = Maps.newHashMap(); + request.getConfigurationList().forEach(p -> configuration.put(p.getName(), p.getValue())); + LOG.info("{} update rsgroup {} configuration {}", master.getClientIdAuditPrefix(), groupName, + configuration); + try { + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().preUpdateRSGroupConfig(groupName, configuration); + } + groupAdminServer.updateRSGroupConfig(groupName, configuration); + if (master.getMasterCoprocessorHost() != null) { + master.getMasterCoprocessorHost().postUpdateRSGroupConfig(groupName, configuration); + } + } catch (IOException e) { + CoprocessorRpcUtils.setControllerException(controller, e); + } + done.run(builder.build()); + } } boolean rsgroupHasServersOnline(TableDescriptor desc) throws IOException { diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java index bf9f8488c82..a1f988dc3f9 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupAdminServer.java @@ -532,6 +532,14 @@ public class RSGroupAdminServer implements RSGroupAdmin { } } + @Override + public void updateRSGroupConfig(String groupName, Map configuration) + throws IOException { + synchronized (rsGroupInfoManager) { + rsGroupInfoManager.updateRSGroupConfig(groupName, configuration); + } + } + private Map rsGroupGetRegionsInTransition(String groupName) throws IOException { Map rit = Maps.newTreeMap(); diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java index 594f0f005da..e64e2d20847 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManager.java @@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.rsgroup; import java.io.IOException; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.hbase.NamespaceDescriptor; @@ -139,4 +140,12 @@ public interface RSGroupInfoManager { * @return {@link RSGroupInfo} which table should belong to */ RSGroupInfo determineRSGroupInfoForTable(TableName tableName) throws IOException; + + /** + * Update RSGroup configuration + * @param groupName the group name + * @param configuration new configuration of the group name to be set + * @throws IOException if a remote or network exception occurs + */ + void updateRSGroupConfig(String groupName, Map configuration) throws IOException; } diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java index 8c2c3135edd..c6a53e99110 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java @@ -32,6 +32,7 @@ import java.util.OptionalLong; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.Coprocessor; import org.apache.hadoop.hbase.DoNotRetryIOException; @@ -452,6 +453,16 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager { return getRSGroup(RSGroupInfo.DEFAULT_GROUP); } + @Override + public void updateRSGroupConfig(String groupName, Map configuration) + throws IOException { + RSGroupInfo rsGroupInfo = getRSGroupInfo(groupName); + new HashSet<>(rsGroupInfo.getConfiguration().keySet()) + .forEach(rsGroupInfo::removeConfiguration); + configuration.forEach(rsGroupInfo::setConfiguration); + flushConfig(); + } + List retrieveGroupListFromGroupTable() throws IOException { List rsGroupInfoList = Lists.newArrayList(); try (Table table = conn.getTable(RSGROUP_TABLE_NAME); diff --git a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupProtobufUtil.java b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupProtobufUtil.java index 9b6ba1cc1c9..9f092c52f2c 100644 --- a/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupProtobufUtil.java +++ b/hbase-rsgroup/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupProtobufUtil.java @@ -20,11 +20,13 @@ package org.apache.hadoop.hbase.rsgroup; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.net.Address; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair; import org.apache.hadoop.hbase.protobuf.generated.RSGroupProtos; import org.apache.hadoop.hbase.protobuf.generated.TableProtos; import org.apache.yetus.audience.InterfaceAudience; @@ -35,14 +37,16 @@ final class RSGroupProtobufUtil { } static RSGroupInfo toGroupInfo(RSGroupProtos.RSGroupInfo proto) { - RSGroupInfo RSGroupInfo = new RSGroupInfo(proto.getName()); + RSGroupInfo rsGroupInfo = new RSGroupInfo(proto.getName()); for(HBaseProtos.ServerName el: proto.getServersList()) { - RSGroupInfo.addServer(Address.fromParts(el.getHostName(), el.getPort())); + rsGroupInfo.addServer(Address.fromParts(el.getHostName(), el.getPort())); } for(TableProtos.TableName pTableName: proto.getTablesList()) { - RSGroupInfo.addTable(ProtobufUtil.toTableName(pTableName)); + rsGroupInfo.addTable(ProtobufUtil.toTableName(pTableName)); } - return RSGroupInfo; + proto.getConfigurationList().forEach(pair -> + rsGroupInfo.setConfiguration(pair.getName(), pair.getValue())); + return rsGroupInfo; } static RSGroupProtos.RSGroupInfo toProtoGroupInfo(RSGroupInfo pojo) { @@ -57,8 +61,11 @@ final class RSGroupProtobufUtil { .setPort(el.getPort()) .build()); } + List configuration = pojo.getConfiguration().entrySet() + .stream().map(entry -> NameStringPair.newBuilder() + .setName(entry.getKey()).setValue(entry.getValue()).build()) + .collect(Collectors.toList()); return RSGroupProtos.RSGroupInfo.newBuilder().setName(pojo.getName()) - .addAllServers(hostports) - .addAllTables(tables).build(); + .addAllServers(hostports).addAllTables(tables).addAllConfiguration(configuration).build(); } } diff --git a/hbase-rsgroup/src/main/protobuf/RSGroupAdmin.proto b/hbase-rsgroup/src/main/protobuf/RSGroupAdmin.proto index 10f6570a2f8..54add90eff4 100644 --- a/hbase-rsgroup/src/main/protobuf/RSGroupAdmin.proto +++ b/hbase-rsgroup/src/main/protobuf/RSGroupAdmin.proto @@ -131,6 +131,14 @@ message RenameRSGroupRequest { message RenameRSGroupResponse { } +message UpdateRSGroupConfigRequest { + required string group_name = 1; + repeated NameStringPair configuration = 2; +} + +message UpdateRSGroupConfigResponse { +} + service RSGroupAdminService { rpc GetRSGroupInfo(GetRSGroupInfoRequest) returns (GetRSGroupInfoResponse); @@ -167,4 +175,7 @@ service RSGroupAdminService { rpc RenameRSGroup(RenameRSGroupRequest) returns (RenameRSGroupResponse); + + rpc UpdateRSGroupConfig(UpdateRSGroupConfigRequest) + returns (UpdateRSGroupConfigResponse); } diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupConfig.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupConfig.java new file mode 100644 index 00000000000..79d0a1e01e4 --- /dev/null +++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupConfig.java @@ -0,0 +1,94 @@ +/** + * 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.rsgroup; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.testclassification.MediumTests; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +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.common.collect.Maps; + +@Category(MediumTests.class) +public class TestRSGroupConfig extends TestRSGroupsBase { + + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestRSGroupConfig.class); + + @Rule + public TestName name = new TestName(); + + protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupConfig.class); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + TestRSGroupsBase.setUpTestBeforeClass(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + TestRSGroupsBase.tearDownAfterClass(); + } + + @Test + public void testSetDefaultGroupConfiguration() throws IOException { + testSetConfiguration(RSGroupInfo.DEFAULT_GROUP); + } + + @Test + public void testSetNonDefaultGroupConfiguration() throws IOException { + String group = getGroupName(name.getMethodName()); + rsGroupAdmin.addRSGroup(group); + testSetConfiguration(RSGroupInfo.DEFAULT_GROUP); + rsGroupAdmin.removeRSGroup(group); + } + + private void testSetConfiguration(String group) throws IOException { + Map configuration = new HashMap<>(); + configuration.put("aaa", "111"); + configuration.put("bbb", "222"); + rsGroupAdmin.updateRSGroupConfig(group, configuration); + RSGroupInfo rsGroup = rsGroupAdmin.getRSGroupInfo(group); + Map configFromGroup = Maps.newHashMap(rsGroup.getConfiguration()); + assertNotNull(configFromGroup); + assertEquals(2, configFromGroup.size()); + assertEquals("111", configFromGroup.get("aaa")); + // unset configuration + rsGroupAdmin.updateRSGroupConfig(group, null); + rsGroup = rsGroupAdmin.getRSGroupInfo(group); + configFromGroup = rsGroup.getConfiguration(); + assertNotNull(configFromGroup); + assertEquals(0, configFromGroup.size()); + } + +} \ No newline at end of file diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java index 923a77d44f9..faa0bc0005f 100644 --- a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java +++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/VerifyingRSGroupAdminClient.java @@ -125,6 +125,13 @@ public class VerifyingRSGroupAdminClient implements RSGroupAdmin { verify(); } + @Override + public void updateRSGroupConfig(String groupName, Map configuration) + throws IOException { + wrapped.updateRSGroupConfig(groupName, configuration); + verify(); + } + public void verify() throws IOException { Map groupMap = Maps.newHashMap(); Set zList = Sets.newHashSet(); 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 48c259bac4e..4ea80de1121 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 @@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.coprocessor; import java.io.IOException; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.hbase.ClusterMetrics; import org.apache.hadoop.hbase.HBaseInterfaceAudience; @@ -1646,4 +1647,22 @@ public interface MasterObserver { default void postRenameRSGroup(final ObserverContext ctx, final String oldName, final String newName) throws IOException { } + + /** + * Called before update rsgroup config. + * @param ctx the environment to interact with the framework and master + * @param groupName the group name + * @param configuration new configuration of the group name to be set + */ + default void preUpdateRSGroupConfig(final ObserverContext ctx, + final String groupName, final Map configuration) throws IOException {} + + /** + * Called after update rsgroup config. + * @param ctx the environment to interact with the framework and master + * @param groupName the group name + * @param configuration new configuration of the group name to be set + */ + default void postUpdateRSGroupConfig(final ObserverContext ctx, + final String groupName, final Map configuration) throws IOException {} } 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 236eda0581f..2a29c72844b 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 @@ -22,6 +22,7 @@ import com.google.protobuf.Service; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.ClusterMetrics; @@ -1493,6 +1494,26 @@ public class MasterCoprocessorHost }); } + public void preUpdateRSGroupConfig(final String groupName, + final Map configuration) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + protected void call(MasterObserver observer) throws IOException { + observer.preUpdateRSGroupConfig(this, groupName, configuration); + } + }); + } + + public void postUpdateRSGroupConfig(final String groupName, + final Map configuration) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + protected void call(MasterObserver observer) throws IOException { + observer.postUpdateRSGroupConfig(this, groupName, configuration); + } + }); + } + public void preAddReplicationPeer(final String peerId, final ReplicationPeerConfig peerConfig) throws IOException { execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { diff --git a/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb b/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb index 76a480b34c5..e1638754752 100644 --- a/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb +++ b/hbase-shell/src/main/ruby/hbase/rsgroup_admin.rb @@ -185,5 +185,42 @@ module Hbase def rename_rsgroup(oldname, newname) @admin.renameRSGroup(oldname, newname) end + + #---------------------------------------------------------------------------------------------- + # modify a rsgroup configuration + def alter_rsgroup_config(rsgroup_name, *args) + # Fail if table name is not a string + raise(ArgumentError, 'RSGroup name must be of type String') unless rsgroup_name.is_a?(String) + + group = @admin.getRSGroupInfo(rsgroup_name) + + raise(ArgumentError, 'RSGroup does not exist') unless group + + configuration = java.util.HashMap.new + configuration.putAll(group.getConfiguration) + + # Flatten params array + args = args.flatten.compact + + # Start defining the table + args.each do |arg| + unless arg.is_a?(Hash) + raise(ArgumentError, "#{arg.class} of #{arg.inspect} is not of Hash type") + end + method = arg[METHOD] + if method == 'unset' + configuration.remove(arg[NAME]) + elsif method == 'set' + arg.delete(METHOD) + for k, v in arg + v = v.to_s unless v.nil? + configuration.put(k, v) + end + else + raise(ArgumentError, "Unknown method #{method}") + end + end + @admin.updateRSGroupConfig(rsgroup_name, configuration) + end end end diff --git a/hbase-shell/src/main/ruby/shell.rb b/hbase-shell/src/main/ruby/shell.rb index 6303d6b34a4..b638bbeebb5 100644 --- a/hbase-shell/src/main/ruby/shell.rb +++ b/hbase-shell/src/main/ruby/shell.rb @@ -508,5 +508,7 @@ Shell.load_command_group( get_table_rsgroup remove_servers_rsgroup rename_rsgroup + alter_rsgroup_config + show_rsgroup_config ] ) diff --git a/hbase-shell/src/main/ruby/shell/commands/alter_rsgroup_config.rb b/hbase-shell/src/main/ruby/shell/commands/alter_rsgroup_config.rb new file mode 100644 index 00000000000..a8489b873cf --- /dev/null +++ b/hbase-shell/src/main/ruby/shell/commands/alter_rsgroup_config.rb @@ -0,0 +1,38 @@ +# +# +# 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. +# + +module Shell + module Commands + class AlterRsgroupConfig < Command + def help + <<-EOF +Alter RSGroup configuration. +Example: + hbase> alter_rsgroup_config 'grp1', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'} +To delete a property: + hbase> alter_rsgroup_config 'grp1', {METHOD => 'unset', NAME=>'PROPERTY_NAME'} +EOF + end + + def command(group, args) + rsgroup_admin.alter_rsgroup_config(group, args) + end + end + end +end \ No newline at end of file diff --git a/hbase-shell/src/main/ruby/shell/commands/show_rsgroup_config.rb b/hbase-shell/src/main/ruby/shell/commands/show_rsgroup_config.rb new file mode 100644 index 00000000000..54344a1707b --- /dev/null +++ b/hbase-shell/src/main/ruby/shell/commands/show_rsgroup_config.rb @@ -0,0 +1,41 @@ +# +# +# 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. +# + +module Shell + module Commands + class ShowRsgroupConfig < Command + def help + <<-EOF +Show the configuration of a special RSGroup. +Example: + hbase> show_rsgroup_config 'group' +EOF + end + + def command(group) + formatter.header(%w['KEY' 'VALUE']) + config = rsgroup_admin.get_rsgroup(group).getConfiguration + config.each { |key, val| + formatter.row([key, val]) + } + formatter.footer(config.size) + end + end + end +end \ No newline at end of file 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 5e7f37d1e12..8b1fba48b2e 100644 --- a/hbase-shell/src/test/ruby/shell/rsgroup_shell_test.rb +++ b/hbase-shell/src/test/ruby/shell/rsgroup_shell_test.rb @@ -142,5 +142,19 @@ module Hbase assert_equal(1, @rsgroup_admin.getRSGroupInfo(new_rs_group_name).getTables.count) assert_equal(table_name, @rsgroup_admin.getRSGroupInfo(new_rs_group_name).getTables.iterator.next.toString) end + + define_test 'Test alter rsgroup configuration' do + group_name = 'grp1' + @shell.command('add_rsgroup', group_name) + assert_not_nil(@rsgroup_admin.getRSGroupInfo(group_name)) + + @hbase.rsgroup_admin.alter_rsgroup_config(group_name, {'METHOD' => 'set', 'a' => 'a'}) + assert_equal(1, @rsgroup_admin.getRSGroupInfo(group_name).getConfiguration.size) + @hbase.rsgroup_admin.alter_rsgroup_config(group_name, {'METHOD' => 'unset', 'NAME' => 'a'}) + assert_equal(0, @rsgroup_admin.getRSGroupInfo(group_name).getConfiguration.size) + + @shell.command('remove_rsgroup', group_name) + assert_nil(@rsgroup_admin.getRSGroupInfo(group_name)) + end end end