[PATCH 2/3] Add noreply parameter to delete, incr, decr, flush_all,
verbosity commands.
Tomash Brechko
tomash.brechko at gmail.com
Fri Nov 9 12:31:49 UTC 2007
Also update documentation for delete: mark <time> as optional.
---
trunk/server/doc/protocol.txt | 42 ++++++++++++++++++++++++--------------
trunk/server/memcached.c | 44 +++++++++++++++++++++++++++++-----------
trunk/server/t/noreply.t | 15 +++++++++++++-
3 files changed, 72 insertions(+), 29 deletions(-)
diff --git a/trunk/server/doc/protocol.txt b/trunk/server/doc/protocol.txt
index 4c93517..589d25c 100644
--- a/trunk/server/doc/protocol.txt
+++ b/trunk/server/doc/protocol.txt
@@ -245,7 +245,7 @@ Deletion
The command "delete" allows for explicit deletion of items:
-delete <key> <time>\r\n
+delete <key> [<time>] [noreply]\r\n
- <key> is the key of the item the client wishes the server to delete
@@ -261,6 +261,10 @@ delete <key> <time>\r\n
(which means that the item will be deleted immediately and further
storage commands with this key will succeed).
+- "noreply" optional parameter instructs the server to not send the
+ reply. See the note in Storage commands regarding malformed
+ requests.
+
The response line to this command can be one of:
- "DELETED\r\n" to indicate success
@@ -285,17 +289,21 @@ non-existent key exists with value 0; instead, they will fail.
The client sends the command line:
-incr <key> <value>\r\n
+incr <key> <value> [noreply]\r\n
or
-decr <key> <value>\r\n
+decr <key> <value> [noreply]\r\n
- <key> is the key of the item the client wishes to change
- <value> is the amount by which the client wants to increase/decrease
the item. It is a decimal representation of a 64-bit unsigned integer.
+- "noreply" optional parameter instructs the server to not send the
+ reply. See the note in Storage commands regarding malformed
+ requests.
+
The response will be one of:
- "NOT_FOUND\r\n" to indicate the item with this value was not found
@@ -399,16 +407,17 @@ Other commands
--------------
"flush_all" is a command with an optional numeric argument. It always
-succeeds, and the server sends "OK\r\n" in response. Its effect is to
-invalidate all existing items immediately (by default) or after the
-expiration specified. After invalidation none of the items will be returned
-in response to a retrieval command (unless it's stored again under the
-same key *after* flush_all has invalidated the items). flush_all doesn't
-actually free all the memory taken up by existing items; that will
-happen gradually as new items are stored. The most precise definition
-of what flush_all does is the following: it causes all items whose
-update time is earlier than the time at which flush_all was set to be
-executed to be ignored for retrieval purposes.
+succeeds, and the server sends "OK\r\n" in response (unless "noreply"
+is given as the last parameter). Its effect is to invalidate all
+existing items immediately (by default) or after the expiration
+specified. After invalidation none of the items will be returned in
+response to a retrieval command (unless it's stored again under the
+same key *after* flush_all has invalidated the items). flush_all
+doesn't actually free all the memory taken up by existing items; that
+will happen gradually as new items are stored. The most precise
+definition of what flush_all does is the following: it causes all
+items whose update time is earlier than the time at which flush_all
+was set to be executed to be ignored for retrieval purposes.
The intent of flush_all with a delay, was that in a setting where you
have a pool of memcached servers, and you need to flush all content,
@@ -431,9 +440,10 @@ In response, the server sends
"VERSION <version>\r\n", where <version> is the version string for the
server.
-"verbosity" is a command with a numeric argument. It always
-succeeds, and the server sends "OK\r\n" in response. Its effect is to
-set the verbosity level of the logging output.
+"verbosity" is a command with a numeric argument. It always succeeds,
+and the server sends "OK\r\n" in response (unless "noreply" is given
+as the last parameter). Its effect is to set the verbosity level of
+the logging output.
"quit" is a command with no arguments:
diff --git a/trunk/server/memcached.c b/trunk/server/memcached.c
index 3a35b84..5a30251 100644
--- a/trunk/server/memcached.c
+++ b/trunk/server/memcached.c
@@ -880,6 +880,23 @@ static void write_and_free(conn *c, char *buf, int bytes) {
}
}
+static inline void set_noreply_maybe(conn *c, token_t *tokens, size_t ntokens)
+{
+ int noreply_index = ntokens - 2;
+
+ /*
+ NOTE: this function is not the first place where we are going to
+ send the reply. We could send it instead from process_command()
+ if the request line has wrong number of tokens. However parsing
+ malformed line for "noreply" option is not reliable anyway, so
+ it can't be helped.
+ */
+ if (tokens[noreply_index].value
+ && strcmp(tokens[noreply_index].value, "noreply") == 0) {
+ c->noreply = true;
+ }
+}
+
inline static void process_stats_detail(conn *c, const char *command) {
assert(c != NULL);
@@ -1218,10 +1235,11 @@ static void process_update_command(conn *c, token_t *tokens, const size_t ntoken
int vlen, old_vlen;
uint32_t req_memory_ptr, in_memory_ptr;
item *it, *old_it;
- int noreply_index = 5;
assert(c != NULL);
+ set_noreply_maybe(c, tokens, ntokens);
+
if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
out_string(c, "CLIENT_ERROR bad command line format");
return;
@@ -1237,12 +1255,6 @@ static void process_update_command(conn *c, token_t *tokens, const size_t ntoken
if (handle_cas)
{
req_memory_ptr = strtoull(tokens[5].value, NULL, 10);
- ++noreply_index;
- }
-
- if (tokens[noreply_index].value
- && strcmp(tokens[noreply_index].value, "noreply") == 0) {
- c->noreply = true;
}
if(errno == ERANGE || ((flags == 0 || exptime == 0) && errno == EINVAL)) {
@@ -1328,6 +1340,8 @@ static void process_arithmetic_command(conn *c, token_t *tokens, const size_t nt
assert(c != NULL);
+ set_noreply_maybe(c, tokens, ntokens);
+
if(tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
out_string(c, "CLIENT_ERROR bad command line format");
return;
@@ -1424,6 +1438,8 @@ static void process_delete_command(conn *c, token_t *tokens, const size_t ntoken
assert(c != NULL);
+ set_noreply_maybe(c, tokens, ntokens);
+
if (settings.managed) {
int bucket = c->bucket;
if (bucket == -1) {
@@ -1508,6 +1524,8 @@ static void process_verbosity_command(conn *c, token_t *tokens, const size_t nto
assert(c != NULL);
+ set_noreply_maybe(c, tokens, ntokens);
+
level = strtoul(tokens[1].value, NULL, 10);
settings.verbose = level > MAX_VERBOSITY_LEVEL ? MAX_VERBOSITY_LEVEL : level;
out_string(c, "OK");
@@ -1558,7 +1576,7 @@ static void process_command(conn *c, char *command) {
process_update_command(c, tokens, ntokens, NREAD_REPLACE, true);
- } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) {
+ } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) {
process_arithmetic_command(c, tokens, ntokens, 1);
@@ -1566,11 +1584,11 @@ static void process_command(conn *c, char *command) {
process_get_command(c, tokens, ntokens, true);
- } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) {
+ } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) {
process_arithmetic_command(c, tokens, ntokens, 0);
- } else if (ntokens >= 3 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) {
+ } else if (ntokens >= 3 && ntokens <= 5 && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) {
process_delete_command(c, tokens, ntokens);
@@ -1639,7 +1657,7 @@ static void process_command(conn *c, char *command) {
process_stat(c, tokens, ntokens);
- } else if (ntokens >= 2 && ntokens <= 3 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) {
+ } else if (ntokens >= 2 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) {
time_t exptime = 0;
set_current_time();
@@ -1650,6 +1668,8 @@ static void process_command(conn *c, char *command) {
return;
}
+ set_noreply_maybe(c, tokens, ntokens);
+
exptime = strtol(tokens[1].value, NULL, 10);
if(errno == ERANGE) {
out_string(c, "CLIENT_ERROR bad command line format");
@@ -1699,7 +1719,7 @@ static void process_command(conn *c, char *command) {
#else
out_string(c, "CLIENT_ERROR Slab reassignment not supported");
#endif
- } else if (ntokens == 3 && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) {
+ } else if ((ntokens == 3 || ntokens == 4) && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) {
process_verbosity_command(c, tokens, ntokens);
} else {
out_string(c, "ERROR");
diff --git a/trunk/server/t/noreply.t b/trunk/server/t/noreply.t
index fe9c33b..0a0b8c5 100644
--- a/trunk/server/t/noreply.t
+++ b/trunk/server/t/noreply.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use strict;
-use Test::More tests => 6;
+use Test::More tests => 9;
use FindBin qw($Bin);
use lib "$Bin/lib";
use MemcachedTest;
@@ -12,6 +12,10 @@ my $sock = $server->sock;
# Test that all update commands can take 'noreply' parameter.
+print $sock "flush_all noreply\r\n";
+
+print $sock "verbosity 0 noreply\r\n";
+
print $sock "add noreply:foo 0 0 1 noreply\r\n1\r\n";
mem_get_is($sock, "noreply:foo", "1");
@@ -30,3 +34,12 @@ ok($result[1] eq "534");
print $sock "cas noreply:foo 0 0 1 $result[0] noreply\r\n6\r\n";
mem_get_is($sock, "noreply:foo", "6");
+
+print $sock "incr noreply:foo 3 noreply\r\n";
+mem_get_is($sock, "noreply:foo", "9");
+
+print $sock "decr noreply:foo 2 noreply\r\n";
+mem_get_is($sock, "noreply:foo", "7");
+
+print $sock "delete noreply:foo noreply\r\n";
+mem_get_is($sock, "noreply:foo");
--
1.5.3.5.529.ge3d6d
More information about the memcached
mailing list