HBASE-22932 Add rs group management methods in Admin and AsyncAdmin (#657)

Signed-off-by: Duo Zhang <zhangduo@apache.org>
This commit is contained in:
linkaline 2019-11-05 14:15:51 +08:00 committed by Duo Zhang
parent e8e9eecef1
commit 72cbb129a4
35 changed files with 2605 additions and 991 deletions

View File

@ -45,6 +45,7 @@ import org.apache.hadoop.hbase.client.replication.ReplicationPeerConfigUtil;
import org.apache.hadoop.hbase.client.replication.TableCFs;
import org.apache.hadoop.hbase.client.security.SecurityCapability;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaFilter;
import org.apache.hadoop.hbase.quotas.QuotaSettings;
import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshotView;
@ -53,6 +54,7 @@ import org.apache.hadoop.hbase.replication.ReplicationException;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
@ -2261,7 +2263,6 @@ public interface Admin extends Abortable, Closeable {
*/
boolean isSnapshotCleanupEnabled() throws IOException;
/**
* Retrieves online slow RPC logs from the provided list of
* RegionServers
@ -2286,4 +2287,80 @@ public interface Admin extends Abortable, Closeable {
List<Boolean> clearSlowLogResponses(final Set<ServerName> serverNames)
throws IOException;
/**
* Creates a new RegionServer group with the given name
* @param groupName the name of the group
* @throws IOException if a remote or network exception occurs
*/
void addRSGroup(String groupName) throws IOException;
/**
* Get group info for the given group name
* @param groupName the group name
* @return group info
* @throws IOException if a remote or network exception occurs
*/
RSGroupInfo getRSGroup(String groupName) throws IOException;
/**
* Get group info for the given hostPort
* @param hostPort HostPort to get RSGroupInfo for
* @throws IOException if a remote or network exception occurs
*/
RSGroupInfo getRSGroup(Address hostPort) throws IOException;
/**
* Get group info for the given table
* @param tableName table name to get RSGroupInfo for
* @throws IOException if a remote or network exception occurs
*/
RSGroupInfo getRSGroup(TableName tableName) throws IOException;
/**
* Lists current set of RegionServer groups
* @throws IOException if a remote or network exception occurs
*/
List<RSGroupInfo> listRSGroups() throws IOException;
/**
* Remove RegionServer group associated with the given name
* @param groupName the group name
* @throws IOException if a remote or network exception occurs
*/
void removeRSGroup(String groupName) throws IOException;
/**
* Remove decommissioned servers from group
* 1. Sometimes we may find the server aborted due to some hardware failure and we must offline
* the server for repairing. Or we need to move some servers to join other clusters.
* So we need to remove these servers from the group.
* 2. Dead/recovering/live servers will be disallowed.
* @param servers set of servers to remove
* @throws IOException if a remote or network exception occurs
*/
void removeRSGroup(Set<Address> servers) throws IOException;
/**
* Move given set of servers to the specified target RegionServer group
* @param servers set of servers to move
* @param targetGroup the group to move servers to
* @throws IOException if a remote or network exception occurs
*/
void moveToRSGroup(Set<Address> servers, String targetGroup) throws IOException;
/**
* Set the RegionServer group for tables
* @param tables tables to set group for
* @param groupName group name for tables
* @throws IOException if a remote or network exception occurs
*/
void setRSGroup(Set<TableName> tables, String groupName) throws IOException;
/**
* Balance regions in the given RegionServer group
* @param groupName the group name
* @return boolean Whether balance ran or not
* @throws IOException if a remote or network exception occurs
*/
boolean balanceRSGroup(String groupName) throws IOException;
}

View File

@ -49,6 +49,7 @@ import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.replication.TableCFs;
import org.apache.hadoop.hbase.client.security.SecurityCapability;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaFilter;
import org.apache.hadoop.hbase.quotas.QuotaSettings;
import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshotView;
@ -56,6 +57,7 @@ import org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
@ -972,4 +974,54 @@ class AdminOverAsyncAdmin implements Admin {
return get(admin.clearSlowLogResponses(serverNames));
}
@Override
public RSGroupInfo getRSGroup(String groupName) throws IOException {
return get(admin.getRSGroup(groupName));
}
@Override
public void moveToRSGroup(Set<Address> servers, String groupName) throws IOException {
get(admin.moveToRSGroup(servers, groupName));
}
@Override
public void addRSGroup(String groupName) throws IOException {
get(admin.addRSGroup(groupName));
}
@Override
public void removeRSGroup(String groupName) throws IOException {
get(admin.removeRSGroup(groupName));
}
@Override
public boolean balanceRSGroup(String groupName) throws IOException {
return get(admin.balanceRSGroup(groupName));
}
@Override
public List<RSGroupInfo> listRSGroups() throws IOException {
return get(admin.listRSGroups());
}
@Override
public RSGroupInfo getRSGroup(Address hostPort) throws IOException {
return get(admin.getRSGroup(hostPort));
}
@Override
public void removeRSGroup(Set<Address> servers) throws IOException {
get(admin.removeRSGroup(servers));
}
@Override
public RSGroupInfo getRSGroup(TableName tableName) throws IOException {
return get(admin.getRSGroup(tableName));
}
@Override
public void setRSGroup(Set<TableName> tables, String groupName) throws IOException {
get(admin.setRSGroup(tables, groupName));
}
}

View File

@ -40,12 +40,14 @@ import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.replication.TableCFs;
import org.apache.hadoop.hbase.client.security.SecurityCapability;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaFilter;
import org.apache.hadoop.hbase.quotas.QuotaSettings;
import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshotView;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
@ -1380,7 +1382,7 @@ public interface AsyncAdmin {
* @param newTableName name of the new table where the table will be created
* @param preserveSplits True if the splits should be preserved
*/
CompletableFuture<Void> cloneTableSchema(final TableName tableName,
CompletableFuture<Void> cloneTableSchema(final TableName tableName,
final TableName newTableName, final boolean preserveSplits);
/**
@ -1526,4 +1528,81 @@ public interface AsyncAdmin {
* from each RegionServer. The return value wrapped by a {@link CompletableFuture}
*/
CompletableFuture<List<Boolean>> clearSlowLogResponses(final Set<ServerName> serverNames);
/**
* Creates a new RegionServer group with the given name
* @param groupName the name of the group
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<Void> addRSGroup(String groupName);
/**
* Get group info for the given group name
* @param groupName the group name
* @return group info
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<RSGroupInfo> getRSGroup(String groupName);
/**
* Get group info for the given hostPort
* @param hostPort HostPort to get RSGroupInfo for
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<RSGroupInfo> getRSGroup(Address hostPort);
/**
* Get group info for the given table
* @param tableName table name to get RSGroupInfo for
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<RSGroupInfo> getRSGroup(TableName tableName);
/**
* Lists current set of RegionServer groups
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<List<RSGroupInfo>> listRSGroups();
/**
* Remove RegionServer group associated with the given name
* @param groupName the group name
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<Void> removeRSGroup(String groupName);
/**
* Remove decommissioned servers from group
* 1. Sometimes we may find the server aborted due to some hardware failure and we must offline
* the server for repairing. Or we need to move some servers to join other clusters.
* So we need to remove these servers from the group.
* 2. Dead/recovering/live servers will be disallowed.
* @param servers set of servers to remove
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<Void> removeRSGroup(Set<Address> servers);
/**
* Move given set of servers to the specified target RegionServer group
* @param servers set of servers to move
* @param groupName the group to move servers to
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<Void> moveToRSGroup(Set<Address> servers, String groupName);
/**
* Set the RegionServer group for tables
* @param tables tables to set group for
* @param groupName group name for tables
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<Void> setRSGroup(Set<TableName> tables, String groupName);
/**
* Balance regions in the given RegionServer group
* @param groupName the group name
* @return boolean Whether balance ran or not
* @throws IOException if a remote or network exception occurs
*/
CompletableFuture<Boolean> balanceRSGroup(String groupName);
}

View File

@ -37,12 +37,14 @@ import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.replication.TableCFs;
import org.apache.hadoop.hbase.client.security.SecurityCapability;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaFilter;
import org.apache.hadoop.hbase.quotas.QuotaSettings;
import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
@ -850,4 +852,53 @@ class AsyncHBaseAdmin implements AsyncAdmin {
return wrap(rawAdmin.clearSlowLogResponses(serverNames));
}
@Override
public CompletableFuture<RSGroupInfo> getRSGroup(String groupName) {
return wrap(rawAdmin.getRSGroup(groupName));
}
@Override
public CompletableFuture<Void> moveToRSGroup(Set<Address> servers, String groupName) {
return wrap(rawAdmin.moveToRSGroup(servers, groupName));
}
@Override
public CompletableFuture<Void> addRSGroup(String groupName) {
return wrap(rawAdmin.addRSGroup(groupName));
}
@Override
public CompletableFuture<Void> removeRSGroup(String groupName) {
return wrap(rawAdmin.removeRSGroup(groupName));
}
@Override
public CompletableFuture<Boolean> balanceRSGroup(String groupName) {
return wrap(rawAdmin.balanceRSGroup(groupName));
}
@Override
public CompletableFuture<List<RSGroupInfo>> listRSGroups() {
return wrap(rawAdmin.listRSGroups());
}
@Override
public CompletableFuture<RSGroupInfo> getRSGroup(Address hostPort) {
return wrap(rawAdmin.getRSGroup(hostPort));
}
@Override
public CompletableFuture<Void> removeRSGroup(Set<Address> servers) {
return wrap(rawAdmin.removeRSGroup(servers));
}
@Override
public CompletableFuture<RSGroupInfo> getRSGroup(TableName tableName) {
return wrap(rawAdmin.getRSGroup(tableName));
}
@Override
public CompletableFuture<Void> setRSGroup(Set<TableName> tables, String groupName) {
return wrap(rawAdmin.setRSGroup(tables, groupName));
}
}

View File

@ -78,6 +78,7 @@ import org.apache.hadoop.hbase.client.replication.TableCFs;
import org.apache.hadoop.hbase.client.security.SecurityCapability;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.ipc.HBaseRpcController;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaFilter;
import org.apache.hadoop.hbase.quotas.QuotaSettings;
import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
@ -86,6 +87,7 @@ import org.apache.hadoop.hbase.replication.ReplicationException;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil;
@ -206,8 +208,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsProcedur
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsProcedureDoneResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsRpcThrottleEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsRpcThrottleEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos
.IsSnapshotCleanupEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotCleanupEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotDoneRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotDoneResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledRequest;
@ -258,8 +259,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetNormali
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetNormalizerRunningResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos
.SetSnapshotCleanupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetSnapshotCleanupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetSplitOrMergeEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetSplitOrMergeEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ShutdownRequest;
@ -285,6 +285,18 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuo
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaRegionSizesResponse.RegionSizes;
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaSnapshotsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaSnapshotsResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.AddRSGroupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.AddRSGroupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.MoveServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.MoveServersResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos.AddReplicationPeerRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos.AddReplicationPeerResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos.DisableReplicationPeerRequest;
@ -3858,23 +3870,70 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
@Override
public CompletableFuture<Boolean> snapshotCleanupSwitch(final boolean on,
final boolean sync) {
return this.<Boolean>newMasterCaller()
.action((controller, stub) -> this
.call(controller, stub,
RequestConverter.buildSetSnapshotCleanupRequest(on, sync),
MasterService.Interface::switchSnapshotCleanup,
SetSnapshotCleanupResponse::getPrevSnapshotCleanup))
.call();
return this.<Boolean>newMasterCaller().action((controller, stub) -> this
.call(controller, stub, RequestConverter.buildSetSnapshotCleanupRequest(on, sync),
MasterService.Interface::switchSnapshotCleanup,
SetSnapshotCleanupResponse::getPrevSnapshotCleanup)).call();
}
@Override
public CompletableFuture<Boolean> isSnapshotCleanupEnabled() {
return this.<Boolean>newMasterCaller()
return this.<Boolean>newMasterCaller().action((controller, stub) -> this
.call(controller, stub, RequestConverter.buildIsSnapshotCleanupEnabledRequest(),
MasterService.Interface::isSnapshotCleanupEnabled,
IsSnapshotCleanupEnabledResponse::getEnabled)).call();
}
@Override
public CompletableFuture<Void> moveToRSGroup(Set<Address> servers, String groupName) {
return this.<Void> newMasterCaller()
.action((controller, stub) -> this.
<MoveServersRequest, MoveServersResponse, Void> call(controller, stub,
RequestConverter.buildMoveServersRequest(servers, groupName),
(s, c, req, done) -> s.moveServers(c, req, done), resp -> null))
.call();
}
@Override
public CompletableFuture<Void> addRSGroup(String groupName) {
return this.<Void> newMasterCaller()
.action(((controller, stub) -> this.
<AddRSGroupRequest, AddRSGroupResponse, Void> call(controller, stub,
AddRSGroupRequest.newBuilder().setRSGroupName(groupName).build(),
(s, c, req, done) -> s.addRSGroup(c, req, done), resp -> null)))
.call();
}
@Override
public CompletableFuture<Void> removeRSGroup(String groupName) {
return this.<Void> newMasterCaller()
.action((controller, stub) -> this.
<RemoveRSGroupRequest, RemoveRSGroupResponse, Void> call(controller, stub,
RemoveRSGroupRequest.newBuilder().setRSGroupName(groupName).build(),
(s, c, req, done) -> s.removeRSGroup(c, req, done), resp -> null))
.call();
}
@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();
}
@Override
public CompletableFuture<List<RSGroupInfo>> listRSGroups() {
return this.<List<RSGroupInfo>> newMasterCaller()
.action((controller, stub) -> this
.call(controller, stub,
RequestConverter.buildIsSnapshotCleanupEnabledRequest(),
MasterService.Interface::isSnapshotCleanupEnabled,
IsSnapshotCleanupEnabledResponse::getEnabled))
.<ListRSGroupInfosRequest, ListRSGroupInfosResponse, List<RSGroupInfo>> call(
controller, stub, ListRSGroupInfosRequest.getDefaultInstance(),
(s, c, req, done) -> s.listRSGroupInfos(c, req, done),
resp -> resp.getRSGroupInfoList().stream()
.map(r -> ProtobufUtil.toGroupInfo(r))
.collect(Collectors.toList())))
.call();
}
@ -3937,4 +3996,120 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
);
}
@Override
public CompletableFuture<RSGroupInfo> getRSGroup(Address hostPort) {
CompletableFuture<RSGroupInfo> future = new CompletableFuture<>();
addListener(listRSGroups(), (groups, err) -> {
if (err != null) {
future.completeExceptionally(err);
return;
}
for (RSGroupInfo rsGroupInfo : groups) {
if (rsGroupInfo.getServers().contains(hostPort)){
future.complete(rsGroupInfo);
return;
}
}
future.complete(null);
});
return future;
}
@Override
public CompletableFuture<Void> removeRSGroup(Set<Address> servers) {
return this.<Void> newMasterCaller()
.action((controller, stub) -> this.
<RemoveServersRequest, RemoveServersResponse, Void> call(controller, stub,
RequestConverter.buildRemoveServersRequest(servers),
(s, c, req, done) -> s.removeServers(c, req, done), resp -> null))
.call();
}
@Override
public CompletableFuture<Void> setRSGroup(Set<TableName> tables, String groupName) {
CompletableFuture<Void> future = new CompletableFuture<>();
for (TableName tableName : tables) {
addListener(tableExists(tableName), (exist, err) -> {
if (err != null) {
future.completeExceptionally(err);
return;
}
if (!exist) {
future.completeExceptionally(new TableNotFoundException(tableName));
return;
}
});
}
addListener(listTableDescriptors(new ArrayList<>(tables)), ((tableDescriptions, err) -> {
if (err != null) {
future.completeExceptionally(err);
return;
}
if (tableDescriptions == null || tableDescriptions.isEmpty()) {
future.complete(null);
return;
}
List<TableDescriptor> newTableDescriptors = new ArrayList<>();
for (TableDescriptor td : tableDescriptions) {
newTableDescriptors
.add(TableDescriptorBuilder.newBuilder(td).setRegionServerGroup(groupName).build());
}
addListener(CompletableFuture.allOf(
newTableDescriptors.stream().map(this::modifyTable).toArray(CompletableFuture[]::new)),
(v, e) -> {
if (e != null) {
future.completeExceptionally(e);
} else {
future.complete(v);
}
});
}));
return future;
}
@Override
public CompletableFuture<RSGroupInfo> getRSGroup(TableName table) {
CompletableFuture<RSGroupInfo> future = new CompletableFuture<>();
addListener(getDescriptor(table), (td, err) -> {
if (err != null) {
// return null instead of err to keep compatible with old semantics
// todo: need to change both this and UTs
future.complete(null);
return;
}
addListener(listRSGroups(), (groups, err2) -> {
if (err2 != null) {
future.completeExceptionally(err2);
return;
}
for (RSGroupInfo rsGroupInfo : groups) {
if (rsGroupInfo.getTables().contains(table)) {
future.complete(rsGroupInfo);
return;
}
}
future.complete(null);
});
});
return future;
}
@Override
public CompletableFuture<RSGroupInfo> getRSGroup(String groupName) {
CompletableFuture<RSGroupInfo> future = new CompletableFuture<>();
addListener(listRSGroups(), (groups, err) -> {
if (err != null) {
future.completeExceptionally(err);
return;
}
for (RSGroupInfo rsGroupInfo : groups) {
if (rsGroupInfo.getName().equals(groupName)){
future.complete(rsGroupInfo);
return;
}
}
future.complete(null);
});
return future;
}
}

View File

@ -26,7 +26,6 @@ import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.CellScannable;
import org.apache.hadoop.hbase.ClusterMetrics.Option;
@ -60,6 +59,7 @@ import org.apache.hadoop.hbase.filter.BinaryComparator;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.io.TimeRange;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.util.Bytes;
@ -68,7 +68,9 @@ import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.security.token.Token;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ClearCompactionQueuesRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ClearRegionBlockCacheRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ClearSlowLogResponseRequest;
@ -123,8 +125,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsCatalogJ
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsCleanerChoreEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsMasterRunningRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsNormalizerEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos
.IsSnapshotCleanupEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotCleanupEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MergeTableRegionsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ModifyColumnRequest;
@ -140,8 +141,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetBalance
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetCleanerChoreRunningRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetNormalizerRunningRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetRegionStateInMetaRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos
.SetSnapshotCleanupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetSnapshotCleanupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetSplitOrMergeEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetTableStateInMetaRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SplitTableRegionRequest;
@ -150,6 +150,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.UnassignRe
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetQuotaStatesRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaRegionSizesRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaSnapshotsRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.MoveServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos.AddReplicationPeerRequest;
@ -1789,4 +1791,28 @@ public final class RequestConverter {
return ClearSlowLogResponseRequest.newBuilder().build();
}
public static MoveServersRequest buildMoveServersRequest(Set<Address> servers,
String targetGroup) {
Set<HBaseProtos.ServerName> hostPorts = Sets.newHashSet();
for (Address el : servers) {
hostPorts.add(
HBaseProtos.ServerName.newBuilder().setHostName(el.getHostname()).setPort(el.getPort())
.build());
}
return MoveServersRequest.newBuilder().setTargetGroup(targetGroup).addAllServers(hostPorts)
.build();
}
public static RemoveServersRequest buildRemoveServersRequest(Set<Address> servers) {
Set<HBaseProtos.ServerName> hostPorts = Sets.newHashSet();
for(Address el: servers) {
hostPorts.add(HBaseProtos.ServerName.newBuilder()
.setHostName(el.getHostname())
.setPort(el.getPort())
.build());
}
return RemoveServersRequest.newBuilder()
.addAllServers(hostPorts)
.build();
}
}

View File

@ -82,7 +82,7 @@ public class IntegrationTestRSGroup extends TestRSGroupsBase {
LOG.info("Waiting for cleanup to finish "+ rsGroupAdmin.listRSGroups());
//Might be greater since moving servers back to default
//is after starting a server
return rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size()
return rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getServers().size()
>= NUM_SLAVES_BASE;
}
});
@ -93,7 +93,7 @@ public class IntegrationTestRSGroup extends TestRSGroupsBase {
LOG.info("Waiting for regionservers to be registered "+ rsGroupAdmin.listRSGroups());
//Might be greater since moving servers back to default
//is after starting a server
return rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size()
return rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getServers().size()
== getNumServers();
}
});

View File

@ -37,6 +37,7 @@ import "Quota.proto";
import "Replication.proto";
import "Snapshot.proto";
import "AccessControl.proto";
import "RSGroupAdmin.proto";
/* Column-level protobufs */
@ -1085,6 +1086,24 @@ service MasterService {
/** returns a list of namespace names */
rpc ListNamespaces(ListNamespacesRequest)
returns(ListNamespacesResponse);
rpc MoveServers(MoveServersRequest)
returns (MoveServersResponse);
rpc AddRSGroup(AddRSGroupRequest)
returns (AddRSGroupResponse);
rpc RemoveRSGroup(RemoveRSGroupRequest)
returns (RemoveRSGroupResponse);
rpc BalanceRSGroup(BalanceRSGroupRequest)
returns (BalanceRSGroupResponse);
rpc ListRSGroupInfos(ListRSGroupInfosRequest)
returns (ListRSGroupInfosResponse);
rpc RemoveServers(RemoveServersRequest)
returns (RemoveServersResponse);
}
// HBCK Service definitions.

View File

@ -3822,7 +3822,7 @@ public class HMaster extends HRegionServer implements MasterServices {
public static void decorateMasterConfiguration(Configuration conf) {
String plugins = conf.get(HBASE_MASTER_LOGCLEANER_PLUGINS);
String cleanerClass = ReplicationLogCleaner.class.getCanonicalName();
if (!plugins.contains(cleanerClass)) {
if (plugins == null || !plugins.contains(cleanerClass)) {
conf.set(HBASE_MASTER_LOGCLEANER_PLUGINS, plugins + "," + cleanerClass);
}
if (ReplicationUtils.isReplicationForBulkLoadDataEnabled(conf)) {

View File

@ -1772,7 +1772,8 @@ public class MasterCoprocessorHost
});
}
public void preDecommissionRegionServers(List<ServerName> servers, boolean offload) throws IOException {
public void preDecommissionRegionServers(List<ServerName> servers, boolean offload)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {
@ -1781,7 +1782,8 @@ public class MasterCoprocessorHost
});
}
public void postDecommissionRegionServers(List<ServerName> servers, boolean offload) throws IOException {
public void postDecommissionRegionServers(List<ServerName> servers, boolean offload)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
@Override
public void call(MasterObserver observer) throws IOException {

View File

@ -95,6 +95,7 @@ import org.apache.hadoop.hbase.regionserver.RpcSchedulerFactory;
import org.apache.hadoop.hbase.replication.ReplicationException;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.Superusers;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessChecker;
@ -121,6 +122,8 @@ 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.RpcController;
import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
@ -314,6 +317,18 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetQuotaSta
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaRegionSizesRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaRegionSizesResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.GetSpaceQuotaRegionSizesResponse.RegionSizes;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.AddRSGroupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.AddRSGroupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.BalanceRSGroupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.ListRSGroupInfosResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.MoveServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.MoveServersResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.FileArchiveNotificationRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.FileArchiveNotificationResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdRequest;
@ -363,6 +378,7 @@ public class MasterRpcServices extends RSRpcServices implements
MasterService.BlockingInterface, RegionServerStatusService.BlockingInterface,
LockService.BlockingInterface, HbckService.BlockingInterface,
ClientMetaService.BlockingInterface {
private static final Logger LOG = LoggerFactory.getLogger(MasterRpcServices.class.getName());
private static final Logger AUDITLOG =
LoggerFactory.getLogger("SecurityLogger."+MasterRpcServices.class.getName());
@ -2901,4 +2917,154 @@ public class MasterRpcServices extends RSRpcServices implements
location -> response.addMetaLocations(ProtobufUtil.toRegionLocation(location))));
return response.build();
}
@Override
public MoveServersResponse moveServers(RpcController controller, MoveServersRequest request)
throws ServiceException {
Set<Address> hostPorts = Sets.newHashSet();
MoveServersResponse.Builder builder = MoveServersResponse.newBuilder();
for (HBaseProtos.ServerName el : request.getServersList()) {
hostPorts.add(Address.fromParts(el.getHostName(), el.getPort()));
}
LOG.info(master.getClientIdAuditPrefix() + " move servers " + hostPorts + " to rsgroup " +
request.getTargetGroup());
try {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preMoveServers(hostPorts, request.getTargetGroup());
}
master.getRSGroupInfoManager().moveServers(hostPorts, request.getTargetGroup());
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postMoveServers(hostPorts, request.getTargetGroup());
}
} catch (IOException e) {
throw new ServiceException(e);
}
return builder.build();
}
@Override
public AddRSGroupResponse addRSGroup(RpcController controller, AddRSGroupRequest request)
throws ServiceException {
AddRSGroupResponse.Builder builder = AddRSGroupResponse.newBuilder();
LOG.info(master.getClientIdAuditPrefix() + " add rsgroup " + request.getRSGroupName());
try {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preAddRSGroup(request.getRSGroupName());
}
master.getRSGroupInfoManager().addRSGroup(new RSGroupInfo(request.getRSGroupName()));
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postAddRSGroup(request.getRSGroupName());
}
} catch (IOException e) {
throw new ServiceException(e);
}
return builder.build();
}
@Override
public RemoveRSGroupResponse removeRSGroup(RpcController controller, RemoveRSGroupRequest request)
throws ServiceException {
RemoveRSGroupResponse.Builder builder = RemoveRSGroupResponse.newBuilder();
LOG.info(master.getClientIdAuditPrefix() + " remove rsgroup " + request.getRSGroupName());
try {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preRemoveRSGroup(request.getRSGroupName());
}
master.getRSGroupInfoManager().removeRSGroup(request.getRSGroupName());
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postRemoveRSGroup(request.getRSGroupName());
}
} catch (IOException e) {
throw new ServiceException(e);
}
return builder.build();
}
@Override
public BalanceRSGroupResponse balanceRSGroup(RpcController controller,
BalanceRSGroupRequest request) throws ServiceException {
BalanceRSGroupResponse.Builder builder = BalanceRSGroupResponse.newBuilder();
LOG.info(
master.getClientIdAuditPrefix() + " balance rsgroup, group=" + request.getRSGroupName());
try {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preBalanceRSGroup(request.getRSGroupName());
}
boolean balancerRan =
master.getRSGroupInfoManager().balanceRSGroup(request.getRSGroupName());
builder.setBalanceRan(balancerRan);
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postBalanceRSGroup(request.getRSGroupName(), balancerRan);
}
} catch (IOException e) {
throw new ServiceException(e);
}
return builder.build();
}
@Override
public ListRSGroupInfosResponse listRSGroupInfos(RpcController controller,
ListRSGroupInfosRequest request) throws ServiceException {
ListRSGroupInfosResponse.Builder builder = ListRSGroupInfosResponse.newBuilder();
LOG.info(master.getClientIdAuditPrefix() + " list rsgroup");
try {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preListRSGroups();
}
List<RSGroupInfo> rsGroupInfos = master.getRSGroupInfoManager().listRSGroups().stream()
.map(RSGroupInfo::new).collect(Collectors.toList());
Map<String, RSGroupInfo> name2Info = new HashMap<>();
List<TableDescriptor> needToFill =
new ArrayList<>(master.getTableDescriptors().getAll().values());
for (RSGroupInfo rsGroupInfo : rsGroupInfos) {
name2Info.put(rsGroupInfo.getName(), rsGroupInfo);
for (TableDescriptor td : master.getTableDescriptors().getAll().values()) {
if (rsGroupInfo.containsTable(td.getTableName())){
needToFill.remove(td);
}
}
}
for (TableDescriptor td : needToFill) {
String groupName = td.getRegionServerGroup().orElse(RSGroupInfo.DEFAULT_GROUP);
RSGroupInfo rsGroupInfo = name2Info.get(groupName);
if (rsGroupInfo != null) {
rsGroupInfo.addTable(td.getTableName());
}
}
for (RSGroupInfo rsGroupInfo : rsGroupInfos) {
// TODO: this can be done at once outside this loop, do not need to scan all every time.
builder.addRSGroupInfo(ProtobufUtil.toProtoGroupInfo(rsGroupInfo));
}
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postListRSGroups();
}
} catch (IOException e) {
throw new ServiceException(e);
}
return builder.build();
}
@Override
public RemoveServersResponse removeServers(RpcController controller,
RemoveServersRequest request) throws ServiceException {
RemoveServersResponse.Builder builder = RemoveServersResponse.newBuilder();
Set<Address> servers = Sets.newHashSet();
for (HBaseProtos.ServerName el : request.getServersList()) {
servers.add(Address.fromParts(el.getHostName(), el.getPort()));
}
LOG.info(master.getClientIdAuditPrefix() + " remove decommissioned servers from rsgroup: " +
servers);
try {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preRemoveServers(servers);
}
master.getRSGroupInfoManager().removeServers(servers);
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postRemoveServers(servers);
}
} catch (IOException e) {
throw new ServiceException(e);
}
return builder.build();
}
}

View File

@ -52,6 +52,7 @@ import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfoManager;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.hadoop.hbase.security.access.ZKPermissionWatcher;
import org.apache.hadoop.hbase.zookeeper.LoadBalancerTracker;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
@ -545,4 +546,12 @@ public interface MasterServices extends Server {
* @return the {@link RSGroupInfoManager}
*/
RSGroupInfoManager getRSGroupInfoManager();
/**
* Queries the state of the {@link LoadBalancerTracker}. If the balancer is not initialized,
* false is returned.
*
* @return The state of the load balancer, or false if the load balancer isn't defined.
*/
boolean isBalancerOn();
}

View File

@ -57,8 +57,7 @@ class DisabledRSGroupInfoManager implements RSGroupInfoManager {
}
@Override
public Set<Address> moveServers(Set<Address> servers, String srcGroup, String dstGroup)
throws IOException {
public void moveServers(Set<Address> servers, String targetGroupName) throws IOException {
throw new DoNotRetryIOException("RSGroup is disabled");
}
@ -106,4 +105,14 @@ class DisabledRSGroupInfoManager implements RSGroupInfoManager {
public RSGroupInfo getRSGroupForTable(TableName tableName) throws IOException {
return null;
}
@Override
public boolean balanceRSGroup(String groupName) throws IOException {
throw new DoNotRetryIOException("RSGroup is disabled");
}
@Override
public void setRSGroup(Set<TableName> tables, String groupName) throws IOException {
throw new DoNotRetryIOException("RSGroup is disabled");
}
}

View File

@ -20,12 +20,16 @@ package org.apache.hadoop.hbase.rsgroup;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.net.Address;
import org.apache.yetus.audience.InterfaceAudience;
/**
* Group user API interface used between client and server.
*
* @deprecated Keep it here only for tests, using {@link Admin} instead.
*/
@Deprecated
@InterfaceAudience.Private
public interface RSGroupAdmin {
/**

View File

@ -25,12 +25,8 @@ import org.apache.hadoop.hbase.coprocessor.CoreCoprocessor;
import org.apache.hadoop.hbase.coprocessor.HasMasterServices;
import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.security.UserProvider;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
/**
* @deprecated Keep it here only for compatibility with old client, all the logics have been moved
* into core of HBase.
@ -42,8 +38,6 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor {
// Only instance of RSGroupInfoManager. RSGroup aware load balancers ask for this instance on
// their setup.
private MasterServices master;
private RSGroupInfoManager groupInfoManager;
private RSGroupAdminServer groupAdminServer;
private RSGroupAdminServiceImpl groupAdminService = new RSGroupAdminServiceImpl();
@Override
@ -51,19 +45,8 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor {
if (!(env instanceof HasMasterServices)) {
throw new IOException("Does not implement HMasterServices");
}
master = ((HasMasterServices) env).getMasterServices();
groupInfoManager = master.getRSGroupInfoManager();
groupAdminServer = new RSGroupAdminServer(master, groupInfoManager);
AccessChecker accessChecker = ((HasMasterServices) env).getMasterServices().getAccessChecker();
// set the user-provider.
UserProvider userProvider = UserProvider.instantiate(env.getConfiguration());
groupAdminService.initialize(master, groupAdminServer, accessChecker, userProvider);
}
@Override
public void stop(CoprocessorEnvironment env) {
groupAdminService.initialize(master);
}
@Override
@ -72,11 +55,7 @@ public class RSGroupAdminEndpoint implements MasterCoprocessor {
}
RSGroupInfoManager getGroupInfoManager() {
return groupInfoManager;
return master.getRSGroupInfoManager();
}
@VisibleForTesting
RSGroupAdminServiceImpl getGroupAdminService() {
return groupAdminService;
}
}

View File

@ -1,496 +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.rsgroup;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.constraint.ConstraintException;
import org.apache.hadoop.hbase.master.HMaster;
import org.apache.hadoop.hbase.master.LoadBalancer;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.master.RegionPlan;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.master.assignment.RegionStateNode;
import org.apache.hadoop.hbase.net.Address;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
/**
* Service to support Region Server Grouping (HBase-6721).
*/
@InterfaceAudience.Private
public class RSGroupAdminServer implements RSGroupAdmin {
private static final Logger LOG = LoggerFactory.getLogger(RSGroupAdminServer.class);
static final String KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE = "should keep at least " +
"one server in 'default' RSGroup.";
private MasterServices master;
final RSGroupInfoManager rsGroupInfoManager;
/** Define the config key of retries threshold when movements failed */
//made package private for testing
static final String FAILED_MOVE_MAX_RETRY = "hbase.rsgroup.move.max.retry";
/** Define the default number of retries */
//made package private for testing
static final int DEFAULT_MAX_RETRY_VALUE = 50;
private int moveMaxRetry;
public RSGroupAdminServer(MasterServices master, RSGroupInfoManager rsGroupInfoManager) {
this.master = master;
this.rsGroupInfoManager = rsGroupInfoManager;
this.moveMaxRetry = master.getConfiguration().getInt(FAILED_MOVE_MAX_RETRY,
DEFAULT_MAX_RETRY_VALUE);
}
@Override
public RSGroupInfo getRSGroupInfo(String groupName) throws IOException {
return rsGroupInfoManager.getRSGroup(groupName);
}
private void checkOnlineServersOnly(Set<Address> servers) throws ConstraintException {
// This uglyness is because we only have Address, not ServerName.
// Online servers are keyed by ServerName.
Set<Address> onlineServers = new HashSet<>();
for(ServerName server: master.getServerManager().getOnlineServers().keySet()) {
onlineServers.add(server.getAddress());
}
for (Address address: servers) {
if (!onlineServers.contains(address)) {
throw new ConstraintException(
"Server " + address + " is not an online server in 'default' RSGroup.");
}
}
}
/**
* Check passed name. Fail if nulls or if corresponding RSGroupInfo not found.
* @return The RSGroupInfo named <code>name</code>
*/
private RSGroupInfo getAndCheckRSGroupInfo(String name) throws IOException {
if (StringUtils.isEmpty(name)) {
throw new ConstraintException("RSGroup cannot be null.");
}
RSGroupInfo rsGroupInfo = getRSGroupInfo(name);
if (rsGroupInfo == null) {
throw new ConstraintException("RSGroup does not exist: " + name);
}
return rsGroupInfo;
}
/**
* @return List of Regions associated with this <code>server</code>.
*/
private List<RegionInfo> getRegions(final Address server) {
LinkedList<RegionInfo> regions = new LinkedList<>();
for (Map.Entry<RegionInfo, ServerName> el :
master.getAssignmentManager().getRegionStates().getRegionAssignments().entrySet()) {
if (el.getValue() == null) {
continue;
}
if (el.getValue().getAddress().equals(server)) {
addRegion(regions, el.getKey());
}
}
for (RegionStateNode state : master.getAssignmentManager().getRegionsInTransition()) {
if (state.getRegionLocation() != null &&
state.getRegionLocation().getAddress().equals(server)) {
addRegion(regions, state.getRegionInfo());
}
}
return regions;
}
private void addRegion(final LinkedList<RegionInfo> regions, RegionInfo hri) {
// If meta, move it last otherwise other unassigns fail because meta is not
// online for them to update state in. This is dodgy. Needs to be made more
// robust. See TODO below.
if (hri.isMetaRegion()) {
regions.addLast(hri);
} else {
regions.addFirst(hri);
}
}
/**
* Move every region from servers which are currently located on these servers, but should not be
* located there.
* @param servers the servers that will move to new group
* @param targetGroupName the target group name
* @throws IOException if moving the server and tables fail
*/
private void moveServerRegionsFromGroup(Set<Address> servers, String targetGroupName)
throws IOException {
moveRegionsBetweenGroups(servers, targetGroupName, rs -> getRegions(rs), info -> {
try {
String groupName = RSGroupUtil.getRSGroupInfo(master, rsGroupInfoManager, info.getTable())
.map(RSGroupInfo::getName).orElse(RSGroupInfo.DEFAULT_GROUP);
return groupName.equals(targetGroupName);
} catch (IOException e) {
LOG.warn("Failed to test group for region {} and target group {}", info, targetGroupName);
return false;
}
}, rs -> rs.getHostname());
}
private <T> void moveRegionsBetweenGroups(Set<T> regionsOwners, String targetGroupName,
Function<T, List<RegionInfo>> getRegionsInfo, Function<RegionInfo, Boolean> validation,
Function<T, String> getOwnerName) throws IOException {
boolean hasRegionsToMove;
int retry = 0;
Set<T> allOwners = new HashSet<>(regionsOwners);
Set<String> failedRegions = new HashSet<>();
IOException toThrow = null;
do {
hasRegionsToMove = false;
for (Iterator<T> iter = allOwners.iterator(); iter.hasNext(); ) {
T owner = iter.next();
// Get regions that are associated with this server and filter regions by group tables.
for (RegionInfo region : getRegionsInfo.apply(owner)) {
if (!validation.apply(region)) {
LOG.info("Moving region {}, which do not belong to RSGroup {}",
region.getShortNameToLog(), targetGroupName);
try {
this.master.getAssignmentManager().move(region);
failedRegions.remove(region.getRegionNameAsString());
} catch (IOException ioe) {
LOG.debug("Move region {} from group failed, will retry, current retry time is {}",
region.getShortNameToLog(), retry, ioe);
toThrow = ioe;
failedRegions.add(region.getRegionNameAsString());
}
if (master.getAssignmentManager().getRegionStates().
getRegionState(region).isFailedOpen()) {
continue;
}
hasRegionsToMove = true;
}
}
if (!hasRegionsToMove) {
LOG.info("No more regions to move from {} to RSGroup {}", getOwnerName.apply(owner),
targetGroupName);
iter.remove();
}
}
retry++;
try {
rsGroupInfoManager.wait(1000);
} catch (InterruptedException e) {
LOG.warn("Sleep interrupted", e);
Thread.currentThread().interrupt();
}
} while (hasRegionsToMove && retry <= moveMaxRetry);
//has up to max retry time or there are no more regions to move
if (hasRegionsToMove) {
// print failed moved regions, for later process conveniently
String msg = String
.format("move regions for group %s failed, failed regions: %s", targetGroupName,
failedRegions);
LOG.error(msg);
throw new DoNotRetryIOException(
msg + ", just record the last failed region's cause, more details in server log",
toThrow);
}
}
@Override
public void moveServers(Set<Address> servers, String targetGroupName) throws IOException {
if (servers == null) {
throw new ConstraintException("The list of servers to move cannot be null.");
}
if (servers.isEmpty()) {
// For some reason this difference between null servers and isEmpty is important distinction.
// TODO. Why? Stuff breaks if I equate them.
return;
}
//check target group
getAndCheckRSGroupInfo(targetGroupName);
// Hold a lock on the manager instance while moving servers to prevent
// another writer changing our state while we are working.
synchronized (rsGroupInfoManager) {
// Presume first server's source group. Later ensure all servers are from this group.
Address firstServer = servers.iterator().next();
RSGroupInfo srcGrp = rsGroupInfoManager.getRSGroupOfServer(firstServer);
if (srcGrp == null) {
// Be careful. This exception message is tested for in TestRSGroupsBase...
throw new ConstraintException("Source RSGroup for server " + firstServer
+ " does not exist.");
}
// Only move online servers (when moving from 'default') or servers from other
// groups. This prevents bogus servers from entering groups
if (RSGroupInfo.DEFAULT_GROUP.equals(srcGrp.getName())) {
if (srcGrp.getServers().size() <= servers.size()) {
throw new ConstraintException(KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE);
}
checkOnlineServersOnly(servers);
}
// Ensure all servers are of same rsgroup.
for (Address server: servers) {
String tmpGroup = rsGroupInfoManager.getRSGroupOfServer(server).getName();
if (!tmpGroup.equals(srcGrp.getName())) {
throw new ConstraintException("Move server request should only come from one source " +
"RSGroup. Expecting only " + srcGrp.getName() + " but contains " + tmpGroup);
}
}
if (srcGrp.getServers().size() <= servers.size()) {
// check if there are still tables reference this group
for (TableDescriptor td : master.getTableDescriptors().getAll().values()) {
Optional<String> optGroupName = td.getRegionServerGroup();
if (optGroupName.isPresent() && optGroupName.get().equals(srcGrp.getName())) {
throw new ConstraintException(
"Cannot leave a RSGroup " + srcGrp.getName() + " that contains tables('" +
td.getTableName() + "' at least) without servers to host them.");
}
}
}
// MovedServers may be < passed in 'servers'.
Set<Address> movedServers = rsGroupInfoManager.moveServers(servers, srcGrp.getName(),
targetGroupName);
moveServerRegionsFromGroup(movedServers, targetGroupName);
LOG.info("Move servers done: {} => {}", srcGrp.getName(), targetGroupName);
}
}
@Override
public void addRSGroup(String name) throws IOException {
rsGroupInfoManager.addRSGroup(new RSGroupInfo(name));
}
@Override
public void removeRSGroup(String name) throws IOException {
// Hold a lock on the manager instance while moving servers to prevent
// another writer changing our state while we are working.
synchronized (rsGroupInfoManager) {
RSGroupInfo rsGroupInfo = rsGroupInfoManager.getRSGroup(name);
if (rsGroupInfo == null) {
throw new ConstraintException("RSGroup " + name + " does not exist");
}
int serverCount = rsGroupInfo.getServers().size();
if (serverCount > 0) {
throw new ConstraintException("RSGroup " + name + " has " + serverCount +
" servers; you must remove these servers from the RSGroup before" +
" the RSGroup can be removed.");
}
for (TableDescriptor td : master.getTableDescriptors().getAll().values()) {
if (td.getRegionServerGroup().map(name::equals).orElse(false)) {
throw new ConstraintException("RSGroup " + name + " is already referenced by " +
td.getTableName() + "; you must remove all the tables from the rsgroup before " +
"the rsgroup can be removed.");
}
}
for (NamespaceDescriptor ns : master.getClusterSchema().getNamespaces()) {
String nsGroup = ns.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
if (nsGroup != null && nsGroup.equals(name)) {
throw new ConstraintException(
"RSGroup " + name + " is referenced by namespace: " + ns.getName());
}
}
rsGroupInfoManager.removeRSGroup(name);
}
}
@Override
public boolean balanceRSGroup(String groupName) throws IOException {
ServerManager serverManager = master.getServerManager();
LoadBalancer balancer = master.getLoadBalancer();
synchronized (balancer) {
// If balance not true, don't run balancer.
if (!((HMaster) master).isBalancerOn()) {
return false;
}
if (getRSGroupInfo(groupName) == null) {
throw new ConstraintException("RSGroup does not exist: " + groupName);
}
// Only allow one balance run at at time.
Map<String, RegionState> groupRIT = rsGroupGetRegionsInTransition(groupName);
if (groupRIT.size() > 0) {
LOG.debug("Not running balancer because {} region(s) in transition: {}", groupRIT.size(),
StringUtils.abbreviate(
master.getAssignmentManager().getRegionStates().getRegionsInTransition().toString(),
256));
return false;
}
if (serverManager.areDeadServersInProgress()) {
LOG.debug("Not running balancer because processing dead regionserver(s): {}",
serverManager.getDeadServers());
return false;
}
// We balance per group instead of per table
List<RegionPlan> plans = new ArrayList<>();
Map<TableName, Map<ServerName, List<RegionInfo>>> assignmentsByTable =
getRSGroupAssignmentsByTable(groupName);
for (Map.Entry<TableName, Map<ServerName, List<RegionInfo>>> tableMap : assignmentsByTable
.entrySet()) {
LOG.info("Creating partial plan for table {} : {}", tableMap.getKey(), tableMap.getValue());
List<RegionPlan> partialPlans = balancer.balanceCluster(tableMap.getValue());
LOG.info("Partial plan for table {} : {}", tableMap.getKey(), partialPlans);
if (partialPlans != null) {
plans.addAll(partialPlans);
}
}
boolean balancerRan = !plans.isEmpty();
if (balancerRan) {
LOG.info("RSGroup balance {} starting with plan count: {}", groupName, plans.size());
master.executeRegionPlansWithThrottling(plans);
LOG.info("RSGroup balance " + groupName + " completed");
}
return balancerRan;
}
}
@Override
public List<RSGroupInfo> listRSGroups() throws IOException {
return rsGroupInfoManager.listRSGroups();
}
@Override
public RSGroupInfo getRSGroupOfServer(Address hostPort) throws IOException {
return rsGroupInfoManager.getRSGroupOfServer(hostPort);
}
@Override
public void removeServers(Set<Address> servers) throws IOException {
if (servers == null || servers.isEmpty()) {
throw new ConstraintException("The set of servers to remove cannot be null or empty.");
}
// Hold a lock on the manager instance while moving servers to prevent
// another writer changing our state while we are working.
synchronized (rsGroupInfoManager) {
// check the set of servers
checkForDeadOrOnlineServers(servers);
rsGroupInfoManager.removeServers(servers);
LOG.info("Remove decommissioned servers {} from RSGroup done", servers);
}
}
private boolean isTableInGroup(TableName tableName, String groupName,
Set<TableName> tablesInGroupCache) throws IOException {
if (tablesInGroupCache.contains(tableName)) {
return true;
}
if (RSGroupUtil.getRSGroupInfo(master, rsGroupInfoManager, tableName).map(RSGroupInfo::getName)
.orElse(RSGroupInfo.DEFAULT_GROUP).equals(groupName)) {
tablesInGroupCache.add(tableName);
return true;
}
return false;
}
private Map<String, RegionState> rsGroupGetRegionsInTransition(String groupName)
throws IOException {
Map<String, RegionState> rit = Maps.newTreeMap();
Set<TableName> tablesInGroupCache = new HashSet<>();
for (RegionStateNode regionNode : master.getAssignmentManager().getRegionsInTransition()) {
TableName tn = regionNode.getTable();
if (isTableInGroup(tn, groupName, tablesInGroupCache)) {
rit.put(regionNode.getRegionInfo().getEncodedName(), regionNode.toRegionState());
}
}
return rit;
}
private Map<TableName, Map<ServerName, List<RegionInfo>>>
getRSGroupAssignmentsByTable(String groupName) throws IOException {
Map<TableName, Map<ServerName, List<RegionInfo>>> result = Maps.newHashMap();
Set<TableName> tablesInGroupCache = new HashSet<>();
for (Map.Entry<RegionInfo, ServerName> entry : master.getAssignmentManager().getRegionStates()
.getRegionAssignments().entrySet()) {
RegionInfo region = entry.getKey();
TableName tn = region.getTable();
ServerName server = entry.getValue();
if (isTableInGroup(tn, groupName, tablesInGroupCache)) {
result.computeIfAbsent(tn, k -> new HashMap<>())
.computeIfAbsent(server, k -> new ArrayList<>()).add(region);
}
}
RSGroupInfo rsGroupInfo = getRSGroupInfo(groupName);
for (ServerName serverName : master.getServerManager().getOnlineServers().keySet()) {
if (rsGroupInfo.containsServer(serverName.getAddress())) {
for (Map<ServerName, List<RegionInfo>> map : result.values()) {
map.computeIfAbsent(serverName, k -> Collections.emptyList());
}
}
}
return result;
}
/**
* Check if the set of servers are belong to dead servers list or online servers list.
* @param servers servers to remove
*/
private void checkForDeadOrOnlineServers(Set<Address> servers) throws ConstraintException {
// This uglyness is because we only have Address, not ServerName.
Set<Address> onlineServers = new HashSet<>();
List<ServerName> drainingServers = master.getServerManager().getDrainingServersList();
for (ServerName server : master.getServerManager().getOnlineServers().keySet()) {
// Only online but not decommissioned servers are really online
if (!drainingServers.contains(server)) {
onlineServers.add(server.getAddress());
}
}
Set<Address> deadServers = new HashSet<>();
for(ServerName server: master.getServerManager().getDeadServers().copyServerNames()) {
deadServers.add(server.getAddress());
}
for (Address address: servers) {
if (onlineServers.contains(address)) {
throw new ConstraintException(
"Server " + address + " is an online server, not allowed to remove.");
}
if (deadServers.contains(address)) {
throw new ConstraintException(
"Server " + address + " is on the dead servers list,"
+ " Maybe it will come back again, not allowed to remove.");
}
}
}
}

View File

@ -33,7 +33,6 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
import org.apache.hadoop.hbase.ipc.RpcServer;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.master.procedure.ProcedureSyncWait;
import org.apache.hadoop.hbase.net.Address;
@ -63,62 +62,34 @@ import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGro
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveRSGroupResponse;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersRequest;
import org.apache.hadoop.hbase.protobuf.generated.RSGroupAdminProtos.RemoveServersResponse;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.UserProvider;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.hadoop.hbase.security.access.Permission.Action;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
/**
* Implementation of RSGroupAdminService defined in RSGroupAdmin.proto. This class calls
* {@link RSGroupAdminServer} for actual work, converts result to protocol buffer response, handles
* exceptions if any occurred and then calls the {@code RpcCallback} with the response.
* {@link RSGroupInfoManagerImpl} for actual work, converts result to protocol buffer response,
* handles exceptions if any occurred and then calls the {@code RpcCallback} with the response.
*
* @deprecated Keep it here only for compatibility with {@link RSGroupAdminClient},
* using {@link org.apache.hadoop.hbase.master.MasterRpcServices} instead.
*/
@Deprecated
class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
private static final Logger LOG = LoggerFactory.getLogger(RSGroupAdminServiceImpl.class);
private MasterServices master;
private RSGroupAdminServer groupAdminServer;
private AccessChecker accessChecker;
/** Provider for mapping principal names to Users */
private UserProvider userProvider;
private RSGroupInfoManager rsGroupInfoManager;
RSGroupAdminServiceImpl() {
}
void initialize(MasterServices master, RSGroupAdminServer groupAdminServer,
AccessChecker accessChecker, UserProvider userProvider) {
this.master = master;
this.groupAdminServer = groupAdminServer;
this.accessChecker = accessChecker;
this.userProvider = userProvider;
}
@VisibleForTesting
void checkPermission(String request) throws IOException {
accessChecker.requirePermission(getActiveUser(), request, null, Action.ADMIN);
}
/**
* Returns the active user to which authorization checks should be applied. If we are in the
* context of an RPC call, the remote user is used, otherwise the currently logged in user is
* used.
*/
private User getActiveUser() throws IOException {
// for non-rpc handling, fallback to system user
Optional<User> optionalUser = RpcServer.getRequestUser();
if (optionalUser.isPresent()) {
return optionalUser.get();
}
return userProvider.getCurrent();
void initialize(MasterServices masterServices){
this.master = masterServices;
this.rsGroupInfoManager = masterServices.getRSGroupInfoManager();
}
// for backward compatible
@ -137,8 +108,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preGetRSGroupInfo(groupName);
}
checkPermission("getRSGroupInfo");
RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName);
RSGroupInfo rsGroupInfo = rsGroupInfoManager.getRSGroup(groupName);
if (rsGroupInfo != null) {
builder.setRSGroupInfo(ProtobufUtil.toProtoGroupInfo(fillTables(rsGroupInfo)));
}
@ -162,14 +132,13 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preGetRSGroupInfoOfTable(tableName);
}
checkPermission("getRSGroupInfoOfTable");
Optional<RSGroupInfo> optGroup =
RSGroupUtil.getRSGroupInfo(master, groupAdminServer.rsGroupInfoManager, tableName);
RSGroupUtil.getRSGroupInfo(master, rsGroupInfoManager, tableName);
if (optGroup.isPresent()) {
builder.setRSGroupInfo(ProtobufUtil.toProtoGroupInfo(fillTables(optGroup.get())));
} else {
if (master.getTableStateManager().isTablePresent(tableName)) {
RSGroupInfo rsGroupInfo = groupAdminServer.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
RSGroupInfo rsGroupInfo = rsGroupInfoManager.getRSGroup(RSGroupInfo.DEFAULT_GROUP);
builder.setRSGroupInfo(ProtobufUtil.toProtoGroupInfo(fillTables(rsGroupInfo)));
}
}
@ -197,8 +166,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preMoveServers(hostPorts, request.getTargetGroup());
}
checkPermission("moveServers");
groupAdminServer.moveServers(hostPorts, request.getTargetGroup());
rsGroupInfoManager.moveServers(hostPorts, request.getTargetGroup());
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postMoveServers(hostPorts, request.getTargetGroup());
}
@ -243,7 +211,6 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preMoveTables(tables, request.getTargetGroup());
}
checkPermission("moveTables");
moveTablesAndWait(tables, request.getTargetGroup());
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postMoveTables(tables, request.getTargetGroup());
@ -263,8 +230,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preAddRSGroup(request.getRSGroupName());
}
checkPermission("addRSGroup");
groupAdminServer.addRSGroup(request.getRSGroupName());
rsGroupInfoManager.addRSGroup(new RSGroupInfo(request.getRSGroupName()));
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postAddRSGroup(request.getRSGroupName());
}
@ -283,8 +249,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preRemoveRSGroup(request.getRSGroupName());
}
checkPermission("removeRSGroup");
groupAdminServer.removeRSGroup(request.getRSGroupName());
rsGroupInfoManager.removeRSGroup(request.getRSGroupName());
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postRemoveRSGroup(request.getRSGroupName());
}
@ -304,8 +269,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preBalanceRSGroup(request.getRSGroupName());
}
checkPermission("balanceRSGroup");
boolean balancerRan = groupAdminServer.balanceRSGroup(request.getRSGroupName());
boolean balancerRan = rsGroupInfoManager.balanceRSGroup(request.getRSGroupName());
builder.setBalanceRan(balancerRan);
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postBalanceRSGroup(request.getRSGroupName(), balancerRan);
@ -326,8 +290,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preListRSGroups();
}
checkPermission("listRSGroup");
List<RSGroupInfo> rsGroupInfos = groupAdminServer.listRSGroups().stream()
List<RSGroupInfo> rsGroupInfos = rsGroupInfoManager.listRSGroups().stream()
.map(RSGroupInfo::new).collect(Collectors.toList());
Map<String, RSGroupInfo> name2Info = new HashMap<>();
for (RSGroupInfo rsGroupInfo : rsGroupInfos) {
@ -364,8 +327,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preGetRSGroupInfoOfServer(hp);
}
checkPermission("getRSGroupInfoOfServer");
RSGroupInfo info = groupAdminServer.getRSGroupOfServer(hp);
RSGroupInfo info = rsGroupInfoManager.getRSGroupOfServer(hp);
if (info != null) {
builder.setRSGroupInfo(ProtobufUtil.toProtoGroupInfo(fillTables(info)));
}
@ -397,8 +359,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
master.getMasterCoprocessorHost().preMoveServersAndTables(hostPorts, tables,
request.getTargetGroup());
}
checkPermission("moveServersAndTables");
groupAdminServer.moveServers(hostPorts, request.getTargetGroup());
rsGroupInfoManager.moveServers(hostPorts, request.getTargetGroup());
moveTablesAndWait(tables, request.getTargetGroup());
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postMoveServersAndTables(hostPorts, tables,
@ -424,8 +385,7 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().preRemoveServers(servers);
}
checkPermission("removeServers");
groupAdminServer.removeServers(servers);
rsGroupInfoManager.removeServers(servers);
if (master.getMasterCoprocessorHost() != null) {
master.getMasterCoprocessorHost().postRemoveServers(servers);
}
@ -434,4 +394,5 @@ class RSGroupAdminServiceImpl extends RSGroupAdminProtos.RSGroupAdminService {
}
done.run(builder.build());
}
}

View File

@ -48,13 +48,8 @@ public interface RSGroupInfoManager {
/**
* Move servers to a new group.
* @param servers list of servers, must be part of the same group
* @param srcGroup groupName being moved from
* @param dstGroup groupName being moved to
* @return Set of servers moved (May be a subset of {@code servers}).
*/
Set<Address> moveServers(Set<Address> servers, String srcGroup, String dstGroup)
throws IOException;
void moveServers(Set<Address> servers, String targetGroupName) throws IOException;
/**
* Gets the group info of server.
@ -85,10 +80,7 @@ public interface RSGroupInfoManager {
/**
* Get {@code RSGroupInfo} for the given table.
* @deprecated Since 3.0.0, will be removed in 4.0.0. Only for compatibility, where we upgrade
* from a version that stores table names for a rs group in the {@code RSGroupInfo}.
*/
@Deprecated
RSGroupInfo getRSGroupForTable(TableName tableName) throws IOException;
static RSGroupInfoManager create(MasterServices master) throws IOException {
@ -98,4 +90,14 @@ public interface RSGroupInfoManager {
return new DisabledRSGroupInfoManager(master.getServerManager());
}
}
/**
* Balance a region server group.
*/
boolean balanceRSGroup(String groupName) throws IOException;
/**
* Set group for tables.
*/
void setRSGroup(Set<TableName> tables, String groupName) throws IOException;
}

View File

@ -24,15 +24,21 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableDescriptors;
@ -45,6 +51,7 @@ import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.TableDescriptor;
@ -52,11 +59,17 @@ import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.constraint.ConstraintException;
import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.LoadBalancer;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.master.RegionPlan;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.master.ServerListener;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.master.TableStateManager;
import org.apache.hadoop.hbase.master.assignment.RegionStateNode;
import org.apache.hadoop.hbase.master.procedure.CreateTableProcedure;
import org.apache.hadoop.hbase.master.procedure.MasterProcedureUtil;
import org.apache.hadoop.hbase.master.procedure.ProcedureSyncWait;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.procedure2.Procedure;
import org.apache.hadoop.hbase.protobuf.ProtobufMagic;
@ -83,15 +96,13 @@ import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
/**
* This is an implementation of {@link RSGroupInfoManager} which makes use of an HBase table as the
* persistence store for the group information. It also makes use of zookeeper to store group
* information needed for bootstrapping during offline mode.
* <h2>Concurrency</h2> RSGroup state is kept locally in Maps. There is a rsgroup name to cached
* RSGroupInfo Map at {@link #rsGroupMap} and a Map of tables to the name of the rsgroup they belong
* too (in {@link #tableMap}). These Maps are persisted to the hbase:rsgroup table (and cached in
* zk) on each modification.
* RSGroupInfo Map at {@link #rsGroupMap}. These Maps are persisted to the hbase:rsgroup table
* (and cached in zk) on each modification.
* <p/>
* Mutations on state are synchronized but reads can continue without having to wait on an instance
* monitor, mutations do wholesale replace of the Maps on update -- Copy-On-Write; the local Maps of
@ -113,6 +124,18 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
static final TableName RSGROUP_TABLE_NAME =
TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "rsgroup");
@VisibleForTesting
static final String KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE = "should keep at least " +
"one server in 'default' RSGroup.";
/** Define the config key of retries threshold when movements failed */
@VisibleForTesting
static final String FAILED_MOVE_MAX_RETRY = "hbase.rsgroup.move.max.retry";
/** Define the default number of retries */
@VisibleForTesting
static final int DEFAULT_MAX_RETRY_VALUE = 50;
private static final String RS_GROUP_ZNODE = "rsgroup";
@VisibleForTesting
@ -176,7 +199,7 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
// contains list of groups that were last flushed to persistent store
private Set<String> prevRSGroups = new HashSet<>();
private RSGroupInfoManagerImpl(MasterServices masterServices) throws IOException {
private RSGroupInfoManagerImpl(MasterServices masterServices) {
this.masterServices = masterServices;
this.watcher = masterServices.getZooKeeper();
this.conn = masterServices.getAsyncClusterConnection();
@ -214,8 +237,8 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
migrate();
}
static RSGroupInfoManager getInstance(MasterServices master) throws IOException {
RSGroupInfoManagerImpl instance = new RSGroupInfoManagerImpl(master);
static RSGroupInfoManager getInstance(MasterServices masterServices) throws IOException {
RSGroupInfoManagerImpl instance = new RSGroupInfoManagerImpl(masterServices);
instance.init();
return instance;
}
@ -231,17 +254,17 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
Map<String, RSGroupInfo> rsGroupMap = holder.groupName2Group;
if (rsGroupMap.get(rsGroupInfo.getName()) != null ||
rsGroupInfo.getName().equals(RSGroupInfo.DEFAULT_GROUP)) {
throw new DoNotRetryIOException("Group already exists: " + rsGroupInfo.getName());
throw new ConstraintException("Group already exists: " + rsGroupInfo.getName());
}
Map<String, RSGroupInfo> newGroupMap = Maps.newHashMap(rsGroupMap);
newGroupMap.put(rsGroupInfo.getName(), rsGroupInfo);
flushConfig(newGroupMap);
}
private RSGroupInfo getRSGroupInfo(final String groupName) throws DoNotRetryIOException {
RSGroupInfo rsGroupInfo = getRSGroup(groupName);
private RSGroupInfo getRSGroupInfo(final String groupName) throws ConstraintException {
RSGroupInfo rsGroupInfo = holder.groupName2Group.get(groupName);
if (rsGroupInfo == null) {
throw new DoNotRetryIOException("RSGroup " + groupName + " does not exist");
throw new ConstraintException("RSGroup " + groupName + " does not exist");
}
return rsGroupInfo;
}
@ -254,7 +277,6 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
.map(ServerName::getAddress).collect(Collectors.toSet());
}
@Override
public synchronized Set<Address> moveServers(Set<Address> servers, String srcGroup,
String dstGroup) throws IOException {
RSGroupInfo src = getRSGroupInfo(srcGroup);
@ -284,7 +306,7 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
}
@Override
public RSGroupInfo getRSGroupOfServer(Address serverHostPort) throws IOException {
public RSGroupInfo getRSGroupOfServer(Address serverHostPort) {
for (RSGroupInfo info : holder.groupName2Group.values()) {
if (info.containsServer(serverHostPort)) {
return info;
@ -300,9 +322,30 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
@Override
public synchronized void removeRSGroup(String groupName) throws IOException {
RSGroupInfo rsGroupInfo = getRSGroupInfo(groupName);
int serverCount = rsGroupInfo.getServers().size();
if (serverCount > 0) {
throw new ConstraintException("RSGroup " + groupName + " has " + serverCount +
" servers; you must remove these servers from the RSGroup before" +
" the RSGroup can be removed.");
}
for (TableDescriptor td : masterServices.getTableDescriptors().getAll().values()) {
if (td.getRegionServerGroup().map(groupName::equals).orElse(false)) {
throw new ConstraintException("RSGroup " + groupName + " is already referenced by " +
td.getTableName() + "; you must remove all the tables from the rsgroup before " +
"the rsgroup can be removed.");
}
}
for (NamespaceDescriptor ns : masterServices.getClusterSchema().getNamespaces()) {
String nsGroup = ns.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP);
if (nsGroup != null && nsGroup.equals(groupName)) {
throw new ConstraintException(
"RSGroup " + groupName + " is referenced by namespace: " + ns.getName());
}
}
Map<String, RSGroupInfo> rsGroupMap = holder.groupName2Group;
if (!rsGroupMap.containsKey(groupName) || groupName.equals(RSGroupInfo.DEFAULT_GROUP)) {
throw new DoNotRetryIOException(
throw new ConstraintException(
"Group " + groupName + " does not exist or is a reserved " + "group");
}
Map<String, RSGroupInfo> newGroupMap = Maps.newHashMap(rsGroupMap);
@ -322,6 +365,13 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
@Override
public synchronized void removeServers(Set<Address> servers) throws IOException {
if (servers == null || servers.isEmpty()) {
throw new ConstraintException("The set of servers to remove cannot be null or empty.");
}
// check the set of servers
checkForDeadOrOnlineServers(servers);
Map<String, RSGroupInfo> rsGroupInfos = new HashMap<String, RSGroupInfo>();
for (Address el : servers) {
RSGroupInfo rsGroupInfo = getRSGroupOfServer(el);
@ -344,6 +394,7 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
newGroupMap.putAll(rsGroupInfos);
flushConfig(newGroupMap);
}
LOG.info("Remove decommissioned servers {} from RSGroup done", servers);
}
private List<RSGroupInfo> retrieveGroupListFromGroupTable() throws IOException {
@ -575,7 +626,6 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
// Make changes visible after having been persisted to the source of truth
resetRSGroupMap(newGroupMap);
saveRSGroupMapToZK(newGroupMap);
updateCacheOfRSGroups(newGroupMap.keySet());
}
@ -764,9 +814,371 @@ final class RSGroupInfoManagerImpl implements RSGroupInfoManager {
}
}
@Override
public RSGroupInfo getRSGroupForTable(TableName tableName) throws IOException {
return holder.tableName2Group.get(tableName);
}
/**
* Check if the set of servers are belong to dead servers list or online servers list.
* @param servers servers to remove
*/
private void checkForDeadOrOnlineServers(Set<Address> servers) throws IOException {
// This uglyness is because we only have Address, not ServerName.
Set<Address> onlineServers = new HashSet<>();
List<ServerName> drainingServers = masterServices.getServerManager().getDrainingServersList();
for (ServerName server : masterServices.getServerManager().getOnlineServers().keySet()) {
// Only online but not decommissioned servers are really online
if (!drainingServers.contains(server)) {
onlineServers.add(server.getAddress());
}
}
Set<Address> deadServers = new HashSet<>();
for(ServerName server: masterServices.getServerManager().getDeadServers().copyServerNames()) {
deadServers.add(server.getAddress());
}
for (Address address: servers) {
if (onlineServers.contains(address)) {
throw new DoNotRetryIOException(
"Server " + address + " is an online server, not allowed to remove.");
}
if (deadServers.contains(address)) {
throw new DoNotRetryIOException(
"Server " + address + " is on the dead servers list,"
+ " Maybe it will come back again, not allowed to remove.");
}
}
}
private void checkOnlineServersOnly(Set<Address> servers) throws IOException {
// This uglyness is because we only have Address, not ServerName.
// Online servers are keyed by ServerName.
Set<Address> onlineServers = new HashSet<>();
for(ServerName server: masterServices.getServerManager().getOnlineServers().keySet()) {
onlineServers.add(server.getAddress());
}
for (Address address: servers) {
if (!onlineServers.contains(address)) {
throw new DoNotRetryIOException("Server " + address +
" is not an online server in 'default' RSGroup.");
}
}
}
/**
* @return List of Regions associated with this <code>server</code>.
*/
private List<RegionInfo> getRegions(final Address server) {
LinkedList<RegionInfo> regions = new LinkedList<>();
for (Map.Entry<RegionInfo, ServerName> el :
masterServices.getAssignmentManager().getRegionStates().getRegionAssignments().entrySet()) {
if (el.getValue() == null) {
continue;
}
if (el.getValue().getAddress().equals(server)) {
addRegion(regions, el.getKey());
}
}
for (RegionStateNode state : masterServices.getAssignmentManager().getRegionsInTransition()) {
if (state.getRegionLocation() != null &&
state.getRegionLocation().getAddress().equals(server)) {
addRegion(regions, state.getRegionInfo());
}
}
return regions;
}
private void addRegion(final LinkedList<RegionInfo> regions, RegionInfo hri) {
// If meta, move it last otherwise other unassigns fail because meta is not
// online for them to update state in. This is dodgy. Needs to be made more
// robust. See TODO below.
if (hri.isMetaRegion()) {
regions.addLast(hri);
} else {
regions.addFirst(hri);
}
}
/**
* Move every region from servers which are currently located on these servers, but should not be
* located there.
* @param servers the servers that will move to new group
* @param targetGroupName the target group name
* @throws IOException if moving the server and tables fail
*/
private void moveServerRegionsFromGroup(Set<Address> servers, String targetGroupName)
throws IOException {
moveRegionsBetweenGroups(servers, targetGroupName, rs -> getRegions(rs), info -> {
try {
String groupName = RSGroupUtil.getRSGroupInfo(masterServices, this, info.getTable())
.map(RSGroupInfo::getName).orElse(RSGroupInfo.DEFAULT_GROUP);
return groupName.equals(targetGroupName);
} catch (IOException e) {
LOG.warn("Failed to test group for region {} and target group {}", info, targetGroupName);
return false;
}
}, rs -> rs.getHostname());
}
private <T> void moveRegionsBetweenGroups(Set<T> regionsOwners, String targetGroupName,
Function<T, List<RegionInfo>> getRegionsInfo, Function<RegionInfo, Boolean> validation,
Function<T, String> getOwnerName) throws IOException {
boolean hasRegionsToMove;
int retry = 0;
Set<T> allOwners = new HashSet<>(regionsOwners);
Set<String> failedRegions = new HashSet<>();
IOException toThrow = null;
do {
hasRegionsToMove = false;
for (Iterator<T> iter = allOwners.iterator(); iter.hasNext(); ) {
T owner = iter.next();
// Get regions that are associated with this server and filter regions by group tables.
for (RegionInfo region : getRegionsInfo.apply(owner)) {
if (!validation.apply(region)) {
LOG.info("Moving region {}, which do not belong to RSGroup {}",
region.getShortNameToLog(), targetGroupName);
try {
this.masterServices.getAssignmentManager().move(region);
failedRegions.remove(region.getRegionNameAsString());
} catch (IOException ioe) {
LOG.debug("Move region {} from group failed, will retry, current retry time is {}",
region.getShortNameToLog(), retry, ioe);
toThrow = ioe;
failedRegions.add(region.getRegionNameAsString());
}
if (masterServices.getAssignmentManager().getRegionStates().
getRegionState(region).isFailedOpen()) {
continue;
}
hasRegionsToMove = true;
}
}
if (!hasRegionsToMove) {
LOG.info("No more regions to move from {} to RSGroup", getOwnerName.apply(owner));
iter.remove();
}
}
retry++;
try {
wait(1000);
} catch (InterruptedException e) {
LOG.warn("Sleep interrupted", e);
Thread.currentThread().interrupt();
}
} while (hasRegionsToMove && retry <=
masterServices.getConfiguration().getInt(FAILED_MOVE_MAX_RETRY, DEFAULT_MAX_RETRY_VALUE));
//has up to max retry time or there are no more regions to move
if (hasRegionsToMove) {
// print failed moved regions, for later process conveniently
String msg = String
.format("move regions for group %s failed, failed regions: %s", targetGroupName,
failedRegions);
LOG.error(msg);
throw new DoNotRetryIOException(
msg + ", just record the last failed region's cause, more details in server log",
toThrow);
}
}
private boolean isTableInGroup(TableName tableName, String groupName,
Set<TableName> tablesInGroupCache) throws IOException {
if (tablesInGroupCache.contains(tableName)) {
return true;
}
if (RSGroupUtil.getRSGroupInfo(masterServices, this, tableName)
.map(RSGroupInfo::getName)
.orElse(RSGroupInfo.DEFAULT_GROUP).equals(groupName)) {
tablesInGroupCache.add(tableName);
return true;
}
return false;
}
private Map<String, RegionState> rsGroupGetRegionsInTransition(String groupName)
throws IOException {
Map<String, RegionState> rit = Maps.newTreeMap();
Set<TableName> tablesInGroupCache = new HashSet<>();
for (RegionStateNode regionNode :
masterServices.getAssignmentManager().getRegionsInTransition()) {
TableName tn = regionNode.getTable();
if (isTableInGroup(tn, groupName, tablesInGroupCache)) {
rit.put(regionNode.getRegionInfo().getEncodedName(), regionNode.toRegionState());
}
}
return rit;
}
private Map<TableName, Map<ServerName, List<RegionInfo>>> getRSGroupAssignmentsByTable(
String groupName) throws IOException {
Map<TableName, Map<ServerName, List<RegionInfo>>> result = Maps.newHashMap();
Set<TableName> tablesInGroupCache = new HashSet<>();
for (Map.Entry<RegionInfo, ServerName> entry :
masterServices.getAssignmentManager().getRegionStates()
.getRegionAssignments().entrySet()) {
RegionInfo region = entry.getKey();
TableName tn = region.getTable();
ServerName server = entry.getValue();
if (isTableInGroup(tn, groupName, tablesInGroupCache)) {
result.computeIfAbsent(tn, k -> new HashMap<>())
.computeIfAbsent(server, k -> new ArrayList<>()).add(region);
}
}
RSGroupInfo rsGroupInfo = getRSGroupInfo(groupName);
for (ServerName serverName : masterServices.getServerManager().getOnlineServers().keySet()) {
if (rsGroupInfo.containsServer(serverName.getAddress())) {
for (Map<ServerName, List<RegionInfo>> map : result.values()) {
map.computeIfAbsent(serverName, k -> Collections.emptyList());
}
}
}
return result;
}
@Override
public boolean balanceRSGroup(String groupName) throws IOException {
ServerManager serverManager = masterServices.getServerManager();
LoadBalancer balancer = masterServices.getLoadBalancer();
getRSGroupInfo(groupName);
synchronized (balancer) {
// If balance not true, don't run balancer.
if (!masterServices.isBalancerOn()) {
return false;
}
// Only allow one balance run at at time.
Map<String, RegionState> groupRIT = rsGroupGetRegionsInTransition(groupName);
if (groupRIT.size() > 0) {
LOG.debug("Not running balancer because {} region(s) in transition: {}", groupRIT.size(),
StringUtils.abbreviate(masterServices.getAssignmentManager().getRegionStates()
.getRegionsInTransition().toString(),
256));
return false;
}
if (serverManager.areDeadServersInProgress()) {
LOG.debug("Not running balancer because processing dead regionserver(s): {}",
serverManager.getDeadServers());
return false;
}
// We balance per group instead of per table
List<RegionPlan> plans = new ArrayList<>();
Map<TableName, Map<ServerName, List<RegionInfo>>> assignmentsByTable =
getRSGroupAssignmentsByTable(groupName);
for (Map.Entry<TableName, Map<ServerName, List<RegionInfo>>> tableMap : assignmentsByTable
.entrySet()) {
LOG.info("Creating partial plan for table {} : {}", tableMap.getKey(), tableMap.getValue());
List<RegionPlan> partialPlans = balancer.balanceCluster(tableMap.getValue());
LOG.info("Partial plan for table {} : {}", tableMap.getKey(), partialPlans);
if (partialPlans != null) {
plans.addAll(partialPlans);
}
}
boolean balancerRan = !plans.isEmpty();
if (balancerRan) {
LOG.info("RSGroup balance {} starting with plan count: {}", groupName, plans.size());
masterServices.executeRegionPlansWithThrottling(plans);
LOG.info("RSGroup balance " + groupName + " completed");
}
return balancerRan;
}
}
private void moveTablesAndWait(Set<TableName> tables, String targetGroup) throws IOException {
List<Long> procIds = new ArrayList<Long>();
for (TableName tableName : tables) {
TableDescriptor oldTd = masterServices.getTableDescriptors().get(tableName);
if (oldTd == null) {
continue;
}
TableDescriptor newTd =
TableDescriptorBuilder.newBuilder(oldTd).setRegionServerGroup(targetGroup).build();
procIds.add(masterServices.modifyTable(tableName, newTd, HConstants.NO_NONCE,
HConstants.NO_NONCE));
}
for (long procId : procIds) {
Procedure<?> proc = masterServices.getMasterProcedureExecutor().getProcedure(procId);
if (proc == null) {
continue;
}
ProcedureSyncWait.waitForProcedureToCompleteIOE(masterServices.getMasterProcedureExecutor(),
proc, Long.MAX_VALUE);
}
}
@Override
public void setRSGroup(Set<TableName> tables, String groupName) throws IOException {
getRSGroupInfo(groupName);
moveTablesAndWait(tables, groupName);
}
public void moveServers(Set<Address> servers, String targetGroupName) throws IOException {
if (servers == null) {
throw new ConstraintException("The list of servers to move cannot be null.");
}
if (servers.isEmpty()) {
// For some reason this difference between null servers and isEmpty is important distinction.
// TODO. Why? Stuff breaks if I equate them.
return;
}
if (StringUtils.isEmpty(targetGroupName)) {
throw new ConstraintException("RSGroup cannot be null.");
}
getRSGroupInfo(targetGroupName);
// Hold a lock on the manager instance while moving servers to prevent
// another writer changing our state while we are working.
synchronized (this) {
// Presume first server's source group. Later ensure all servers are from this group.
Address firstServer = servers.iterator().next();
RSGroupInfo srcGrp = getRSGroupOfServer(firstServer);
if (srcGrp == null) {
// Be careful. This exception message is tested for in TestRSGroupsBase...
throw new ConstraintException("Source RSGroup for server " + firstServer
+ " does not exist.");
}
// Only move online servers (when moving from 'default') or servers from other
// groups. This prevents bogus servers from entering groups
if (RSGroupInfo.DEFAULT_GROUP.equals(srcGrp.getName())) {
if (srcGrp.getServers().size() <= servers.size()) {
throw new ConstraintException(KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE);
}
checkOnlineServersOnly(servers);
}
// Ensure all servers are of same rsgroup.
for (Address server: servers) {
String tmpGroup = getRSGroupOfServer(server).getName();
if (!tmpGroup.equals(srcGrp.getName())) {
throw new ConstraintException("Move server request should only come from one source " +
"RSGroup. Expecting only " + srcGrp.getName() + " but contains " + tmpGroup);
}
}
if (srcGrp.getServers().size() <= servers.size()) {
// check if there are still tables reference this group
for (TableDescriptor td : masterServices.getTableDescriptors().getAll().values()) {
Optional<String> optGroupName = td.getRegionServerGroup();
if (optGroupName.isPresent() && optGroupName.get().equals(srcGrp.getName())) {
throw new ConstraintException(
"Cannot leave a RSGroup " + srcGrp.getName() + " that contains tables('" +
td.getTableName() + "' at least) without servers to host them.");
}
}
}
// MovedServers may be < passed in 'servers'.
Set<Address> movedServers = moveServers(servers, srcGrp.getName(),
targetGroupName);
moveServerRegionsFromGroup(movedServers, targetGroupName);
LOG.info("Move servers done: {} => {}", srcGrp.getName(), targetGroupName);
}
}
}

View File

@ -19,11 +19,11 @@
package org.apache.hadoop.hbase.rsgroup;
import java.util.Arrays;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.util.compaction.MajorCompactorTTL;
@ -31,6 +31,7 @@ import org.apache.hadoop.util.ToolRunner;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLineParser;
@ -58,9 +59,9 @@ public class RSGroupMajorCompactionTTL extends MajorCompactorTTL {
throws Exception {
Connection conn = ConnectionFactory.createConnection(conf);
RSGroupAdmin rsGroupAdmin = new RSGroupAdminClient(conn);
Admin admin = conn.getAdmin();
RSGroupInfo rsGroupInfo = rsGroupAdmin.getRSGroupInfo(rsgroup);
RSGroupInfo rsGroupInfo = admin.getRSGroup(rsgroup);
if (rsGroupInfo == null) {
LOG.error("Invalid rsgroup specified: " + rsgroup);
throw new IllegalArgumentException("Invalid rsgroup specified: " + rsgroup);

View File

@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory;
* Helper class for RSGroup implementation
*/
@InterfaceAudience.Private
final class RSGroupUtil {
public final class RSGroupUtil {
private static final Logger LOG = LoggerFactory.getLogger(RSGroupUtil.class);
@ -38,8 +38,8 @@ final class RSGroupUtil {
* Will try to get the rsgroup from {@link TableDescriptor} first, and then try to get the rsgroup
* from the {@link NamespaceDescriptor}. If still not present, return empty.
*/
static Optional<RSGroupInfo> getRSGroupInfo(MasterServices master, RSGroupInfoManager manager,
TableName tableName) throws IOException {
public static Optional<RSGroupInfo> getRSGroupInfo(MasterServices master,
RSGroupInfoManager manager, TableName tableName) throws IOException {
TableDescriptor td = master.getTableDescriptors().get(tableName);
if (td == null) {
return Optional.empty();
@ -79,7 +79,7 @@ final class RSGroupUtil {
* Fill the tables field for {@link RSGroupInfo}, for backward compatibility.
*/
@SuppressWarnings("deprecation")
static RSGroupInfo fillTables(RSGroupInfo rsGroupInfo, Collection<TableDescriptor> tds) {
public static RSGroupInfo fillTables(RSGroupInfo rsGroupInfo, Collection<TableDescriptor> tds) {
RSGroupInfo newRsGroupInfo = new RSGroupInfo(rsGroupInfo);
Predicate<TableDescriptor> filter;
if (rsGroupInfo.getName().equals(RSGroupInfo.DEFAULT_GROUP)) {

View File

@ -98,6 +98,7 @@ import org.apache.hadoop.hbase.io.hfile.HFile;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
import org.apache.hadoop.hbase.ipc.RpcServer;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
@ -2586,4 +2587,84 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
}
}
}
@Override
public void preMoveServersAndTables(ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "moveServersAndTables",
null, Permission.Action.ADMIN);
}
@Override
public void preMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers, String targetGroup) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "moveServers",
null, Permission.Action.ADMIN);
}
@Override
public void preMoveTables(ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<TableName> tables, String targetGroup) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "moveTables",
null, Permission.Action.ADMIN);
}
@Override
public void preAddRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx,
String name) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "addRSGroup",
null, Permission.Action.ADMIN);
}
@Override
public void preRemoveRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx,
String name) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "removeRSGroup",
null, Permission.Action.ADMIN);
}
@Override
public void preBalanceRSGroup(ObserverContext<MasterCoprocessorEnvironment> ctx,
String groupName) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "balanceRSGroup",
null, Permission.Action.ADMIN);
}
@Override
public void preRemoveServers(
ObserverContext<MasterCoprocessorEnvironment> ctx,
Set<Address> servers) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "removeServers",
null, Permission.Action.ADMIN);
}
@Override
public void preGetRSGroupInfo(ObserverContext<MasterCoprocessorEnvironment> ctx,
String groupName) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "getRSGroupInfo",
null, Permission.Action.ADMIN);
}
@Override
public void preGetRSGroupInfoOfTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
TableName tableName) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "getRSGroupInfoOfTable",
null, Permission.Action.ADMIN);
//todo: should add check for table existence
}
@Override
public void preListRSGroups(ObserverContext<MasterCoprocessorEnvironment> ctx)
throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "listRSGroups",
null, Permission.Action.ADMIN);
}
@Override
public void preGetRSGroupInfoOfServer(ObserverContext<MasterCoprocessorEnvironment> ctx,
Address server) throws IOException {
accessChecker.requirePermission(getActiveUser(ctx), "getRSGroupInfoOfServer",
null, Permission.Action.ADMIN);
}
}

View File

@ -500,4 +500,9 @@ public class MockNoopMasterServices implements MasterServices {
public RSGroupInfoManager getRSGroupInfoManager() {
return null;
}
@Override
public boolean isBalancerOn() {
return false;
}
}

View File

@ -41,15 +41,18 @@ import org.apache.hadoop.hbase.protobuf.generated.RSGroupProtos;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.zookeeper.KeeperException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
/**
* Testcase for HBASE-22819
*/
@RunWith(Parameterized.class)
@Category({ MediumTests.class })
public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
@ -63,8 +66,8 @@ public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
private static byte[] FAMILY = Bytes.toBytes("family");
@BeforeClass
public static void setUp() throws Exception {
@Before
public void setUp() throws Exception {
TEST_UTIL.getConfiguration().setClass(HConstants.MASTER_IMPL, HMasterForTest.class,
HMaster.class);
setUpTestBeforeClass();
@ -73,8 +76,8 @@ public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
}
}
@AfterClass
public static void tearDown() throws Exception {
@After
public void tearDown() throws Exception {
tearDownAfterClass();
}
@ -90,7 +93,7 @@ public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
public TableDescriptors getTableDescriptors() {
if (RESUME != null) {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getClassName().contains("RSGroupInfoManagerImpl")) {
if (element.getMethodName().equals("migrate")) {
try {
RESUME.await();
} catch (InterruptedException e) {
@ -106,9 +109,10 @@ public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
@Test
public void testMigrate() throws IOException, InterruptedException {
String groupName = name.getMethodName();
setAdmin();
String groupName = getNameWithoutIndex(name.getMethodName());
addGroup(groupName, TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads().size() - 1);
RSGroupInfo rsGroupInfo = rsGroupAdmin.getRSGroupInfo(groupName);
RSGroupInfo rsGroupInfo = rsGroupAdmin.getRSGroup(groupName);
assertTrue(rsGroupInfo.getTables().isEmpty());
for (int i = 0; i < NUM_TABLES; i++) {
rsGroupInfo.addTable(TableName.valueOf(TABLE_NAME_PREFIX + i));
@ -123,12 +127,11 @@ public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
RESUME = new CountDownLatch(1);
TEST_UTIL.getMiniHBaseCluster().startMaster();
TEST_UTIL.invalidateConnection();
RS_GROUP_ADMIN_CLIENT = new RSGroupAdminClient(TEST_UTIL.getConnection());
// wait until we can get the rs group info for a table
TEST_UTIL.waitFor(30000, () -> {
try {
rsGroupAdmin.getRSGroupInfoOfTable(TableName.valueOf(TABLE_NAME_PREFIX + 0));
rsGroupAdmin.getRSGroup(TableName.valueOf(TABLE_NAME_PREFIX + 0));
return true;
} catch (IOException e) {
return false;
@ -137,7 +140,7 @@ public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
// confirm that before migrating, we could still get the correct rs group for a table.
for (int i = 0; i < NUM_TABLES; i++) {
RSGroupInfo info =
rsGroupAdmin.getRSGroupInfoOfTable(TableName.valueOf(TABLE_NAME_PREFIX + i));
rsGroupAdmin.getRSGroup(TableName.valueOf(TABLE_NAME_PREFIX + i));
assertEquals(rsGroupInfo.getName(), info.getName());
assertEquals(NUM_TABLES, info.getTables().size());
}
@ -173,7 +176,7 @@ public class TestMigrateRSGroupInfo extends TestRSGroupsBase {
// make sure we could still get the correct rs group info after migration
for (int i = 0; i < NUM_TABLES; i++) {
RSGroupInfo info =
rsGroupAdmin.getRSGroupInfoOfTable(TableName.valueOf(TABLE_NAME_PREFIX + i));
rsGroupAdmin.getRSGroup(TableName.valueOf(TABLE_NAME_PREFIX + i));
assertEquals(rsGroupInfo.getName(), info.getName());
assertEquals(NUM_TABLES, info.getTables().size());
}

View File

@ -42,11 +42,8 @@ import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.constraint.ConstraintException;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.master.TableNamespaceManager;
import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaUtil;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
@ -57,11 +54,14 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
@RunWith(Parameterized.class)
@Category({ MediumTests.class })
public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
@ -112,9 +112,9 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
@Test
public void testBogusArgs() throws Exception {
assertNull(rsGroupAdmin.getRSGroupInfoOfTable(TableName.valueOf("nonexistent")));
assertNull(rsGroupAdmin.getRSGroupOfServer(Address.fromParts("bogus", 123)));
assertNull(rsGroupAdmin.getRSGroupInfo("bogus"));
assertNull(rsGroupAdmin.getRSGroup(TableName.valueOf("nonexistent")));
assertNull(rsGroupAdmin.getRSGroup(Address.fromParts("bogus", 123)));
assertNull(rsGroupAdmin.getRSGroup("bogus"));
try {
rsGroupAdmin.removeRSGroup("bogus");
@ -124,14 +124,15 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
}
try {
rsGroupAdmin.moveTables(Sets.newHashSet(TableName.valueOf("bogustable")), "bogus");
fail("Expected move with bogus group to fail");
rsGroupAdmin.setRSGroup(Sets.newHashSet(TableName.valueOf("bogustable")), "bogus");
fail("Expected set table to bogus group fail");
} catch (ConstraintException | TableNotFoundException ex) {
// expected
}
try {
rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromParts("bogus", 123)), "bogus");
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(Address.fromParts("bogus", 123)),
"bogus");
fail("Expected move with bogus group to fail");
} catch (ConstraintException ex) {
// expected
@ -158,8 +159,8 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
admin.createNamespace(NamespaceDescriptor.create(nsName)
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName).build());
RSGroupInfo rsGroupInfo = rsGroupAdmin.getRSGroupInfo(groupName);
rsGroupAdmin.moveServers(rsGroupInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
RSGroupInfo rsGroupInfo = rsGroupAdmin.getRSGroup(groupName);
rsGroupAdmin.moveToRSGroup(rsGroupInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
// test removing a referenced group
try {
rsGroupAdmin.removeRSGroup(groupName);
@ -198,16 +199,20 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
@Test
public void testGetRSGroupInfoCPHookCalled() throws Exception {
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
assertTrue(observer.preGetRSGroupInfoCalled);
assertTrue(observer.postGetRSGroupInfoCalled);
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP);
if (rsGroupAdmin instanceof RSGroupAdminClient) {
assertTrue(observer.preGetRSGroupInfoCalled);
assertTrue(observer.postGetRSGroupInfoCalled);
}
}
@Test
public void testGetRSGroupInfoOfTableCPHookCalled() throws Exception {
rsGroupAdmin.getRSGroupInfoOfTable(TableName.META_TABLE_NAME);
assertTrue(observer.preGetRSGroupInfoOfTableCalled);
assertTrue(observer.postGetRSGroupInfoOfTableCalled);
rsGroupAdmin.getRSGroup(TableName.META_TABLE_NAME);
if (rsGroupAdmin instanceof RSGroupAdminClient) {
assertTrue(observer.preGetRSGroupInfoOfTableCalled);
assertTrue(observer.postGetRSGroupInfoOfTableCalled);
}
}
@Test
@ -220,9 +225,11 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
@Test
public void testGetRSGroupInfoOfServerCPHookCalled() throws Exception {
ServerName masterServerName = ((MiniHBaseCluster) cluster).getMaster().getServerName();
rsGroupAdmin.getRSGroupOfServer(masterServerName.getAddress());
assertTrue(observer.preGetRSGroupInfoOfServerCalled);
assertTrue(observer.postGetRSGroupInfoOfServerCalled);
rsGroupAdmin.getRSGroup(masterServerName.getAddress());
if (rsGroupAdmin instanceof RSGroupAdminClient) {
assertTrue(observer.preGetRSGroupInfoOfServerCalled);
assertTrue(observer.postGetRSGroupInfoOfServerCalled);
}
}
@Test
@ -230,8 +237,8 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
int initNumGroups = rsGroupAdmin.listRSGroups().size();
addGroup("bar", 3);
TEST_UTIL.createTable(tableName, Bytes.toBytes("f"));
rsGroupAdmin.moveTables(Sets.newHashSet(tableName), "bar");
RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), "bar");
RSGroupInfo barGroup = rsGroupAdmin.getRSGroup("bar");
// group is not empty therefore it should fail
try {
rsGroupAdmin.removeRSGroup(barGroup.getName());
@ -240,19 +247,19 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
}
// group cannot lose all it's servers therefore it should fail
try {
rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
fail("Expected move servers to fail");
} catch (IOException e) {
}
rsGroupAdmin.moveTables(barGroup.getTables(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.setRSGroup(barGroup.getTables(), RSGroupInfo.DEFAULT_GROUP);
try {
rsGroupAdmin.removeRSGroup(barGroup.getName());
fail("Expected move servers to fail");
} catch (IOException e) {
}
rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(barGroup.getName());
Assert.assertEquals(initNumGroups, rsGroupAdmin.listRSGroups().size());
@ -260,10 +267,12 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
@Test
public void testMultiTableMove() throws Exception {
final TableName tableNameA = TableName.valueOf(tablePrefix + name.getMethodName() + "A");
final TableName tableNameB = TableName.valueOf(tablePrefix + name.getMethodName() + "B");
final TableName tableNameA = TableName.valueOf(tablePrefix +
getNameWithoutIndex(name.getMethodName()) + "A");
final TableName tableNameB = TableName.valueOf(tablePrefix +
getNameWithoutIndex(name.getMethodName()) + "B");
final byte[] familyNameBytes = Bytes.toBytes("f");
String newGroupName = getGroupName(name.getMethodName());
String newGroupName = getGroupName(getNameWithoutIndex(name.getMethodName()));
final RSGroupInfo newGroup = addGroup(newGroupName, 1);
TEST_UTIL.createTable(tableNameA, familyNameBytes);
@ -284,30 +293,30 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
}
});
RSGroupInfo tableGrpA = rsGroupAdmin.getRSGroupInfoOfTable(tableNameA);
RSGroupInfo tableGrpA = rsGroupAdmin.getRSGroup(tableNameA);
assertTrue(tableGrpA.getName().equals(RSGroupInfo.DEFAULT_GROUP));
RSGroupInfo tableGrpB = rsGroupAdmin.getRSGroupInfoOfTable(tableNameB);
RSGroupInfo tableGrpB = rsGroupAdmin.getRSGroup(tableNameB);
assertTrue(tableGrpB.getName().equals(RSGroupInfo.DEFAULT_GROUP));
// change table's group
LOG.info("Moving table [" + tableNameA + "," + tableNameB + "] to " + newGroup.getName());
rsGroupAdmin.moveTables(Sets.newHashSet(tableNameA, tableNameB), newGroup.getName());
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableNameA, tableNameB), newGroup.getName());
// verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableNameA).getName());
rsGroupAdmin.getRSGroup(tableNameA).getName());
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableNameB).getName());
rsGroupAdmin.getRSGroup(tableNameB).getName());
// verify tables' not exist in old group
Set<TableName> DefaultTables =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables();
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getTables();
assertFalse(DefaultTables.contains(tableNameA));
assertFalse(DefaultTables.contains(tableNameB));
// verify tables' exist in new group
Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroupName).getTables();
Set<TableName> newGroupTables = rsGroupAdmin.getRSGroup(newGroupName).getTables();
assertTrue(newGroupTables.contains(tableNameA));
assertTrue(newGroupTables.contains(tableNameB));
}
@ -315,7 +324,7 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
@Test
public void testTableMoveTruncateAndDrop() throws Exception {
final byte[] familyNameBytes = Bytes.toBytes("f");
String newGroupName = getGroupName(name.getMethodName());
String newGroupName = getGroupName(getNameWithoutIndex(name.getMethodName()));
final RSGroupInfo newGroup = addGroup(newGroupName, 2);
TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
@ -331,16 +340,17 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
}
});
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroup(tableName);
LOG.info("got table group info is {}", tableGrp);
assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
// change table's group
LOG.info("Moving table " + tableName + " to " + newGroup.getName());
rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), newGroup.getName());
// verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
rsGroupAdmin.getRSGroup(tableName).getName());
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
@ -361,22 +371,20 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
// test truncate
admin.disableTable(tableName);
admin.truncateTable(tableName, true);
Assert.assertEquals(1, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
Assert.assertEquals(1, rsGroupAdmin.getRSGroup(newGroup.getName()).getTables().size());
Assert.assertEquals(tableName,
rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().first());
rsGroupAdmin.getRSGroup(newGroup.getName()).getTables().first());
// verify removed table is removed from group
TEST_UTIL.deleteTable(tableName);
Assert.assertEquals(0, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
Assert.assertEquals(0, rsGroupAdmin.getRSGroup(newGroup.getName()).getTables().size());
assertTrue(observer.preMoveTablesCalled);
assertTrue(observer.postMoveTablesCalled);
}
@Test
public void testDisabledTableMove() throws Exception {
final byte[] familyNameBytes = Bytes.toBytes("f");
String newGroupName = getGroupName(name.getMethodName());
String newGroupName = getGroupName(getNameWithoutIndex(name.getMethodName()));
final RSGroupInfo newGroup = addGroup(newGroupName, 2);
TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
@ -391,7 +399,7 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
}
});
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroup(tableName);
assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
// test disable table
@ -399,18 +407,18 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
// change table's group
LOG.info("Moving table " + tableName + " to " + newGroup.getName());
rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), newGroup.getName());
// verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
rsGroupAdmin.getRSGroup(tableName).getName());
}
@Test
public void testNonExistentTableMove() throws Exception {
TableName tableName = TableName.valueOf(tablePrefix + name.getMethodName());
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
TableName tableName = TableName.valueOf(tablePrefix +
getNameWithoutIndex(name.getMethodName()));
RSGroupInfo tableGrp = rsGroupAdmin.getRSGroup(tableName);
assertNull(tableGrp);
// test if table exists already.
@ -419,21 +427,22 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
LOG.info("Moving table " + tableName + " to " + RSGroupInfo.DEFAULT_GROUP);
try {
rsGroupAdmin.moveTables(Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
fail("Table " + tableName + " shouldn't have been successfully moved.");
} catch (IOException ex) {
assertTrue(ex instanceof TableNotFoundException);
}
try {
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(Address.fromParts("bogus", 123)),
Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(Address.fromParts("bogus", 123)),
RSGroupInfo.DEFAULT_GROUP);
fail("Table " + tableName + " shouldn't have been successfully moved.");
} catch (IOException ex) {
assertTrue(ex instanceof TableNotFoundException);
}
// verify group change
assertNull(rsGroupAdmin.getRSGroupInfoOfTable(tableName));
assertNull(rsGroupAdmin.getRSGroup(tableName));
}
@Test
@ -512,20 +521,10 @@ public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
}
});
SortedSet<TableName> tables
= rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables();
= rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getTables();
assertTrue("Table 't1' must be in 'default' rsgroup", tables.contains(tn1));
// Cleanup
TEST_UTIL.deleteTable(tn1);
}
private void toggleQuotaCheckAndRestartMiniCluster(boolean enable) throws Exception {
TEST_UTIL.shutdownMiniCluster();
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, enable);
TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
initialize();
}
}

View File

@ -17,7 +17,6 @@
*/
package org.apache.hadoop.hbase.rsgroup;
import static org.apache.hadoop.hbase.rsgroup.RSGroupAdminServer.DEFAULT_MAX_RETRY_VALUE;
import static org.apache.hadoop.hbase.util.Threads.sleep;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -55,12 +54,15 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
@RunWith(Parameterized.class)
@Category({ LargeTests.class })
public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
@ -128,7 +130,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
}
final ServerName targetServer = tmpTargetServer;
// move target server to group
rsGroupAdmin.moveServers(Sets.newHashSet(targetServer.getAddress()), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(targetServer.getAddress()), newGroup.getName());
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
@ -162,14 +164,14 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
int initNumGroups = rsGroupAdmin.listRSGroups().size();
RSGroupInfo appInfo = addGroup(getGroupName(name.getMethodName()), 1);
RSGroupInfo adminInfo = addGroup(getGroupName(name.getMethodName()), 1);
RSGroupInfo dInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
RSGroupInfo dInfo = rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP);
Assert.assertEquals(initNumGroups + 2, rsGroupAdmin.listRSGroups().size());
assertEquals(1, adminInfo.getServers().size());
assertEquals(1, appInfo.getServers().size());
assertEquals(getNumServers() - 2, dInfo.getServers().size());
rsGroupAdmin.moveServers(appInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(appInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(appInfo.getName());
rsGroupAdmin.moveServers(adminInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(adminInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(adminInfo.getName());
Assert.assertEquals(rsGroupAdmin.listRSGroups().size(), initNumGroups);
}
@ -180,14 +182,14 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
addGroup("bar", 3);
rsGroupAdmin.addRSGroup("foo");
RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
RSGroupInfo fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
RSGroupInfo barGroup = rsGroupAdmin.getRSGroup("bar");
RSGroupInfo fooGroup = rsGroupAdmin.getRSGroup("foo");
assertEquals(3, barGroup.getServers().size());
assertEquals(0, fooGroup.getServers().size());
// test fail bogus server move
try {
rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromString("foo:9999")), "foo");
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(Address.fromString("foo:9999")), "foo");
fail("Bogus servers shouldn't have been successfully moved.");
} catch (IOException ex) {
String exp = "Source RSGroup for server foo:9999 does not exist.";
@ -197,34 +199,34 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// test success case
LOG.info("moving servers " + barGroup.getServers() + " to group foo");
rsGroupAdmin.moveServers(barGroup.getServers(), fooGroup.getName());
rsGroupAdmin.moveToRSGroup(barGroup.getServers(), fooGroup.getName());
barGroup = rsGroupAdmin.getRSGroupInfo("bar");
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
barGroup = rsGroupAdmin.getRSGroup("bar");
fooGroup = rsGroupAdmin.getRSGroup("foo");
assertEquals(0, barGroup.getServers().size());
assertEquals(3, fooGroup.getServers().size());
LOG.info("moving servers " + fooGroup.getServers() + " to group default");
rsGroupAdmin.moveServers(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getNumServers() == rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP)
return getNumServers() == rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP)
.getServers().size();
}
});
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
fooGroup = rsGroupAdmin.getRSGroup("foo");
assertEquals(0, fooGroup.getServers().size());
// test group removal
LOG.info("Remove group " + barGroup.getName());
rsGroupAdmin.removeRSGroup(barGroup.getName());
Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(barGroup.getName()));
Assert.assertEquals(null, rsGroupAdmin.getRSGroup(barGroup.getName()));
LOG.info("Remove group " + fooGroup.getName());
rsGroupAdmin.removeRSGroup(fooGroup.getName());
Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(fooGroup.getName()));
Assert.assertEquals(null, rsGroupAdmin.getRSGroup(fooGroup.getName()));
}
@Test
@ -236,7 +238,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// remove online servers
try {
rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
rsGroupAdmin.removeRSGroup(Sets.newHashSet(targetServer.getAddress()));
fail("Online servers shouldn't have been successfully removed.");
} catch (IOException ex) {
String exp =
@ -267,7 +269,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
});
try {
rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
rsGroupAdmin.removeRSGroup(Sets.newHashSet(targetServer.getAddress()));
fail("Dead servers shouldn't have been successfully removed.");
} catch (IOException ex) {
String exp = "Server " + targetServer.getAddress() + " is on the dead servers list," +
@ -287,8 +289,8 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
assertEquals(1, admin.listDecommissionedRegionServers().size());
assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
rsGroupAdmin.removeRSGroup(Sets.newHashSet(targetServer.getAddress()));
Set<Address> newGroupServers = rsGroupAdmin.getRSGroup(newGroup.getName()).getServers();
assertFalse(newGroupServers.contains(targetServer.getAddress()));
assertEquals(2, newGroupServers.size());
@ -320,7 +322,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
for (ServerName server : admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
.getLiveServerMetrics().keySet()) {
if (!newGroup.containsServer(server.getAddress()) &&
!rsGroupAdmin.getRSGroupInfo("master").containsServer(server.getAddress())) {
!rsGroupAdmin.getRSGroup("master").containsServer(server.getAddress())) {
targetServer = server;
break;
}
@ -328,14 +330,15 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
LOG.debug("Print group info : " + rsGroupAdmin.listRSGroups());
int oldDefaultGroupServerSize =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getServers().size();
int oldDefaultGroupTableSize =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size();
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getTables().size();
// test fail bogus server move
try {
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(Address.fromString("foo:9999")),
Sets.newHashSet(tableName), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(Address.fromString("foo:9999")),
newGroup.getName());
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), newGroup.getName());
fail("Bogus servers shouldn't have been successfully moved.");
} catch (IOException ex) {
String exp = "Source RSGroup for server foo:9999 does not exist.";
@ -344,18 +347,19 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
}
// test move when src = dst
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(targetServer.getAddress()),
RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
// verify default group info
Assert.assertEquals(oldDefaultGroupServerSize,
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size());
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getServers().size());
Assert.assertEquals(oldDefaultGroupTableSize,
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size());
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getTables().size());
// verify new group info
Assert.assertEquals(1, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers().size());
Assert.assertEquals(0, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
Assert.assertEquals(1, rsGroupAdmin.getRSGroup(newGroup.getName()).getServers().size());
Assert.assertEquals(0, rsGroupAdmin.getRSGroup(newGroup.getName()).getTables().size());
// get all region to move targetServer
List<String> regionList = getTableRegionMap().get(tableName);
@ -381,38 +385,39 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// move targetServer and table to newGroup
LOG.info("moving server and table to newGroup");
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
Sets.newHashSet(tableName), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(targetServer.getAddress()),
newGroup.getName());
rsGroupAdmin.setRSGroup(Sets.newHashSet(tableName), newGroup.getName());
// verify group change
Assert.assertEquals(newGroup.getName(),
rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
rsGroupAdmin.getRSGroup(tableName).getName());
// verify servers' not exist in old group
Set<Address> defaultServers =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers();
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getServers();
assertFalse(defaultServers.contains(targetServer.getAddress()));
// verify servers' exist in new group
Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
Set<Address> newGroupServers = rsGroupAdmin.getRSGroup(newGroup.getName()).getServers();
assertTrue(newGroupServers.contains(targetServer.getAddress()));
// verify tables' not exist in old group
Set<TableName> defaultTables =
rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables();
rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getTables();
assertFalse(defaultTables.contains(tableName));
// verify tables' exist in new group
Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables();
Set<TableName> newGroupTables = rsGroupAdmin.getRSGroup(newGroup.getName()).getTables();
assertTrue(newGroupTables.contains(tableName));
// verify that all region still assgin on targetServer
// TODO: uncomment after we reimplement moveServersAndTables, now the implementation is
// moveServers first and then moveTables, so the region will be moved to other region servers.
// moveToRSGroup first and then moveTables, so the region will be moved to other region servers.
// Assert.assertEquals(5, getTableServerRegionMap().get(tableName).get(targetServer).size());
assertTrue(observer.preMoveServersAndTables);
assertTrue(observer.postMoveServersAndTables);
assertTrue(observer.preMoveServersCalled);
assertTrue(observer.postMoveServersCalled);
}
@Test
@ -420,17 +425,17 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// create groups and assign servers
rsGroupAdmin.addRSGroup("foo");
RSGroupInfo fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
RSGroupInfo fooGroup = rsGroupAdmin.getRSGroup("foo");
assertEquals(0, fooGroup.getServers().size());
RSGroupInfo defaultGroup = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
RSGroupInfo defaultGroup = rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP);
// test remove all servers from default
try {
rsGroupAdmin.moveServers(defaultGroup.getServers(), fooGroup.getName());
fail(RSGroupAdminServer.KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE);
rsGroupAdmin.moveToRSGroup(defaultGroup.getServers(), fooGroup.getName());
fail(RSGroupInfoManagerImpl.KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE);
} catch (ConstraintException ex) {
assertTrue(
ex.getMessage().contains(RSGroupAdminServer.KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE));
ex.getMessage().contains(RSGroupInfoManagerImpl.KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE));
}
// test success case, remove one server from default ,keep at least one server
@ -438,35 +443,35 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
Address serverInDefaultGroup = defaultGroup.getServers().iterator().next();
LOG.info("moving server " + serverInDefaultGroup + " from group default to group " +
fooGroup.getName());
rsGroupAdmin.moveServers(Sets.newHashSet(serverInDefaultGroup), fooGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(serverInDefaultGroup), fooGroup.getName());
}
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
fooGroup = rsGroupAdmin.getRSGroup("foo");
LOG.info("moving servers " + fooGroup.getServers() + " to group default");
rsGroupAdmin.moveServers(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return getNumServers() == rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP)
return getNumServers() == rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP)
.getServers().size();
}
});
fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
fooGroup = rsGroupAdmin.getRSGroup("foo");
assertEquals(0, fooGroup.getServers().size());
// test group removal
LOG.info("Remove group " + fooGroup.getName());
rsGroupAdmin.removeRSGroup(fooGroup.getName());
Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(fooGroup.getName()));
Assert.assertEquals(null, rsGroupAdmin.getRSGroup(fooGroup.getName()));
}
@Test
public void testFailedMoveBeforeRetryExhaustedWhenMoveServer() throws Exception {
String groupName = getGroupName(name.getMethodName());
rsGroupAdmin.addRSGroup(groupName);
final RSGroupInfo newGroup = rsGroupAdmin.getRSGroupInfo(groupName);
final RSGroupInfo newGroup = rsGroupAdmin.getRSGroup(groupName);
Pair<ServerName, RegionStateNode> gotPair = createTableWithRegionSplitting(newGroup,
10);
@ -482,7 +487,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
Thread t2 = new Thread(() -> {
LOG.info("thread2 start running, to move regions");
try {
rsGroupAdmin.moveServers(Sets.newHashSet(movedServer.getAddress()), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(movedServer.getAddress()), newGroup.getName());
} catch (IOException e) {
LOG.error("move server error", e);
}
@ -512,7 +517,8 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// wait until there is only left the region we changed state and recover its state.
// wait time is set according to the number of max retries, all except failed regions will be
// moved in one retry, and will sleep 1s until next retry.
while (System.currentTimeMillis() - current <= DEFAULT_MAX_RETRY_VALUE * 1000) {
while (System.currentTimeMillis() - current <=
RSGroupInfoManagerImpl.DEFAULT_MAX_RETRY_VALUE * 1000) {
List<RegionInfo> regions = getRegions.apply(owner);
LOG.debug("server table region size is:{}", regions.size());
assert regions.size() >= 1;
@ -600,7 +606,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
@Test
public void testFailedMoveServersAndRepair() throws Exception{
// This UT calls moveServers() twice to test the idempotency of it.
// This UT calls moveToRSGroup() twice to test the idempotency of it.
// The first time, movement fails because a region is made in SPLITTING state
// which will not be moved.
// The second time, the region state is OPEN and check if all
@ -616,7 +622,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// move server to newGroup and check regions
try {
rsGroupAdmin.moveServers(Sets.newHashSet(srcServer.getAddress()), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(srcServer.getAddress()), newGroup.getName());
fail("should get IOException when retry exhausted but there still exists failed moved "
+ "regions");
}catch (Exception e){
@ -632,7 +638,7 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// retry move server to newGroup and check if all regions on srcServer was moved
rsn.setState(RegionState.State.OPEN);
rsGroupAdmin.moveServers(Sets.newHashSet(srcServer.getAddress()), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(srcServer.getAddress()), newGroup.getName());
assertEquals(master.getAssignmentManager().getRegionsOnServer(srcServer).size(), 0);
}
@ -661,8 +667,8 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// move server and table to newGroup and check regions
try {
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(srcServer.getAddress()),
Sets.newHashSet(table2), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(srcServer.getAddress()), newGroup.getName());
rsGroupAdmin.setRSGroup(Sets.newHashSet(table2), newGroup.getName());
fail("should get IOException when retry exhausted but there still exists failed moved "
+ "regions");
}catch (Exception e){
@ -679,8 +685,8 @@ public class TestRSGroupsAdmin2 extends TestRSGroupsBase {
// retry moveServersAndTables to newGroup and check if all regions on srcServer belongs to
// table2
rsn.setState(RegionState.State.OPEN);
rsGroupAdmin.moveServersAndTables(Sets.newHashSet(srcServer.getAddress()),
Sets.newHashSet(table2), newGroup.getName());
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(srcServer.getAddress()), newGroup.getName());
rsGroupAdmin.setRSGroup(Sets.newHashSet(table2), newGroup.getName());
for(RegionInfo regionsInfo : master.getAssignmentManager().getRegionsOnServer(srcServer)){
assertEquals(regionsInfo.getTable(), table2);
}

View File

@ -42,9 +42,12 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(Parameterized.class)
@Category({ MediumTests.class })
public class TestRSGroupsBalance extends TestRSGroupsBase {
@ -80,7 +83,8 @@ public class TestRSGroupsBalance extends TestRSGroupsBase {
String newGroupName = getGroupName(name.getMethodName());
addGroup(newGroupName, 3);
final TableName tableName = TableName.valueOf(tablePrefix + "_ns", name.getMethodName());
final TableName tableName = TableName.valueOf(tablePrefix + "_ns",
getNameWithoutIndex(name.getMethodName()));
admin.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString())
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, newGroupName).build());
final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
@ -151,13 +155,12 @@ public class TestRSGroupsBalance extends TestRSGroupsBase {
@Test
public void testMisplacedRegions() throws Exception {
String namespace = tablePrefix + "_" + name.getMethodName();
String namespace = tablePrefix + "_" + getNameWithoutIndex(name.getMethodName());
TEST_UTIL.getAdmin().createNamespace(NamespaceDescriptor.create(namespace).build());
final TableName tableName =
TableName.valueOf(namespace, tablePrefix + "_" + name.getMethodName());
LOG.info(name.getMethodName());
final TableName tableName = TableName.valueOf(namespace, tablePrefix + "_" +
getNameWithoutIndex(name.getMethodName()));
final RSGroupInfo rsGroupInfo = addGroup(name.getMethodName(), 1);
final RSGroupInfo rsGroupInfo = addGroup(getGroupName(name.getMethodName()), 1);
TEST_UTIL.createMultiRegionTable(tableName, new byte[] { 'f' }, 15);
TEST_UTIL.waitUntilAllRegionsAssigned(tableName);

View File

@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedList;
@ -30,6 +31,7 @@ import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import org.apache.hadoop.hbase.ClusterMetrics;
import org.apache.hadoop.hbase.ClusterMetrics.Option;
@ -54,8 +56,10 @@ import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaUtil;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -74,7 +78,6 @@ public abstract class TestRSGroupsBase {
protected static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
protected static Admin admin;
protected static HBaseCluster cluster;
protected static RSGroupAdminClient rsGroupAdmin;
protected static HMaster master;
protected boolean INIT = false;
protected static RSGroupAdminEndpoint rsGroupAdminEndpoint;
@ -89,6 +92,48 @@ public abstract class TestRSGroupsBase {
public TestName name = new TestName();
protected TableName tableName;
protected Admin rsGroupAdmin;
@Parameterized.Parameter
public Supplier<Object> getAdmin;
private static RSGroupAdminClient getRSGroupAdmin(){
try {
return new VerifyingRSGroupAdminClient(
new RSGroupAdminClient(TEST_UTIL.getConnection()), TEST_UTIL.getConfiguration());
} catch (IOException e) {
LOG.error("Get group admin failed", e);
return null;
}
}
private static Admin getAdmin(){
try {
return TEST_UTIL.getAdmin();
} catch (IOException e) {
LOG.error("Get hbase admin failed", e);
return null;
}
}
public static Object resetAdminConnection(Object admin) {
if(admin instanceof RSGroupAdminClient) {
return getRSGroupAdmin();
}else {
return getAdmin();
}
}
public static String getNameWithoutIndex(String name) {
return name.split("\\[")[0];
}
@Parameterized.Parameters
public static List<Object[]> params() {
return Arrays.asList(new Supplier<?>[] { TestRSGroupsBase::getRSGroupAdmin },
new Supplier<?>[] { TestRSGroupsBase::getAdmin });
}
public static void setUpTestBeforeClass() throws Exception {
TEST_UTIL.getConfiguration().setFloat(
"hbase.master.balancer.stochastic.tableSkewCost", 6000);
@ -107,6 +152,10 @@ public abstract class TestRSGroupsBase {
initialize();
}
public void setAdmin(){
rsGroupAdmin = (Admin) getAdmin.get();
}
protected static void initialize() throws Exception {
admin = TEST_UTIL.getAdmin();
cluster = TEST_UTIL.getHBaseCluster();
@ -121,8 +170,6 @@ public abstract class TestRSGroupsBase {
}
});
admin.balancerSwitch(false, true);
rsGroupAdmin = new VerifyingRSGroupAdminClient(
new RSGroupAdminClient(TEST_UTIL.getConnection()), TEST_UTIL.getConfiguration());
MasterCoprocessorHost host = master.getMasterCoprocessorHost();
observer = (CPMasterObserver) host.findCoprocessor(CPMasterObserver.class.getName());
rsGroupAdminEndpoint = (RSGroupAdminEndpoint)
@ -134,8 +181,9 @@ public abstract class TestRSGroupsBase {
}
public void setUpBeforeMethod() throws Exception {
setAdmin();
LOG.info(name.getMethodName());
tableName = TableName.valueOf(tablePrefix + "_" + name.getMethodName());
tableName = TableName.valueOf(tablePrefix + "_" + name.getMethodName().split("\\[")[0]);
if (!INIT) {
INIT = true;
tearDownAfterMethod();
@ -164,7 +212,8 @@ public abstract class TestRSGroupsBase {
((MiniHBaseCluster)cluster).getMaster().getServerName();
try {
rsGroupAdmin.moveServers(Sets.newHashSet(masterServerName.getAddress()), "master");
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(masterServerName.getAddress()),
"master");
} catch (Exception ex) {
LOG.warn("Got this on setup, FYI", ex);
}
@ -176,7 +225,7 @@ public abstract class TestRSGroupsBase {
//Might be greater since moving servers back to default
//is after starting a server
return rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size()
return rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getServers().size()
== NUM_SLAVES_BASE;
}
});
@ -184,7 +233,7 @@ public abstract class TestRSGroupsBase {
protected RSGroupInfo addGroup(String groupName, int serverCount)
throws IOException, InterruptedException {
RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.addRSGroup(groupName);
Set<Address> set = new HashSet<>();
for (Address server : defaultInfo.getServers()) {
@ -193,15 +242,15 @@ public abstract class TestRSGroupsBase {
}
set.add(server);
}
rsGroupAdmin.moveServers(set, groupName);
RSGroupInfo result = rsGroupAdmin.getRSGroupInfo(groupName);
rsGroupAdmin.moveToRSGroup(set, groupName);
RSGroupInfo result = rsGroupAdmin.getRSGroup(groupName);
return result;
}
protected void removeGroup(String groupName) throws IOException {
RSGroupInfo groupInfo = rsGroupAdmin.getRSGroupInfo(groupName);
rsGroupAdmin.moveTables(groupInfo.getTables(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveServers(groupInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
public void removeGroup(String groupName) throws IOException {
RSGroupInfo groupInfo = rsGroupAdmin.getRSGroup(groupName);
rsGroupAdmin.setRSGroup(groupInfo.getTables(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.moveToRSGroup(groupInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
rsGroupAdmin.removeRSGroup(groupName);
}
@ -224,7 +273,7 @@ public abstract class TestRSGroupsBase {
RSGroupAdminClient groupAdmin = new RSGroupAdminClient(TEST_UTIL.getConnection());
for(RSGroupInfo group: groupAdmin.listRSGroups()) {
if(!group.getName().equals(RSGroupInfo.DEFAULT_GROUP)) {
groupAdmin.moveTables(group.getTables(), RSGroupInfo.DEFAULT_GROUP);
groupAdmin.setRSGroup(group.getTables(), RSGroupInfo.DEFAULT_GROUP);
groupAdmin.moveServers(group.getServers(), RSGroupInfo.DEFAULT_GROUP);
groupAdmin.removeRSGroup(group.getName());
}
@ -276,8 +325,9 @@ public abstract class TestRSGroupsBase {
return count;
}
protected String getGroupName(String baseName) {
return groupPrefix + "_" + baseName + "_" + rand.nextInt(Integer.MAX_VALUE);
public String getGroupName(String baseName) {
return groupPrefix + "_" + getNameWithoutIndex(baseName) + "_" +
rand.nextInt(Integer.MAX_VALUE);
}
/**
@ -290,6 +340,17 @@ public abstract class TestRSGroupsBase {
.findFirst().get();
}
protected void toggleQuotaCheckAndRestartMiniCluster(boolean enable) throws Exception {
TEST_UTIL.shutdownMiniCluster();
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, enable);
TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
NUM_SLAVES_BASE - 1);
TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
initialize();
rsGroupAdmin = (Admin) resetAdminConnection(rsGroupAdmin);
}
public static class CPMasterObserver implements MasterCoprocessor, MasterObserver {
boolean preBalanceRSGroupCalled = false;
boolean postBalanceRSGroupCalled = false;
@ -313,6 +374,8 @@ public abstract class TestRSGroupsBase {
boolean postListRSGroupsCalled = false;
boolean preGetRSGroupInfoOfServerCalled = false;
boolean postGetRSGroupInfoOfServerCalled = false;
boolean preSetRSGroupForTablesCalled = false;
boolean postSetRSGroupForTablesCalled = false;
public void resetFlags() {
preBalanceRSGroupCalled = false;
@ -337,6 +400,8 @@ public abstract class TestRSGroupsBase {
postListRSGroupsCalled = false;
preGetRSGroupInfoOfServerCalled = false;
postGetRSGroupInfoOfServerCalled = false;
preSetRSGroupForTablesCalled = false;
postSetRSGroupForTablesCalled = false;
}
@Override

View File

@ -34,7 +34,6 @@ import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
import org.apache.hadoop.hbase.quotas.QuotaUtil;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
@ -45,11 +44,14 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
@RunWith(Parameterized.class)
@Category({ MediumTests.class })
public class TestRSGroupsBasics extends TestRSGroupsBase {
@ -81,10 +83,12 @@ public class TestRSGroupsBasics extends TestRSGroupsBase {
@Test
public void testBasicStartUp() throws IOException {
RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP);
assertEquals(NUM_SLAVES_BASE, defaultInfo.getServers().size());
// Assignment of meta and rsgroup regions.
int count = master.getAssignmentManager().getRegionStates().getRegionAssignments().size();
LOG.info("regions assignments are" +
master.getAssignmentManager().getRegionStates().getRegionAssignments().toString());
// 2 (meta and rsgroup)
assertEquals(2, count);
}
@ -165,6 +169,7 @@ public class TestRSGroupsBasics extends TestRSGroupsBase {
// clone
admin.cloneSnapshot(snapshotName, clonedTableName);
admin.deleteSnapshot(snapshotName);
}
@Test
@ -206,7 +211,7 @@ public class TestRSGroupsBasics extends TestRSGroupsBase {
assertEquals(0, notClearedServers.size());
// the stopped region server gets cleared and removed from the group
Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
Set<Address> newGroupServers = rsGroupAdmin.getRSGroup(newGroup.getName()).getServers();
assertFalse(newGroupServers.contains(serverToStop.getAddress()));
assertEquals(serverCountToMoveToNewGroup - 1 /* 1 stopped */, newGroupServers.size());
}
@ -240,34 +245,20 @@ public class TestRSGroupsBasics extends TestRSGroupsBase {
});
Set<Address> ServersInDeadServerGroup =
rsGroupAdmin.getRSGroupInfo(deadServerGroup.getName()).getServers();
rsGroupAdmin.getRSGroup(deadServerGroup.getName()).getServers();
assertEquals(serverCountToMoveToDeadServerGroup, ServersInDeadServerGroup.size());
assertTrue(ServersInDeadServerGroup.contains(serverToStop.getAddress()));
}
@Test
public void testRSGroupsWithHBaseQuota() throws Exception {
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
restartHBaseCluster();
try {
TEST_UTIL.waitFor(90000, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return admin.isTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
}
});
} finally {
TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, false);
restartHBaseCluster();
}
}
private void restartHBaseCluster() throws Exception {
LOG.info("\n\nShutting down cluster");
TEST_UTIL.shutdownMiniHBaseCluster();
LOG.info("\n\nSleeping a bit");
Thread.sleep(2000);
TEST_UTIL.restartHBaseCluster(NUM_SLAVES_BASE - 1);
initialize();
toggleQuotaCheckAndRestartMiniCluster(true);
TEST_UTIL.waitFor(90000, new Waiter.Predicate<Exception>() {
@Override
public boolean evaluate() throws Exception {
return admin.isTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
}
});
toggleQuotaCheckAndRestartMiniCluster(false);
}
}

View File

@ -41,7 +41,7 @@ import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.master.procedure.ServerCrashProcedure;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.testclassification.LargeTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.JVMClusterUtil;
import org.apache.hadoop.hbase.util.VersionInfo;
@ -52,12 +52,15 @@ import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
@Category({ LargeTests.class })
@RunWith(Parameterized.class)
@Category({ MediumTests.class })
public class TestRSGroupsKillRS extends TestRSGroupsBase {
@ClassRule
@ -89,7 +92,8 @@ public class TestRSGroupsKillRS extends TestRSGroupsBase {
@Test
public void testKillRS() throws Exception {
RSGroupInfo appInfo = addGroup("appInfo", 1);
final TableName tableName = TableName.valueOf(tablePrefix + "_ns", name.getMethodName());
final TableName tableName = TableName.valueOf(tablePrefix + "_ns",
getNameWithoutIndex(name.getMethodName()));
admin.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString())
.addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
@ -129,8 +133,8 @@ public class TestRSGroupsKillRS extends TestRSGroupsBase {
});
Set<Address> newServers = Sets.newHashSet();
newServers
.add(rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().iterator().next());
rsGroupAdmin.moveServers(newServers, appInfo.getName());
.add(rsGroupAdmin.getRSGroup(RSGroupInfo.DEFAULT_GROUP).getServers().iterator().next());
rsGroupAdmin.moveToRSGroup(newServers, appInfo.getName());
// Make sure all the table's regions get reassigned
// disabling the table guarantees no conflicting assign/unassign (ie SSH) happens
@ -162,12 +166,12 @@ public class TestRSGroupsKillRS extends TestRSGroupsBase {
TEST_UTIL.loadTable(t, Bytes.toBytes("f"));
Set<TableName> toAddTables = new HashSet<>();
toAddTables.add(tableName);
rsGroupAdmin.moveTables(toAddTables, groupName);
assertTrue(rsGroupAdmin.getRSGroupInfo(groupName).getTables().contains(tableName));
rsGroupAdmin.setRSGroup(toAddTables, groupName);
assertTrue(rsGroupAdmin.getRSGroup(groupName).getTables().contains(tableName));
TEST_UTIL.waitTableAvailable(tableName, 30000);
// check my_group servers and table regions
Set<Address> servers = rsGroupAdmin.getRSGroupInfo(groupName).getServers();
Set<Address> servers = rsGroupAdmin.getRSGroup(groupName).getServers();
assertEquals(2, servers.size());
LOG.debug("group servers {}", servers);
for (RegionInfo tr :
@ -198,7 +202,7 @@ public class TestRSGroupsKillRS extends TestRSGroupsBase {
// case 1: stop all the regionservers in my_group, and restart a regionserver in my_group,
// and then check if all table regions are online
for(Address addr : rsGroupAdmin.getRSGroupInfo(groupName).getServers()) {
for(Address addr : rsGroupAdmin.getRSGroup(groupName).getServers()) {
TEST_UTIL.getMiniHBaseCluster().stopRegionServer(getServerName(addr));
}
// better wait for a while for region reassign
@ -225,7 +229,7 @@ public class TestRSGroupsKillRS extends TestRSGroupsBase {
assertEquals(NUM_SLAVES_BASE - gsn.size(),
TEST_UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size());
ServerName newServer = master.getServerManager().getOnlineServersList().get(0);
rsGroupAdmin.moveServers(Sets.newHashSet(newServer.getAddress()), groupName);
rsGroupAdmin.moveToRSGroup(Sets.newHashSet(newServer.getAddress()), groupName);
// wait and check if table regions are online
TEST_UTIL.waitTableAvailable(tableName, 30000);
}
@ -240,14 +244,14 @@ public class TestRSGroupsKillRS extends TestRSGroupsBase {
// move hbase:meta to meta_group
Set<TableName> toAddTables = new HashSet<>();
toAddTables.add(TableName.META_TABLE_NAME);
rsGroupAdmin.moveTables(toAddTables, groupName);
assertTrue(
rsGroupAdmin.getRSGroupInfo(groupName).getTables().contains(TableName.META_TABLE_NAME));
rsGroupAdmin.setRSGroup(toAddTables, groupName);
assertTrue(rsGroupAdmin.getRSGroup(groupName).getTables().contains(TableName.META_TABLE_NAME));
TEST_UTIL.waitTableAvailable(tableName, 30000);
// restart the regionserver in meta_group, and lower its version
String originVersion = "";
Set<Address> servers = new HashSet<>();
for(Address addr : rsGroupAdmin.getRSGroupInfo(groupName).getServers()) {
for(Address addr : rsGroupAdmin.getRSGroup(groupName).getServers()) {
servers.add(addr);
TEST_UTIL.getMiniHBaseCluster().stopRegionServer(getServerName(addr));
originVersion = master.getRegionServerVersion(getServerName(addr));

View File

@ -56,7 +56,7 @@ import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
// online. In new master, RSGroupInfoManagerImpl gets the data from zk and waits for the expected
// assignment with a timeout.
@Category(MediumTests.class)
public class TestRSGroupsOfflineMode {
public class TestRSGroupsOfflineMode extends TestRSGroupsBase {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
@ -106,7 +106,7 @@ public class TestRSGroupsOfflineMode {
@Test
public void testOffline() throws Exception, InterruptedException {
// Table should be after group table name so it gets assigned later.
final TableName failoverTable = TableName.valueOf(name.getMethodName());
final TableName failoverTable = TableName.valueOf(getNameWithoutIndex(name.getMethodName()));
TEST_UTIL.createTable(failoverTable, Bytes.toBytes("f"));
final HRegionServer killRS = ((MiniHBaseCluster) cluster).getRegionServer(0);
final HRegionServer groupRS = ((MiniHBaseCluster) cluster).getRegionServer(1);
@ -139,7 +139,7 @@ public class TestRSGroupsOfflineMode {
}
});
// Move table to group and wait.
groupAdmin.moveTables(Sets.newHashSet(RSGroupInfoManagerImpl.RSGROUP_TABLE_NAME), newGroup);
groupAdmin.setRSGroup(Sets.newHashSet(RSGroupInfoManagerImpl.RSGROUP_TABLE_NAME), newGroup);
LOG.info("Waiting for move table...");
TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
@Override

View File

@ -21,6 +21,8 @@ import static org.apache.hadoop.hbase.AuthUtil.toGroupEntry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Optional;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
@ -31,7 +33,11 @@ import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
import org.apache.hadoop.hbase.ipc.RpcServer;
import org.apache.hadoop.hbase.master.HMaster;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.UserProvider;
import org.apache.hadoop.hbase.security.access.AccessChecker;
import org.apache.hadoop.hbase.security.access.AccessControlClient;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.PermissionStorage;
@ -92,6 +98,9 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
private static RSGroupAdminEndpoint rsGroupAdminEndpoint;
private static HMaster master;
private static AccessChecker accessChecker;
private static UserProvider userProvider;
@BeforeClass
public static void setupBeforeClass() throws Exception {
@ -131,6 +140,22 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
systemUserConnection = TEST_UTIL.getConnection();
setUpTableAndUserPermissions();
master = TEST_UTIL.getHBaseCluster().getMaster();
accessChecker = master.getAccessChecker();
userProvider = UserProvider.instantiate(TEST_UTIL.getConfiguration());
}
private void checkPermission(String request) throws IOException {
accessChecker.requirePermission(getActiveUser(), request, null, Permission.Action.ADMIN);
}
private User getActiveUser() throws IOException {
// for non-rpc handling, fallback to system user
Optional<User> optionalUser = RpcServer.getRequestUser();
if (optionalUser.isPresent()) {
return optionalUser.get();
}
return userProvider.getCurrent();
}
private static void setUpTableAndUserPermissions() throws Exception {
@ -204,7 +229,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testGetRSGroupInfo() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("getRSGroupInfo");
checkPermission("getRSGroupInfo");
return null;
};
@ -214,7 +239,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testGetRSGroupInfoOfTable() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("getRSGroupInfoOfTable");
checkPermission("getRSGroupInfoOfTable");
return null;
};
@ -224,7 +249,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testMoveServers() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("moveServers");
checkPermission("moveServers");
return null;
};
@ -234,7 +259,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testMoveTables() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("moveTables");
checkPermission("moveTables");
return null;
};
@ -244,7 +269,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testAddRSGroup() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("addRSGroup");
checkPermission("addRSGroup");
return null;
};
@ -254,7 +279,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testRemoveRSGroup() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("removeRSGroup");
checkPermission("removeRSGroup");
return null;
};
@ -264,7 +289,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testBalanceRSGroup() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("balanceRSGroup");
checkPermission("balanceRSGroup");
return null;
};
@ -274,7 +299,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testListRSGroup() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("listRSGroup");
checkPermission("listRSGroup");
return null;
};
@ -284,7 +309,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testGetRSGroupInfoOfServer() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("getRSGroupInfoOfServer");
checkPermission("getRSGroupInfoOfServer");
return null;
};
@ -294,7 +319,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testMoveServersAndTables() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("moveServersAndTables");
checkPermission("moveServersAndTables");
return null;
};
@ -304,7 +329,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil {
@Test
public void testRemoveServers() throws Exception {
AccessTestAction action = () -> {
rsGroupAdminEndpoint.getGroupAdminService().checkPermission("removeServers");
checkPermission("removeServers");
return null;
};

View File

@ -73,24 +73,18 @@ public class VerifyingRSGroupAdminClient extends RSGroupAdminClient {
}
@Override
public RSGroupInfo getRSGroupInfo(String groupName) throws IOException {
public RSGroupInfo getRSGroup(String groupName) throws IOException {
return wrapped.getRSGroupInfo(groupName);
}
@Override
public RSGroupInfo getRSGroupInfoOfTable(TableName tableName) throws IOException {
return wrapped.getRSGroupInfoOfTable(tableName);
public RSGroupInfo getRSGroup(TableName tableName) throws IOException {
return wrapped.getRSGroup(tableName);
}
@Override
public void moveServers(Set<Address> servers, String targetGroup) throws IOException {
wrapped.moveServers(servers, targetGroup);
verify();
}
@Override
public void moveTables(Set<TableName> tables, String targetGroup) throws IOException {
wrapped.moveTables(tables, targetGroup);
public void moveToRSGroup(Set<Address> servers, String targetGroup) throws IOException {
wrapped.moveToRSGroup(servers, targetGroup);
verify();
}
@ -111,20 +105,19 @@ public class VerifyingRSGroupAdminClient extends RSGroupAdminClient {
}
@Override
public RSGroupInfo getRSGroupOfServer(Address hostPort) throws IOException {
return wrapped.getRSGroupOfServer(hostPort);
public RSGroupInfo getRSGroup(Address hostPort) throws IOException {
return wrapped.getRSGroup(hostPort);
}
@Override
public void moveServersAndTables(Set<Address> servers, Set<TableName> tables, String targetGroup)
throws IOException {
wrapped.moveServersAndTables(servers, tables, targetGroup);
public void removeRSGroup(Set<Address> servers) throws IOException {
wrapped.removeRSGroup(servers);
verify();
}
@Override
public void removeServers(Set<Address> servers) throws IOException {
wrapped.removeServers(servers);
public void setRSGroup(Set<TableName> tables, String groupName) throws IOException{
wrapped.setRSGroup(tables, groupName);
verify();
}

View File

@ -52,12 +52,14 @@ import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.replication.TableCFs;
import org.apache.hadoop.hbase.client.security.SecurityCapability;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
import org.apache.hadoop.hbase.net.Address;
import org.apache.hadoop.hbase.quotas.QuotaFilter;
import org.apache.hadoop.hbase.quotas.QuotaSettings;
import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot;
import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
import org.apache.hadoop.hbase.replication.SyncReplicationState;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.UserPermission;
@ -1170,6 +1172,56 @@ public class ThriftAdmin implements Admin {
throw new NotImplementedException("clearSlowLogsResponses not supported in ThriftAdmin");
}
@Override
public RSGroupInfo getRSGroup(String groupName) {
throw new NotImplementedException("getRSGroup not supported in ThriftAdmin");
}
@Override
public void moveToRSGroup(Set<Address> servers, String targetGroup) {
throw new NotImplementedException("moveToRSGroup not supported in ThriftAdmin");
}
@Override
public void addRSGroup(String groupName) {
throw new NotImplementedException("addRSGroup not supported in ThriftAdmin");
}
@Override
public void removeRSGroup(String groupName) {
throw new NotImplementedException("removeRSGroup not supported in ThriftAdmin");
}
@Override
public boolean balanceRSGroup(String groupName) {
throw new NotImplementedException("balanceRSGroup not supported in ThriftAdmin");
}
@Override
public List<RSGroupInfo> listRSGroups() {
throw new NotImplementedException("listRSGroups not supported in ThriftAdmin");
}
@Override
public RSGroupInfo getRSGroup(Address hostPort) {
throw new NotImplementedException("getRSGroup not supported in ThriftAdmin");
}
@Override
public void removeRSGroup(Set<Address> servers) {
throw new NotImplementedException("removeRSGroup not supported in ThriftAdmin");
}
@Override
public RSGroupInfo getRSGroup(TableName tableName) {
throw new NotImplementedException("getRSGroup not supported in ThriftAdmin");
}
@Override
public void setRSGroup(Set<TableName> tables, String groupName) {
throw new NotImplementedException("setRSGroup not supported in ThriftAdmin");
}
@Override
public Future<Void> splitRegionAsync(byte[] regionName) throws IOException {
return splitRegionAsync(regionName, null);