summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2021-06-09 15:09:53 -0700
committerdormando <dormando@rydia.net>2021-06-10 11:24:15 -0700
commit6a1802cb2a180971c328d9820df23336eec72c0f (patch)
treeb90933420ae79f7e6e95389bdf503f4c73c8c738
parent3d178cfd3241764acb789c166f1b0209457f2aff (diff)
downloadmemcached-6a1802cb2a180971c328d9820df23336eec72c0f.tar.gz
meta: response code OK -> HD
I had the response code as "HD" in the past, but standardized on OK while merging a number of "OK-like" rescodes together. This was a mistake; as many "generic" memcached response codes use "OK". Most of these are management or specialized uncommon commands. With this, a client response parser can know for sure if a response is to a meta command, or some other command. `-o meta_response_old` starttime option has been added, valid for the next 3 months, which switches the response code back from HD to OK. In case any existing users depended on this and need time to migrate.
-rw-r--r--doc/protocol.txt12
-rw-r--r--memcached.c5
-rw-r--r--memcached.h1
-rw-r--r--proto_text.c36
-rw-r--r--t/metaget.t64
5 files changed, 74 insertions, 44 deletions
diff --git a/doc/protocol.txt b/doc/protocol.txt
index bbaabef..623982d 100644
--- a/doc/protocol.txt
+++ b/doc/protocol.txt
@@ -523,7 +523,7 @@ VA <size> <flags>*\r\n
If the request did not ask for a value in the response (v) flag, the server
response looks like:
-OK <flags>*\r\n
+HD <flags>*\r\n
If the request resulted in a miss, the response looks like:
@@ -609,7 +609,7 @@ access time.
- v: return item value in <data block>
The data block for a metaget response is optional, requiring this flag to be
-passed in. The response code also changes from "OK" to "VA <size>"
+passed in. The response code also changes from "HD" to "VA <size>"
These flags can modify the item:
- N(token): vivify on miss, takes TTL as a argument
@@ -698,7 +698,7 @@ the reply, which is of the format:
Where CD is one of:
-- "OK" (STORED), to indicate success.
+- "HD" (STORED), to indicate success.
- "NS" (NOT_STORED), to indicate the data was not stored, but not
because of an error.
@@ -746,7 +746,7 @@ See description under 'Meta Get'
Noreply is a method of reducing the amount of data sent back by memcached to
the client for normal responses. In the case of metaset, a response that
-would start with "OK" will not be sent. Any other code, such as "EX"
+would start with "HD" will not be sent. Any other code, such as "EX"
(EXISTS) will still be returned.
Errors are always returned.
@@ -782,7 +782,7 @@ The response is in the format:
Where CD is one of:
-- "OK" (DELETED), to indicate success
+- "HD" (DELETED), to indicate success
- "NF" (NOT_FOUND), to indicate that the item with this key was not found.
@@ -847,7 +847,7 @@ The response is in the format:
Where CD is one of:
-- "OK" to indicate success
+- "HD" to indicate success
- "NF" (NOT_FOUND), to indicate that the item with this key was not found.
diff --git a/memcached.c b/memcached.c
index b6d4477..ce9f8e6 100644
--- a/memcached.c
+++ b/memcached.c
@@ -4586,6 +4586,7 @@ int main (int argc, char **argv) {
DROP_PRIVILEGES,
RESP_OBJ_MEM_LIMIT,
READ_BUF_MEM_LIMIT,
+ META_RESPONSE_OLD,
#ifdef TLS
SSL_CERT,
SSL_KEY,
@@ -4639,6 +4640,7 @@ int main (int argc, char **argv) {
[DROP_PRIVILEGES] = "drop_privileges",
[RESP_OBJ_MEM_LIMIT] = "resp_obj_mem_limit",
[READ_BUF_MEM_LIMIT] = "read_buf_mem_limit",
+ [META_RESPONSE_OLD] = "meta_response_old",
#ifdef TLS
[SSL_CERT] = "ssl_chain_cert",
[SSL_KEY] = "ssl_key",
@@ -5235,6 +5237,9 @@ int main (int argc, char **argv) {
start_lru_maintainer = false;
settings.lru_segmented = false;
break;
+ case META_RESPONSE_OLD:
+ settings.meta_response_old = true;
+ break;
#ifdef TLS
case SSL_CERT:
if (subopts_value == NULL) {
diff --git a/memcached.h b/memcached.h
index 1202fa0..04bd169 100644
--- a/memcached.h
+++ b/memcached.h
@@ -460,6 +460,7 @@ struct settings {
bool drop_privileges; /* Whether or not to drop unnecessary process privileges */
bool watch_enabled; /* allows watch commands to be dropped */
bool relaxed_privileges; /* Relax process restrictions when running testapp */
+ bool meta_response_old; /* use "OK" instead of "HD". for response code TEMPORARY! */
#ifdef EXTSTORE
unsigned int ext_io_threadcount; /* number of IO threads to run. */
unsigned int ext_page_size; /* size in megabytes of storage pages. */
diff --git a/proto_text.c b/proto_text.c
index f572a7a..22be817 100644
--- a/proto_text.c
+++ b/proto_text.c
@@ -60,7 +60,11 @@ static void _finalize_mset(conn *c, enum store_item_type ret) {
switch (ret) {
case STORED:
- memcpy(p, "OK", 2);
+ if (settings.meta_response_old) {
+ memcpy(p, "OK", 2);
+ } else {
+ memcpy(p, "HD", 2);
+ }
// Only place noreply is used for meta cmds is a nominal response.
if (c->noreply) {
resp->skip = true;
@@ -1129,7 +1133,11 @@ static void process_mget_command(conn *c, token_t *tokens, const size_t ntokens)
memcpy(p, "VA ", 3);
p = itoa_u32(it->nbytes-2, p+3);
} else {
- memcpy(p, "OK", 2);
+ if (settings.meta_response_old) {
+ memcpy(p, "OK", 2);
+ } else {
+ memcpy(p, "HD", 2);
+ }
p += 2;
}
@@ -1615,7 +1623,11 @@ static void process_mdelete_command(conn *c, token_t *tokens, const size_t ntoke
// Clients can noreply nominal responses.
if (c->noreply)
resp->skip = true;
- memcpy(resp->wbuf, "OK ", 3);
+ if (settings.meta_response_old) {
+ memcpy(resp->wbuf, "OK ", 3);
+ } else {
+ memcpy(resp->wbuf, "HD ", 3);
+ }
} else {
pthread_mutex_lock(&c->thread->stats.mutex);
c->thread->stats.slab_stats[ITEM_clsid(it)].delete_hits++;
@@ -1625,7 +1637,11 @@ static void process_mdelete_command(conn *c, token_t *tokens, const size_t ntoke
STORAGE_delete(c->thread->storage, it);
if (c->noreply)
resp->skip = true;
- memcpy(resp->wbuf, "OK ", 3);
+ if (settings.meta_response_old) {
+ memcpy(resp->wbuf, "OK ", 3);
+ } else {
+ memcpy(resp->wbuf, "HD ", 3);
+ }
}
goto cleanup;
} else {
@@ -1728,7 +1744,11 @@ static void process_marithmetic_command(conn *c, token_t *tokens, const size_t n
case OK:
if (c->noreply)
resp->skip = true;
- memcpy(resp->wbuf, "OK ", 3);
+ if (settings.meta_response_old) {
+ memcpy(resp->wbuf, "OK ", 3);
+ } else {
+ memcpy(resp->wbuf, "HD ", 3);
+ }
break;
case NON_NUMERIC:
errstr = "CLIENT_ERROR cannot increment or decrement non-numeric value";
@@ -1786,7 +1806,11 @@ static void process_marithmetic_command(conn *c, token_t *tokens, const size_t n
memcpy(p, "VA ", 3);
p = itoa_u32(vlen, p+3);
} else {
- memcpy(p, "OK", 2);
+ if (settings.meta_response_old) {
+ memcpy(p, "OK", 2);
+ } else {
+ memcpy(p, "HD", 2);
+ }
p += 2;
}
diff --git a/t/metaget.t b/t/metaget.t
index 3293d9e..d346ea7 100644
--- a/t/metaget.t
+++ b/t/metaget.t
@@ -16,7 +16,7 @@ my $sock = $server->sock;
# VA [size] [flags]\r\n
# data\r\n
# or:
-# OK [flags]\r\n
+# HD [flags]\r\n
# or:
# EN\r\n
# flags are single 'f' or 'f1234' or 'fTEXT'
@@ -46,8 +46,8 @@ my $sock = $server->sock;
# ms [key] [valuelen] [flags]\r\n
# value\r\n
# response:
-# OK [flags]\r\n
-# OK STORED, NS NOT_STORED, EX EXISTS, NF NOT_FOUND
+# HD [flags]\r\n
+# HD STORED, NS NOT_STORED, EX EXISTS, NF NOT_FOUND
#
# flags:
# - q: noreply
@@ -67,7 +67,7 @@ my $sock = $server->sock;
#
# md [key] [flags]\r\n
# response:
-# OK [flags]
+# HD [flags]
# flags:
# - q: noreply
# - T(token): updates TTL
@@ -78,8 +78,8 @@ my $sock = $server->sock;
#
# ma [key] [flags]\r\n
# response:
-# OK [flags]\r\n
-# OK, NS NOT_STORED, EX EXISTS, NF NOT_FOUND
+# HD [flags]\r\n
+# HD, NS NOT_STORED, EX EXISTS, NF NOT_FOUND
# or:
# VA [size] [flags]\r\n
# data\r\n
@@ -152,7 +152,7 @@ my $sock = $server->sock;
# 44OG44K544OI is "tesuto" in katakana
my $tesuto = "44OG44K544OI";
print $sock "ms $tesuto 2 b\r\npo\r\n";
- like(scalar <$sock>, qr/^OK/, "set with encoded key");
+ like(scalar <$sock>, qr/^HD/, "set with encoded key");
my $res = mget($sock, $tesuto, 'v');
ok(! exists $res->{val}, "encoded key doesn't exist");
@@ -176,7 +176,7 @@ my $sock = $server->sock;
like(scalar <$sock>, qr/^STORED/, "stored with set");
print $sock "ma mo\r\n";
- like(scalar <$sock>, qr/^OK/, "incr'd a set value");
+ like(scalar <$sock>, qr/^HD/, "incr'd a set value");
print $sock "set mo 0 0 1\r\nq\r\n";
like(scalar <$sock>, qr/^STORED/, "stored with set");
@@ -185,7 +185,7 @@ my $sock = $server->sock;
like(scalar <$sock>, qr/^CLIENT_ERROR /, "cannot incr non-numeric value");
print $sock "ma mu N90\r\n";
- like(scalar <$sock>, qr/^OK/, "incr with seed");
+ like(scalar <$sock>, qr/^HD/, "incr with seed");
my $res = mget($sock, 'mu', 's t v Ofoo k');
ok(keys %$res, "not a miss");
ok(find_flags($res, 'st'), "got main flags back");
@@ -235,7 +235,7 @@ my $sock = $server->sock;
{
diag "mset mode switch";
print $sock "ms modedefault 2 T120\r\naa\r\n";
- like(scalar <$sock>, qr/^OK/, "default set mode");
+ like(scalar <$sock>, qr/^HD/, "default set mode");
mget_is({ sock => $sock,
flags => 's v',
eflags => 's2' },
@@ -246,7 +246,7 @@ my $sock = $server->sock;
like(scalar <$sock>, qr/^NS/, "add mode gets NOT_STORED");
# Win an add
print $sock "ms modetest 2 T120 ME\r\nbb\r\n";
- like(scalar <$sock>, qr/^OK/, "add mode");
+ like(scalar <$sock>, qr/^HD/, "add mode");
mget_is({ sock => $sock,
flags => 's v',
eflags => 's2' },
@@ -254,14 +254,14 @@ my $sock = $server->sock;
# append
print $sock "ms modetest 2 T120 MA\r\ncc\r\n";
- like(scalar <$sock>, qr/^OK/, "append mode");
+ like(scalar <$sock>, qr/^HD/, "append mode");
mget_is({ sock => $sock,
flags => 's v',
eflags => 's4' },
'modetest', 'bbcc', "retrieved test value");
# prepend
print $sock "ms modetest 2 T120 MP\r\naa\r\n";
- like(scalar <$sock>, qr/^OK/, "append mode");
+ like(scalar <$sock>, qr/^HD/, "append mode");
mget_is({ sock => $sock,
flags => 's v',
eflags => 's6' },
@@ -271,7 +271,7 @@ my $sock = $server->sock;
print $sock "ms modereplace 2 T120 MR\r\nzz\r\n";
like(scalar <$sock>, qr/^NS/, "fail replace mode");
print $sock "ms modetest 2 T120 MR\r\nxx\r\n";
- like(scalar <$sock>, qr/^OK/, "replace mode");
+ like(scalar <$sock>, qr/^HD/, "replace mode");
mget_is({ sock => $sock,
flags => 's v',
eflags => 's2' },
@@ -279,7 +279,7 @@ my $sock = $server->sock;
# explicit set
print $sock "ms modetest 2 T120 MS\r\nyy\r\n";
- like(scalar <$sock>, qr/^OK/, "force set mode");
+ like(scalar <$sock>, qr/^HD/, "force set mode");
# invalid mode
print $sock "ms modetest 2 T120 MZ\r\ntt\r\n";
@@ -321,7 +321,7 @@ my $sock = $server->sock;
# TODO: the actual CAS command should work here too?
my $cas = get_flag($res, 'c');
print $sock "ms needwin 2 C$cas T120\r\nmu\r\n";
- like(scalar <$sock>, qr/^OK/, "SET: CAS matched");
+ like(scalar <$sock>, qr/^HD/, "SET: CAS matched");
# now we repeat the original mget, but the data should be different.
$res = mget($sock, 'needwin', 's k t c v N30');
@@ -353,7 +353,7 @@ my $sock = $server->sock;
# again, but succeed.
$cas = get_flag($res, 'c');
print $sock "ms needwin 4 C$cas T300\r\nzuuu\r\n";
- like(scalar <$sock>, qr/^OK/, "SET: CAS matched");
+ like(scalar <$sock>, qr/^HD/, "SET: CAS matched");
# now we repeat the original mget, but the data should be different.
$res = mget($sock, 'needwin', 's t c v N30');
@@ -371,7 +371,7 @@ my $sock = $server->sock;
{
# Set key with lower initial TTL.
print $sock "ms gatkey 4 T100\r\nooom\r\n";
- like(scalar <$sock>, qr/^OK/, "set gatkey");
+ like(scalar <$sock>, qr/^HD/, "set gatkey");
# Coolish side feature and/or bringer of bugs: 't' before 'T' gives TTL
# before adjustment. 'T' before 't' gives TTL after adjustment.
@@ -387,7 +387,7 @@ my $sock = $server->sock;
{
# Set key with lower initial TTL.
print $sock "ms hidevalue 4 T100\r\nhide\r\n";
- like(scalar <$sock>, qr/^OK/, "set hidevalue");
+ like(scalar <$sock>, qr/^HD/, "set hidevalue");
my $res = mget($sock, 'hidevalue', 's t');
ok(keys %$res, "not a miss");
@@ -401,7 +401,7 @@ my $sock = $server->sock;
# test hit-before? flag
{
print $sock "ms hitflag 3 T100\r\nhit\r\n";
- like(scalar <$sock>, qr/^OK/, "set hitflag");
+ like(scalar <$sock>, qr/^HD/, "set hitflag");
my $res = mget($sock, 'hitflag', 's t h');
ok(keys %$res, "not a miss");
@@ -415,7 +415,7 @@ my $sock = $server->sock;
# test no-update flag
{
print $sock "ms noupdate 3 T100\r\nhit\r\n";
- like(scalar <$sock>, qr/^OK/, "set noupdate");
+ like(scalar <$sock>, qr/^HD/, "set noupdate");
my $res = mget($sock, 'noupdate', 's t u h');
ok(keys %$res, "not a miss");
@@ -433,7 +433,7 @@ my $sock = $server->sock;
# test last-access time
{
print $sock "ms la_test 2 T100\r\nla\r\n";
- like(scalar <$sock>, qr/^OK/, "set la_test");
+ like(scalar <$sock>, qr/^HD/, "set la_test");
sleep 2;
my $res = mget($sock, 'la_test', 's t l');
@@ -464,7 +464,7 @@ my $sock = $server->sock;
# Lets mark the sucker as invalid, and drop its TTL to 30s
diag "running mdelete";
print $sock "md toinv I T30\r\n";
- like(scalar <$sock>, qr/^OK /, "mdelete'd key");
+ like(scalar <$sock>, qr/^HD /, "mdelete'd key");
# TODO: decide on if we need an explicit flag for "if I fetched a stale
# value, does winning matter?
@@ -485,7 +485,7 @@ my $sock = $server->sock;
like(scalar <$sock>, qr/^EX/, "failed to SET: low CAS didn't match");
print $sock "ms toinv 1 I T90 C1\r\nf\r\n";
- like(scalar <$sock>, qr/^OK/, "SET an invalid/stale item");
+ like(scalar <$sock>, qr/^HD/, "SET an invalid/stale item");
diag "confirm item still stale, and TTL wasn't raised.";
$res = mget($sock, 'toinv', 's t c v');
@@ -500,7 +500,7 @@ my $sock = $server->sock;
diag "do valid mset";
$cas = get_flag($res, 'c');
print $sock "ms toinv 1 T90 C$cas\r\ng\r\n";
- like(scalar <$sock>, qr/^OK/, "SET over the stale item");
+ like(scalar <$sock>, qr/^HD/, "SET over the stale item");
$res = mget($sock, 'toinv', 's t c v');
ok(keys %$res, "not a miss");
@@ -523,7 +523,7 @@ my $sock = $server->sock;
print $sock "mg quiet s v q\r\n";
diag "now purposefully cause an error\r\n";
print $sock "ms quiet\r\n";
- like(scalar <$sock>, qr/^CLIENT_ERROR/, "resp not OK, or EN");
+ like(scalar <$sock>, qr/^CLIENT_ERROR/, "resp not HD, or EN");
# Now try a pipelined get. Throw an mnop at the end
print $sock "ms quiet 2 q\r\nbo\r\n";
@@ -538,14 +538,14 @@ my $sock = $server->sock;
# "quiet" won't do anything with autoviv, since the only case (miss)
# should return data anyway.
print $sock "mg quietautov s N30 t q\r\n";
- like(scalar <$sock>, qr/^OK s0/, "quiet doesn't override autovivication");
+ like(scalar <$sock>, qr/^HD s0/, "quiet doesn't override autovivication");
}
{
my $k = 'otest';
diag "testing mget opaque";
print $sock "ms $k 2 T100\r\nra\r\n";
- like(scalar <$sock>, qr/^OK/, "set $k");
+ like(scalar <$sock>, qr/^HD/, "set $k");
my $res = mget($sock, $k, 't v Oopaque');
is(get_flag($res, 'O'), 'opaque', "O flag returned opaque");
@@ -560,10 +560,10 @@ my $sock = $server->sock;
{
diag "pipeline test";
print $sock "ms foo 2 T100\r\nna\r\n";
- like(scalar <$sock>, qr/^OK/, "set foo");
+ like(scalar <$sock>, qr/^HD/, "set foo");
print $sock "mg foo s\r\nmg foo s\r\nquit\r\nmg foo s\r\n";
- like(scalar <$sock>, qr/^OK /, "got resp");
- like(scalar <$sock>, qr/^OK /, "got resp");
+ like(scalar <$sock>, qr/^HD /, "got resp");
+ like(scalar <$sock>, qr/^HD /, "got resp");
is(scalar <$sock>, undef, "final get didn't run");
}
@@ -725,7 +725,7 @@ sub mget_res {
$r{size} = $1;
$r{flags} = $2;
$r{val} = $3;
- } elsif ($resp =~ m/^OK ([^\r]+)\r\n/gm) {
+ } elsif ($resp =~ m/^HD ([^\r]+)\r\n/gm) {
$r{flags} = $1;
$r{hd} = 1;
}