[PATCH 5/6] Implement 'noreply' option for update commands.

Tomash Brechko tomash.brechko at gmail.com
Thu Nov 8 14:56:38 UTC 2007


Commands add, set, replace, append, prepend and cas can take
last optional parameter, 'noreply', which instructs the server to
not send the reply.
---
 trunk/server/doc/protocol.txt |    6 +++++-
 trunk/server/memcached.c      |   21 ++++++++++++++++++---
 trunk/server/memcached.h      |    2 ++
 trunk/server/t/noreply.t      |   32 ++++++++++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 4 deletions(-)
 create mode 100644 trunk/server/t/noreply.t

diff --git a/trunk/server/doc/protocol.txt b/trunk/server/doc/protocol.txt
index 41cc9a7..14cd1e3 100644
--- a/trunk/server/doc/protocol.txt
+++ b/trunk/server/doc/protocol.txt
@@ -126,7 +126,8 @@ Storage commands
 
 First, the client sends a command line which looks like this:
 
-<command name> <key> <flags> <exptime> <bytes> [<cas unqiue>]\r\n
+<command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
+cas <key> <flags> <exptime> <bytes> <cas unqiue> [noreply]\r\n
 
 - <command name> is "set", "add", "replace", "append", "prepend", or "cas"
 
@@ -145,6 +146,9 @@ First, the client sends a command line which looks like this:
   "cas" is a check and set operation which means "store this data but
   only if no one else has updated since I last fetched it."
 
+  "noreply" optional parameter instructs the server to not send the
+  reply.
+
 - <key> is the key under which the client asks to store the data
 
 - <flags> is an arbitrary 16-bit unsigned integer (written out in
diff --git a/trunk/server/memcached.c b/trunk/server/memcached.c
index dd3fbbe..3a35b84 100644
--- a/trunk/server/memcached.c
+++ b/trunk/server/memcached.c
@@ -366,6 +366,8 @@ conn *conn_new(const int sfd, const int init_state, const int event_flags,
     c->bucket = -1;
     c->gen = 0;
 
+    c->noreply = false;
+
     event_set(&c->event, sfd, event_flags, event_handler, (void *)c);
     event_base_set(base, &c->event);
     c->ev_flags = event_flags;
@@ -659,6 +661,12 @@ static void out_string(conn *c, const char *str) {
 
     assert(c != NULL);
 
+    if (c->noreply) {
+        c->noreply = false;
+        conn_set_state(c, conn_read);
+        return;
+    }
+
     if (settings.verbose > 1)
         fprintf(stderr, ">%d %s\n", c->sfd, str);
 
@@ -802,7 +810,7 @@ typedef struct token_s {
 #define KEY_TOKEN 1
 #define KEY_MAX_LENGTH 250
 
-#define MAX_TOKENS 7
+#define MAX_TOKENS 8
 
 /*
  * Tokenize the command string by replacing whitespace with '\0' and update
@@ -1210,6 +1218,7 @@ 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);
 
@@ -1228,6 +1237,12 @@ 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)) {
@@ -1530,7 +1545,7 @@ static void process_command(conn *c, char *command) {
 
         process_get_command(c, tokens, ntokens, false);
 
-    } else if (ntokens == 6 &&
+    } else if ((ntokens == 6 || ntokens == 7) &&
                ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) ||
                 (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) ||
                 (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)) ||
@@ -1539,7 +1554,7 @@ static void process_command(conn *c, char *command) {
 
         process_update_command(c, tokens, ntokens, comm, false);
 
-    } else if (ntokens == 7 && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0)) {
+    } else if ((ntokens == 7 || ntokens == 8) && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0)) {
 
         process_update_command(c, tokens, ntokens, NREAD_REPLACE, true);
 
diff --git a/trunk/server/memcached.h b/trunk/server/memcached.h
index 1ca73e8..501e431 100644
--- a/trunk/server/memcached.h
+++ b/trunk/server/memcached.h
@@ -205,6 +205,8 @@ typedef struct {
     int    bucket;    /* bucket number for the next command, if running as
                          a managed instance. -1 (_not_ 0) means invalid. */
     int    gen;       /* generation requested for the bucket */
+
+    bool   noreply;   /* True if the reply should not be sent.  */
 } conn;
 
 /* number of virtual buckets for a managed instance */
diff --git a/trunk/server/t/noreply.t b/trunk/server/t/noreply.t
new file mode 100644
index 0000000..fe9c33b
--- /dev/null
+++ b/trunk/server/t/noreply.t
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+
+use strict;
+use Test::More tests => 6;
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+use MemcachedTest;
+
+
+my $server = new_memcached();
+my $sock = $server->sock;
+
+
+# Test that all update commands can take 'noreply' parameter.
+print $sock "add noreply:foo 0 0 1 noreply\r\n1\r\n";
+mem_get_is($sock, "noreply:foo", "1");
+
+print $sock "set noreply:foo 0 0 1 noreply\r\n2\r\n";
+mem_get_is($sock, "noreply:foo", "2");
+
+print $sock "replace noreply:foo 0 0 1 noreply\r\n3\r\n";
+mem_get_is($sock, "noreply:foo", "3");
+
+print $sock "append noreply:foo 0 0 1 noreply\r\n4\r\n";
+mem_get_is($sock, "noreply:foo", "34");
+
+print $sock "prepend noreply:foo 0 0 1 noreply\r\n5\r\n";
+my @result = mem_gets($sock, "noreply:foo");
+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");
-- 
1.5.3.5.529.ge3d6d


More information about the memcached mailing list