[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