This is an automated email from the ASF dual-hosted git repository.
kturner pushed a commit to branch 2.1
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/2.1 by this push:
new 27bbe6a1e7 Merges admin signalShutdown into admin stop command (#5745)
27bbe6a1e7 is described below
commit 27bbe6a1e71a4068a144d5e8ec50029e50737a2a
Author: Keith Turner <[email protected]>
AuthorDate: Wed Jul 23 12:33:43 2025 -0400
Merges admin signalShutdown into admin stop command (#5745)
Currently the admin stop command takes a list of hostnames which are
assumed to be tservers. This change allows admin stop to also take a
list of host:port pairs. For these host:port pairs they can be any
accumulo server type and the new gracefulShutdown code will be called for
them. The admin signalShutdown command was removed since the stop
command is calling the same code internally now.
When ports are not specified the command behaves exactly as it used to.
However a deprecation warning is logged because the old command would
use local config to guess at ports, so it would never stop tservers on a
host where its local config had different ports. Hopefully the
deprecated behavior of only specifying host can be replaced w/ something
like the following. Need to see what the actual command would look
like.
```bash
acummulo admin stop $(accumulo admin serviceStatus | grep
$tserver_host_to_stop | ???)
```
---
.../org/apache/accumulo/server/util/Admin.java | 80 ++++++++++++++++------
.../org/apache/accumulo/server/util/ZooZap.java | 8 +--
.../test/functional/GracefulShutdownIT.java | 10 +--
3 files changed, 69 insertions(+), 29 deletions(-)
diff --git
a/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java
b/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java
index 0f7f534751..e2ec6f7fa1 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java
@@ -105,18 +105,12 @@ public class Admin implements KeywordExecutable {
}
@Parameters(
- commandDescription = "signal the server process to shutdown normally,
finishing anything it might be working on, but not starting any new tasks")
- static class GracefulShutdownCommand extends SubCommandOpts {
- @Parameter(required = true, names = {"-a", "--address"}, description =
"<host:port>")
- String address = null;
- }
-
- @Parameters(commandDescription = "stop the tablet server on the given hosts")
+ commandDescription = "Stop the servers at the given addresses allowing
them to complete current task but not start new task. When no port is
specified uses ports from tserver.port.client property.")
static class StopCommand extends SubCommandOpts {
@Parameter(names = {"-f", "--force"},
- description = "force the given server to stop by removing its lock")
+ description = "force the given server to stop immediately by removing
its lock. Does not wait for any task the server is currently working.")
boolean force = false;
- @Parameter(description = "<host> {<host> ... }")
+ @Parameter(description = "<host[:port]> {<host[:port]> ... }")
List<String> args = new ArrayList<>();
}
@@ -321,9 +315,6 @@ public class Admin implements KeywordExecutable {
FateOpsCommand fateOpsCommand = new FateOpsCommand();
cl.addCommand("fate", fateOpsCommand);
- GracefulShutdownCommand gracefulShutdownCommand = new
GracefulShutdownCommand();
- cl.addCommand("signalShutdown", gracefulShutdownCommand);
-
ListInstancesCommand listInstancesOpts = new ListInstancesCommand();
cl.addCommand("listInstances", listInstancesOpts);
@@ -413,9 +404,7 @@ public class Admin implements KeywordExecutable {
}
} else if (cl.getParsedCommand().equals("stop")) {
- stopTabletServer(context, stopOpts.args, stopOpts.force);
- } else if (cl.getParsedCommand().equals("signalShutdown")) {
- signalGracefulShutdown(context, gracefulShutdownCommand.address);
+ stopServers(context, stopOpts.args, stopOpts.force);
} else if (cl.getParsedCommand().equals("dumpConfig")) {
printConfig(context, dumpConfigCommand);
} else if (cl.getParsedCommand().equals("volumes")) {
@@ -563,18 +552,69 @@ public class Admin implements KeywordExecutable {
client -> client.shutdown(TraceUtil.traceInfo(), context.rpcCreds(),
tabletServersToo));
}
- // Visible for tests
- public static void signalGracefulShutdown(final ClientContext context,
String address) {
+ private static void stopServers(final ServerContext context, List<String>
servers,
+ final boolean force)
+ throws AccumuloException, AccumuloSecurityException,
InterruptedException, KeeperException {
+ List<String> hostOnly = new ArrayList<>();
+ Set<HostAndPort> hostAndPort = new TreeSet<>();
+
+ for (var server : servers) {
+ if (server.contains(":")) {
+ hostAndPort.add(HostAndPort.fromString(server));
+ } else {
+ hostOnly.add(server);
+ }
+ }
+
+ if (!hostOnly.isEmpty()) {
+ // The old impl of this command with the old behavior
+ stopTabletServer(context, hostOnly, force);
+ }
+
+ if (!hostAndPort.isEmpty()) {
+ // New behavior for this command when ports are present, supports more
than just tservers. Is
+ // also async.
+ if (force) {
+ ZooZap.Opts opts = new ZooZap.Opts();
+ var zk = context.getZooReaderWriter();
+ var iid = context.getInstanceID();
+
+ String tserversPath = Constants.ZROOT + "/" + iid +
Constants.ZTSERVERS;
+ ZooZap.removeLocks(zk, tserversPath, hostAndPort::contains, opts);
+ String compactorsBasepath = Constants.ZROOT + "/" + iid +
Constants.ZCOMPACTORS;
+ ZooZap.removeGroupedLocks(zk, compactorsBasepath, rg -> true,
hostAndPort::contains, opts);
+ String sserversPath = Constants.ZROOT + "/" + iid +
Constants.ZSSERVERS;
+ ZooZap.removeGroupedLocks(zk, sserversPath, rg -> true,
hostAndPort::contains, opts);
+
+ String managerLockPath = Constants.ZROOT + "/" + iid +
Constants.ZMANAGER_LOCK;
+ ZooZap.removeSingletonLock(zk, managerLockPath, hostAndPort::contains,
opts);
+ String gcLockPath = Constants.ZROOT + "/" + iid + Constants.ZGC_LOCK;
+ ZooZap.removeSingletonLock(zk, gcLockPath, hostAndPort::contains,
opts);
+ String monitorLockPath = Constants.ZROOT + "/" + iid +
Constants.ZMONITOR_LOCK;
+ ZooZap.removeSingletonLock(zk, monitorLockPath, hostAndPort::contains,
opts);
+ } else {
+ for (var server : hostAndPort) {
+ signalGracefulShutdown(context, server);
+ }
+ }
+ }
+ }
- Objects.requireNonNull(address, "address not set");
- final HostAndPort hp = HostAndPort.fromString(address);
+ // Visible for tests
+ public static void signalGracefulShutdown(final ClientContext context,
HostAndPort hp) {
+ Objects.requireNonNull(hp, "address not set");
ServerProcessService.Client client = null;
try {
client =
ThriftClientTypes.SERVER_PROCESS.getServerProcessConnection(context, log,
hp.getHost(), hp.getPort());
+ if (client == null) {
+ log.warn("Failed to initiate shutdown for {}", hp);
+ return;
+ }
client.gracefulShutdown(context.rpcCreds());
+ log.info("Initiated shutdown for {}", hp);
} catch (TException e) {
- throw new RuntimeException("Error invoking graceful shutdown for server:
" + hp, e);
+ log.warn("Failed to initiate shutdown for {}", hp, e);
} finally {
if (client != null) {
ThriftUtil.returnClient(client, context);
diff --git
a/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java
b/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java
index b9484176c6..3d548c37cf 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java
@@ -262,8 +262,8 @@ public class ZooZap implements KeywordExecutable {
}
}
- private static void removeGroupedLocks(ZooReaderWriter zoo, String path,
- Predicate<String> groupPredicate, Predicate<HostAndPort>
hostPortPredicate, Opts opts)
+ static void removeGroupedLocks(ZooReaderWriter zoo, String path,
Predicate<String> groupPredicate,
+ Predicate<HostAndPort> hostPortPredicate, Opts opts)
throws KeeperException, InterruptedException {
if (zoo.exists(path)) {
List<String> groups = zoo.getChildren(path);
@@ -275,7 +275,7 @@ public class ZooZap implements KeywordExecutable {
}
}
- private static void removeLocks(ZooReaderWriter zoo, String path,
+ static void removeLocks(ZooReaderWriter zoo, String path,
Predicate<HostAndPort> hostPortPredicate, Opts opts)
throws KeeperException, InterruptedException {
if (zoo.exists(path)) {
@@ -293,7 +293,7 @@ public class ZooZap implements KeywordExecutable {
}
}
- private static void removeSingletonLock(ZooReaderWriter zoo, String path,
+ static void removeSingletonLock(ZooReaderWriter zoo, String path,
Predicate<HostAndPort> hostPortPredicate, Opts ops)
throws KeeperException, InterruptedException {
var lockData = ServiceLock.getLockData(zoo.getZooKeeper(),
ServiceLock.path(path));
diff --git
a/test/src/main/java/org/apache/accumulo/test/functional/GracefulShutdownIT.java
b/test/src/main/java/org/apache/accumulo/test/functional/GracefulShutdownIT.java
index ad7aef847d..cbdb01b2f2 100644
---
a/test/src/main/java/org/apache/accumulo/test/functional/GracefulShutdownIT.java
+++
b/test/src/main/java/org/apache/accumulo/test/functional/GracefulShutdownIT.java
@@ -173,7 +173,7 @@ public class GracefulShutdownIT extends
SharedMiniClusterBase {
// Don't call `new Admin().execute(new String[] {"signalShutdown", "-h
", host, "-p ",
// Integer.toString(port)})`
// because this poisons the SingletonManager and puts it into SERVER mode
- Admin.signalGracefulShutdown(ctx, gcAddress.toString());
+ Admin.signalGracefulShutdown(ctx, gcAddress);
Wait.waitFor(() -> {
control.refreshProcesses(ServerType.GARBAGE_COLLECTOR);
return control.getProcesses(ServerType.GARBAGE_COLLECTOR).isEmpty();
@@ -183,7 +183,7 @@ public class GracefulShutdownIT extends
SharedMiniClusterBase {
final List<String> tservers =
client.instanceOperations().getTabletServers();
assertEquals(2, tservers.size());
final HostAndPort tserverAddress =
HostAndPort.fromString(tservers.get(0));
- Admin.signalGracefulShutdown(ctx, tserverAddress.toString());
+ Admin.signalGracefulShutdown(ctx, tserverAddress);
Wait.waitFor(() -> {
control.refreshProcesses(ServerType.TABLET_SERVER);
return control.getProcesses(ServerType.TABLET_SERVER).size() == 1;
@@ -197,7 +197,7 @@ public class GracefulShutdownIT extends
SharedMiniClusterBase {
final List<String> managers =
client.instanceOperations().getManagerLocations();
assertEquals(1, managers.size());
final HostAndPort managerAddress =
HostAndPort.fromString(managers.get(0));
- Admin.signalGracefulShutdown(ctx, managerAddress.toString());
+ Admin.signalGracefulShutdown(ctx, managerAddress);
Wait.waitFor(() -> {
control.refreshProcesses(ServerType.MANAGER);
return control.getProcesses(ServerType.MANAGER).isEmpty();
@@ -227,7 +227,7 @@ public class GracefulShutdownIT extends
SharedMiniClusterBase {
client.tableOperations().compact(tableName, cc);
Wait.waitFor(
() ->
ExternalCompactionTestUtils.getRunningCompactions(ctx).getCompactionsSize() >
0);
- Admin.signalGracefulShutdown(ctx, compactorAddress.toString());
+ Admin.signalGracefulShutdown(ctx, compactorAddress);
Wait.waitFor(() -> {
control.refreshProcesses(ServerType.COMPACTOR);
return control.getProcesses(ServerType.COMPACTOR).isEmpty();
@@ -252,7 +252,7 @@ public class GracefulShutdownIT extends
SharedMiniClusterBase {
assertNotNull(e);
count++;
if (count == 2) {
- Admin.signalGracefulShutdown(ctx, sserver.toString());
+ Admin.signalGracefulShutdown(ctx, sserver);
}
}
assertEquals(10, count);