diff options
-rw-r--r-- | doc/protocol.txt | 6 | ||||
-rw-r--r-- | proto_text.c | 16 | ||||
-rw-r--r-- | t/shutdown.t | 49 |
3 files changed, 67 insertions, 4 deletions
diff --git a/doc/protocol.txt b/doc/protocol.txt index 625db25..2788253 100644 --- a/doc/protocol.txt +++ b/doc/protocol.txt @@ -1695,6 +1695,12 @@ be released back to the OS asynchronously. The argument is in megabytes, not bytes. Input gets multiplied out into megabytes internally. +"shutdown" is a command with an optional argument used to stop memcached with +a kill signal. By default, "shutdown" alone raises SIGINT, though "graceful" +may be specified as the single argument to instead trigger a graceful shutdown +with SIGUSR1. The shutdown command is disabled by default, and can be enabled +with the -A/--enable-shutdown flag. + "version" is a command with no arguments: version\r\n diff --git a/proto_text.c b/proto_text.c index 1101c4e..ecc6f92 100644 --- a/proto_text.c +++ b/proto_text.c @@ -2348,12 +2348,20 @@ static void process_quit_command(conn *c) { c->close_after_write = true; } -static void process_shutdown_command(conn *c) { - if (settings.shutdown_command) { +static void process_shutdown_command(conn *c, token_t *tokens, const size_t ntokens) { + if (!settings.shutdown_command) { + out_string(c, "ERROR: shutdown not enabled"); + return; + } + + if (ntokens == 2) { conn_set_state(c, conn_closing); raise(SIGINT); + } else if (ntokens == 3 && strcmp(tokens[SUBCOMMAND_TOKEN].value, "graceful") == 0) { + conn_set_state(c, conn_closing); + raise(SIGUSR1); } else { - out_string(c, "ERROR: shutdown not enabled"); + out_string(c, "CLIENT_ERROR invalid shutdown mode"); } } @@ -2620,7 +2628,7 @@ static void process_command(conn *c, char *command) { process_stat(c, tokens, ntokens); } else if (strcmp(tokens[COMMAND_TOKEN].value, "shutdown") == 0) { - process_shutdown_command(c); + process_shutdown_command(c, tokens, ntokens); } else if (strcmp(tokens[COMMAND_TOKEN].value, "slabs") == 0) { process_slabs_command(c, tokens, ntokens); diff --git a/t/shutdown.t b/t/shutdown.t new file mode 100644 index 0000000..6dfbd77 --- /dev/null +++ b/t/shutdown.t @@ -0,0 +1,49 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More; +use FindBin qw($Bin); +use lib "$Bin/lib"; +use MemcachedTest; + +# Disabled shutdown (default) +{ + my $server = new_memcached(); + my $sock = $server->sock; + print $sock "shutdown\r\n"; + is(scalar <$sock>, "ERROR: shutdown not enabled\r\n", + "error when shutdown is not enabled"); +} + +# Shutdown command error +{ + my$server = new_memcached("-A"); + my $sock = $server->sock; + print $sock "shutdown foo\r\n"; + like(scalar <$sock>, qr/CLIENT_ERROR/, "rejected invalid shutdown mode"); +} + +# Normal shutdown +{ + my $server = new_memcached("-A"); + my $sock = $server->sock; + print $sock "version\r\n"; + like(scalar <$sock>, qr/VERSION/, "server is initially alive"); + print $sock "shutdown\r\n"; + print $sock "version\r\n"; + is(scalar <$sock>, undef, "server has been normally shut down"); +} + +# Graceful shutdown +{ + my $server = new_memcached("-A"); + my $sock = $server->sock; + print $sock "version\r\n"; + like(scalar <$sock>, qr/VERSION/, "server is initially alive"); + print $sock "shutdown graceful\r\n"; + print $sock "version\r\n"; + is(scalar <$sock>, undef, "server has been gracefully shut down"); +} + +done_testing(); |