diff options
author | dormando <dormando@rydia.net> | 2021-06-09 15:09:53 -0700 |
---|---|---|
committer | dormando <dormando@rydia.net> | 2021-06-10 11:24:15 -0700 |
commit | 6a1802cb2a180971c328d9820df23336eec72c0f (patch) | |
tree | b90933420ae79f7e6e95389bdf503f4c73c8c738 | |
parent | 3d178cfd3241764acb789c166f1b0209457f2aff (diff) | |
download | memcached-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.txt | 12 | ||||
-rw-r--r-- | memcached.c | 5 | ||||
-rw-r--r-- | memcached.h | 1 | ||||
-rw-r--r-- | proto_text.c | 36 | ||||
-rw-r--r-- | t/metaget.t | 64 |
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; } |