diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java index 9f2084c256f..397aba06e72 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java @@ -2265,4 +2265,18 @@ public interface Admin extends Abortable, Closeable { */ void clearCompactionQueues(final ServerName sn, final Set queues) throws IOException, InterruptedException; + + /** + * List dead region servers. + * @return List of dead region servers. + */ + List listDeadServers() throws IOException; + + /** + * Clear dead region servers from master. + * @param servers list of dead region servers. + * @throws IOException if a remote or network exception occurs + * @return List of servers that are not cleared + */ + List clearDeadServers(final List servers) throws IOException; } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java index 995a18f0911..d7c3389cbca 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java @@ -1116,4 +1116,17 @@ public interface AsyncAdmin { */ CompletableFuture coprocessorService(Function stubMaker, CoprocessorCallable callable, ServerName serverName); + + /** + * List all the dead region servers. + * @return - returns a list of dead region servers wrapped by a {@link CompletableFuture}. + */ + CompletableFuture> listDeadServers(); + + /** + * Clear dead region servers from master. + * @param servers list of dead region servers. + * @return - returns a list of servers that not cleared wrapped by a {@link CompletableFuture}. + */ + CompletableFuture> clearDeadServers(final List servers); } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java index e8e8c95088b..b92bf35a208 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java @@ -639,4 +639,14 @@ public class AsyncHBaseAdmin implements AsyncAdmin { CoprocessorCallable callable, ServerName serverName) { return wrap(rawAdmin.coprocessorService(stubMaker, callable, serverName)); } + + @Override + public CompletableFuture> listDeadServers() { + return wrap(rawAdmin.listDeadServers()); + } + + @Override + public CompletableFuture> clearDeadServers(List servers) { + return wrap(rawAdmin.clearDeadServers(servers)); + } } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java index b274371c4fc..8e7a261f4bc 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java @@ -1775,6 +1775,18 @@ class ConnectionImplementation implements ClusterConnection, Closeable { RpcController controller, GetQuotaStatesRequest request) throws ServiceException { return stub.getQuotaStates(controller, request); } + + @Override + public MasterProtos.ListDeadServersResponse listDeadServers(RpcController controller, + MasterProtos.ListDeadServersRequest request) throws ServiceException { + return stub.listDeadServers(controller, request); + } + + @Override + public MasterProtos.ClearDeadServersResponse clearDeadServers(RpcController controller, + MasterProtos.ClearDeadServersRequest request) throws ServiceException { + return stub.clearDeadServers(controller, request); + } }; } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index 58034089ad9..19f6b7ee969 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -113,6 +113,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AbortProce import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateTableRequest; @@ -150,6 +151,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.IsSnapshotDoneRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotDoneResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDeadServersRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDrainingRegionServersRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespaceDescriptorsRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceRequest; @@ -4333,4 +4335,33 @@ public class HBaseAdmin implements Admin { }; ProtobufUtil.call(callable); } + + @Override + public List listDeadServers() throws IOException { + return executeCallable(new MasterCallable>(getConnection(), + getRpcControllerFactory()) { + @Override + public List rpcCall() throws ServiceException { + ListDeadServersRequest req = ListDeadServersRequest.newBuilder().build(); + return ProtobufUtil.toServerNameList( + master.listDeadServers(getRpcController(), req).getServerNameList()); + } + }); + } + + @Override + public List clearDeadServers(final List servers) throws IOException { + if (servers == null || servers.size() == 0) { + throw new IllegalArgumentException("servers cannot be null or empty"); + } + return executeCallable(new MasterCallable>(getConnection(), + getRpcControllerFactory()) { + @Override + protected List rpcCall() throws Exception { + ClearDeadServersRequest req = RequestConverter.buildClearDeadServersRequest(servers); + return ProtobufUtil.toServerNameList( + master.clearDeadServers(getRpcController(), req).getServerNameList()); + } + }); + } } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java index 9e6f1069478..b9949c042fc 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java @@ -113,6 +113,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegi import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateTableRequest; @@ -169,6 +171,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshot import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotDoneResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDeadServersRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDeadServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDrainingRegionServersRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDrainingRegionServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespaceDescriptorsRequest; @@ -2900,6 +2904,28 @@ public class RawAsyncHBaseAdmin implements AsyncAdmin { return future; } + @Override + public CompletableFuture> listDeadServers() { + return this.> newMasterCaller() + .action((controller, stub) -> this + .> call( + controller, stub, ListDeadServersRequest.newBuilder().build(), + (s, c, req, done) -> s.listDeadServers(c, req, done), + (resp) -> ProtobufUtil.toServerNameList(resp.getServerNameList()))) + .call(); + } + + @Override + public CompletableFuture> clearDeadServers(List servers) { + return this.> newMasterCaller() + .action((controller, stub) -> this + .> call( + controller, stub, RequestConverter.buildClearDeadServersRequest(servers), + (s, c, req, done) -> s.clearDeadServers(c, req, done), + (resp) -> ProtobufUtil.toServerNameList(resp.getServerNameList()))) + .call(); + } + private ServerRequestCallerBuilder newServerCaller() { return this.connection.callerFactory. serverRequest() .rpcTimeout(rpcTimeoutNs, TimeUnit.NANOSECONDS) diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java index 17b21cfcc65..6b7e4b68753 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java @@ -30,6 +30,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegi import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateTableRequest; @@ -90,6 +92,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshot import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotDoneResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDeadServersRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDeadServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDrainingRegionServersRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDrainingRegionServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespaceDescriptorsRequest; @@ -625,6 +629,18 @@ public class ShortCircuitMasterConnection implements MasterKeepAliveConnection { return stub.getQuotaStates(controller, request); } + @Override + public ClearDeadServersResponse clearDeadServers(RpcController controller, + ClearDeadServersRequest request) throws ServiceException { + return stub.clearDeadServers(controller, request); + } + + @Override + public ListDeadServersResponse listDeadServers(RpcController controller, + ListDeadServersRequest request) throws ServiceException { + return stub.listDeadServers(controller, request); + } + @Override public SplitTableRegionResponse splitRegion(RpcController controller, SplitTableRegionRequest request) throws ServiceException { diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java index b4f23ff5b3f..5679d08ff66 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java @@ -409,6 +409,17 @@ public final class ProtobufUtil { return ServerName.valueOf(hostName, port, startCode); } + /** + * Convert a list of protocol buffer ServerName to a list of ServerName + * @param proto protocol buffer ServerNameList + * @return a list of ServerName + */ + public static List toServerNameList( + List proto) { + return proto.stream().map(ProtobufUtil::toServerName) + .collect(Collectors.toList()); + } + /** * Get a list of NamespaceDescriptor from ListNamespaceDescriptorsResponse protobuf * @param proto the ListNamespaceDescriptorsResponse diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java index 00f051bbba1..d26afcd45c3 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/RequestConverter.java @@ -88,6 +88,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AddColumnRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateTableRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DeleteColumnRequest; @@ -1812,6 +1813,14 @@ public final class RequestConverter { return builder.build(); } + public static ClearDeadServersRequest buildClearDeadServersRequest(List deadServers) { + ClearDeadServersRequest.Builder builder = ClearDeadServersRequest.newBuilder(); + for(ServerName server: deadServers) { + builder.addServerName(ProtobufUtil.toServerName(server)); + } + return builder.build(); + } + private static final GetSpaceQuotaRegionSizesRequest GET_SPACE_QUOTA_REGION_SIZES_REQUEST = GetSpaceQuotaRegionSizesRequest.newBuilder().build(); diff --git a/hbase-protocol-shaded/src/main/protobuf/Master.proto b/hbase-protocol-shaded/src/main/protobuf/Master.proto index 44a6a76c766..6b16bf8bee3 100644 --- a/hbase-protocol-shaded/src/main/protobuf/Master.proto +++ b/hbase-protocol-shaded/src/main/protobuf/Master.proto @@ -622,6 +622,21 @@ message RemoveDrainFromRegionServersRequest { message RemoveDrainFromRegionServersResponse { } +message ListDeadServersRequest { +} + +message ListDeadServersResponse { + repeated ServerName server_name = 1; +} + +message ClearDeadServersRequest { + repeated ServerName server_name = 1; +} + +message ClearDeadServersResponse { + repeated ServerName server_name = 1; +} + service MasterService { /** Used by the client to get the number of regions that have received the updated schema */ rpc GetSchemaAlterStatus(GetSchemaAlterStatusRequest) @@ -970,4 +985,12 @@ service MasterService { /** Fetches the Master's view of quotas */ rpc GetQuotaStates(GetQuotaStatesRequest) returns(GetQuotaStatesResponse); + + /** clear dead servers from master*/ + rpc ClearDeadServers(ClearDeadServersRequest) + returns(ClearDeadServersResponse); + + /** Returns a list of Dead Servers. */ + rpc ListDeadServers(ListDeadServersRequest) + returns(ListDeadServersResponse); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java index f1cf49d8cfc..cf6cd735906 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java @@ -1917,4 +1917,28 @@ public interface MasterObserver extends Coprocessor { */ default void postLockHeartbeat(ObserverContext ctx, LockProcedure proc, boolean keepAlive) throws IOException {} + + /** + * Called before list dead region servers. + */ + default void preListDeadServers(ObserverContext ctx) + throws IOException {} + + /** + * Called after list dead region servers. + */ + default void postListDeadServers(ObserverContext ctx) + throws IOException {} + + /** + * Called before clear dead region servers. + */ + default void preClearDeadServers(ObserverContext ctx) + throws IOException {} + + /** + * Called after clear dead region servers. + */ + default void postClearDeadServers(ObserverContext ctx) + throws IOException {} } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/DeadServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/DeadServer.java index fc862540580..23c170527d2 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/DeadServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/DeadServer.java @@ -202,4 +202,17 @@ public class DeadServer { return o1.getSecond().compareTo(o2.getSecond()); } }; + + /** + * remove the specified dead server + * @param deadServerName the dead server name + * @return true if this server was removed + */ + + public synchronized boolean removeDeadServer(final ServerName deadServerName) { + if (deadServers.remove(deadServerName) == null) { + return false; + } + return true; + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index eaa4f5fd89d..14cebe6f014 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -1879,6 +1879,46 @@ public class MasterCoprocessorHost }); } + public void preListDeadServers() throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, ObserverContext ctx) + throws IOException { + oserver.preListDeadServers(ctx); + } + }); + } + + public void postListDeadServers() throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, ObserverContext ctx) + throws IOException { + oserver.postListDeadServers(ctx); + } + }); + } + + public void preClearDeadServers() throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, ObserverContext ctx) + throws IOException { + oserver.preClearDeadServers(ctx); + } + }); + } + + public void postClearDeadServers() throws IOException { + execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { + @Override + public void call(MasterObserver oserver, ObserverContext ctx) + throws IOException { + oserver.postClearDeadServers(ctx); + } + }); + } + private static ImmutableHTableDescriptor toImmutableHTableDescriptor(TableDescriptor desc) { return new ImmutableHTableDescriptor(desc); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java index 47523a30f0a..eaf9f6160a0 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java @@ -104,6 +104,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegi import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.AssignRegionResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.BalanceResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ClearDeadServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateNamespaceResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.CreateTableRequest; @@ -164,6 +166,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshot import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotDoneResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDeadServersRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDeadServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDrainingRegionServersRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDrainingRegionServersResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespaceDescriptorsRequest; @@ -2121,4 +2125,63 @@ public class MasterRpcServices extends RSRpcServices throw new ServiceException(e); } } + + @Override + public ListDeadServersResponse listDeadServers(RpcController controller, + ListDeadServersRequest request) throws ServiceException { + + LOG.debug(master.getClientIdAuditPrefix() + " list dead region servers."); + ListDeadServersResponse.Builder response = ListDeadServersResponse.newBuilder(); + try { + master.checkInitialized(); + if (master.cpHost != null) { + master.cpHost.preListDeadServers(); + } + + Set servers = master.getServerManager().getDeadServers().copyServerNames(); + for (ServerName server : servers) { + response.addServerName(ProtobufUtil.toServerName(server)); + } + + if (master.cpHost != null) { + master.cpHost.postListDeadServers(); + } + } catch (IOException io) { + throw new ServiceException(io); + } + + return response.build(); + } + + @Override + public ClearDeadServersResponse clearDeadServers(RpcController controller, + ClearDeadServersRequest request) throws ServiceException { + LOG.debug(master.getClientIdAuditPrefix() + " clear dead region servers."); + ClearDeadServersResponse.Builder response = ClearDeadServersResponse.newBuilder(); + try { + master.checkInitialized(); + if (master.cpHost != null) { + master.cpHost.preClearDeadServers(); + } + + if (master.getServerManager().areDeadServersInProgress()) { + LOG.debug("Some dead server is still under processing, won't clear the dead server list"); + response.addAllServerName(request.getServerNameList()); + } else { + for (HBaseProtos.ServerName pbServer : request.getServerNameList()) { + if (!master.getServerManager().getDeadServers() + .removeDeadServer(ProtobufUtil.toServerName(pbServer))) { + response.addServerName(pbServer); + } + } + } + + if (master.cpHost != null) { + master.cpHost.postClearDeadServers(); + } + } catch (IOException io) { + throw new ServiceException(io); + } + return response.build(); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java index 4d79990d99b..6aeba249cb0 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java @@ -1461,6 +1461,11 @@ public class AccessController implements MasterObserver, RegionObserver, RegionS requirePermission(getActiveUser(ctx), "split", tableName, null, null, Action.ADMIN); } + @Override + public void preClearDeadServers(ObserverContext ctx) throws IOException { + requirePermission(getActiveUser(ctx), "clearDeadServers", Action.ADMIN); + } + /* ---- RegionObserver implementation ---- */ @Override diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestDeadServer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestDeadServer.java index fd18b6c00ba..d5f238d9771 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestDeadServer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestDeadServer.java @@ -151,5 +151,23 @@ public class TestDeadServer { Assert.assertTrue(d.isEmpty()); } + @Test + public void testClearDeadServer(){ + DeadServer d = new DeadServer(); + d.add(hostname123); + d.add(hostname1234); + Assert.assertEquals(2, d.size()); + + d.removeDeadServer(hostname123); + Assert.assertEquals(1, d.size()); + d.removeDeadServer(hostname1234); + Assert.assertTrue(d.isEmpty()); + + d.add(hostname1234); + Assert.assertFalse(d.removeDeadServer(hostname123_2)); + Assert.assertEquals(1, d.size()); + Assert.assertTrue(d.removeDeadServer(hostname1234)); + Assert.assertTrue(d.isEmpty()); + } } diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb index 1dfa0c1dc94..236fac5709e 100644 --- a/hbase-shell/src/main/ruby/hbase/admin.rb +++ b/hbase-shell/src/main/ruby/hbase/admin.rb @@ -1249,5 +1249,27 @@ module Hbase end @admin.clearCompactionQueues(ServerName.valueOf(server_name), queues) end + + #---------------------------------------------------------------------------------------------- + # clear dead region servers + def list_deadservers + @admin.listDeadServers.to_a + end + + #---------------------------------------------------------------------------------------------- + # clear dead region servers + def clear_deadservers(dead_servers) + # Flatten params array + dead_servers = dead_servers.flatten.compact + if dead_servers.empty? + servers = list_deadservers + else + servers = java.util.ArrayList.new + dead_servers.each do |s| + servers.add(ServerName.valueOf(s)) + end + end + @admin.clearDeadServers(servers).to_a + end end end diff --git a/hbase-shell/src/main/ruby/shell.rb b/hbase-shell/src/main/ruby/shell.rb index 469505fb245..759898bd72b 100644 --- a/hbase-shell/src/main/ruby/shell.rb +++ b/hbase-shell/src/main/ruby/shell.rb @@ -358,6 +358,8 @@ Shell.load_command_group( splitormerge_switch splitormerge_enabled clear_compaction_queues + list_deadservers + clear_deadservers ], # TODO: remove older hlog_roll command aliases: { diff --git a/hbase-shell/src/main/ruby/shell/commands/clear_deadservers.rb b/hbase-shell/src/main/ruby/shell/commands/clear_deadservers.rb new file mode 100644 index 00000000000..c3b5659cc0a --- /dev/null +++ b/hbase-shell/src/main/ruby/shell/commands/clear_deadservers.rb @@ -0,0 +1,52 @@ +# +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +module Shell + module Commands + class ClearDeadservers < Command + def help + <<-EOF + Clear the dead region servers that are never used. + Examples: + Clear all dead region servers: + hbase> clear_deadservers + Clear the specified dead region servers: + hbase> clear_deadservers 'host187.example.com,60020,1289493121758' + or + hbase> clear_deadservers 'host187.example.com,60020,1289493121758', + 'host188.example.com,60020,1289493121758' + EOF + end + + def command(*dead_servers) + servers = admin.clear_deadservers(dead_servers) + if servers.size <= 0 + formatter.row(['true']) + else + formatter.row(['Some dead server clear failed']) + formatter.row(['SERVERNAME']) + servers.each do |server| + formatter.row([server.toString]) + end + formatter.footer(servers.size) + end + end + end + end +end diff --git a/hbase-shell/src/main/ruby/shell/commands/list_deadservers.rb b/hbase-shell/src/main/ruby/shell/commands/list_deadservers.rb new file mode 100644 index 00000000000..be3f0bf7ff0 --- /dev/null +++ b/hbase-shell/src/main/ruby/shell/commands/list_deadservers.rb @@ -0,0 +1,43 @@ +# +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +module Shell + module Commands + class ListDeadservers < Command + def help + <<-EOF + List all dead region servers in hbase + Examples: + hbase> list_deadservers + EOF + end + + def command + formatter.header(['SERVERNAME']) + + servers = admin.list_deadservers + servers.each do |server| + formatter.row([server.toString]) + end + + formatter.footer(servers.size) + end + end + end +end