[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