8000 move get/gets/gat/gats commands · memcached/memcached@88b4ed4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 88b4ed4

Browse files
committed
move get/gets/gat/gats commands
abstracted multi-key parsing out of the actual get command code. now all the main parsing is finally shared.
1 parent ebfd756 commit 88b4ed4

File tree

4 files changed

+101
-218
lines changed

4 files changed

+101
-218
lines changed

proto_parser.c

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -590,27 +590,18 @@ static inline int make_ascii_get_suffix(char *suffix, item *it, bool return_cas,
590590
return (p - suffix) + 2;
591591
}
592592

593-
void process_get_cmd(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, parser_storage_get_cb storage_cb, bool return_cas, bool should_touch) {
594-
const char *key = MCP_PARSER_KEY(pr);
595-
int nkey = pr->klen;
596-
int32_t exptime_int = 0;
597-
rel_time_t exptime = 0;
593+
int process_get_cmd(LIBEVENT_THREAD *t, const char *key, const int nkey, mc_resp *resp, parser_storage_get_cb storage_cb, rel_time_t exptime, bool return_cas, bool should_touch) {
598594
bool overflow = false; // unused.
599595

600596
if (nkey > KEY_MAX_LENGTH) {
601597
pout_string(resp, "CLIENT_ERROR bad command line format");
602-
return;
603-
}
604-
605-
if (should_touch) {
606-
if (!safe_strtol(&pr->request[pr->tok.tokens[1]], &exptime_int)) {
607-
pout_string(resp, "CLIENT_ERROR invalid exptime argument");
608-
return;
609-
}
610-
exptime = realtime(EXPTIME_TO_POSITIVE_TIME(exptime_int));
598+
return -1;
611599
}
612600

613601
item *it = limited_get(key, nkey, t, exptime, should_touch, DO_UPDATE, &overflow);
602+
if (settings.detail_enabled) {
603+
stats_prefix_record_get(key, nkey, NULL != it);
604+
}
614605
if (it) {
615606
int nbytes = it->nbytes;;
616607
nbytes = it->nbytes;
@@ -631,7 +622,7 @@ void process_get_cmd(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, parser
631622

632623
item_remove(it);
633624
pout_errstring(resp, "SERVER_ERROR out of memory writing get response");
634-
return;
625+
return -1;
635626
}
636627
} else if ((it->it_flags & ITEM_CHUNKED) == 0) {
637628
resp_add_iov(resp, ITEM_data(it), it->nbytes);
@@ -676,8 +667,7 @@ void process_get_cmd(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, parser
676667
pthread_mutex_unlock(&t->stats.mutex);
677668
}
678669

679-
resp_add_iov(resp, "END\r\n", 5);
680-
return;
670+
return 0;
681671
}
682672

683673
item *process_update_cmd_start(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, int comm, bool handle_cas) {

proto_parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ enum proxy_defines {
100100
int process_request(mcp_parser_t *pr, const char *command, size_t cmdlen);
101101

102102
typedef int (*parser_storage_get_cb)(LIBEVENT_THREAD *t, item *it, mc_resp *resp);
103-
void process_get_cmd(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, parser_storage_get_cb storage_cb, bool return_cas, bool should_touch);
103+
int process_get_cmd(LIBEVENT_THREAD *t, const char *key, const int nkey, mc_resp *resp, parser_storage_get_cb storage_cb, rel_time_t exptime, bool return_cas, bool should_touch);
104104
item *process_update_cmd_start(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, int comm, bool handle_cas);
105105
void process_update_cmd(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, int comm, bool handle_cas);
106106
void process_arithmetic_cmd(LIBEVENT_THREAD *t, mcp_parser_t *pr, mc_resp *resp, const bool incr);

proto_text.c

Lines changed: 72 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#include <string.h>
2020
#include <stdlib.h>
2121

22+
#define _DO_CAS true
23+
#define _NO_CAS false
24+
#define _DO_TOUCH true
25+
#define _NO_TOUCH false
26+
2227
#define META_SPACE(p) { \
2328
*p = ' '; \
2429
p++; \
@@ -493,208 +498,81 @@ static inline bool set_noreply_maybe(conn *c, token_t *tokens, size_t ntokens)
493498
return c->resp->noreply;
494499
}
495500

496-
/* client flags == 0 means use no storage for client flags */
497-
static inline int make_ascii_get_suffix(char *suffix, item *it, bool return_cas, int nbytes) {
498-
char *p = suffix;
499-
*p = ' ';
500-
p++;
501-
if (FLAGS_SIZE(it) == 0) {
502-
*p = '0';
503-
p++;
501+
static void process_get_command_err(conn *c, const char *errstr) {
502+
// Use passed in error or rescue the last error while processing.
503+
char wbuf[WRITE_BUFFER_SIZE];
504+
if (errstr) {
505+
memcpy(wbuf, errstr, strlen(errstr));
504506
} else {
505-
p = itoa_u64(*((client_flags_t *) ITEM_suffix(it)), p);
507+
size_t l = c->resp->iov[0].iov_len;
508+
memcpy(wbuf, c->resp->wbuf, l);
509+
wbuf[l] = '\0';
506510
}
507-
*p = ' ';
508-
p = itoa_u32(nbytes-2, p+1);
509-
510-
if (return_cas) {
511-
*p = ' ';
512-
p = itoa_u64(ITEM_get_cas(it), p+1);
511+
conn_release_items(c);
512+
if (!resp_start(c)) {
513+
conn_set_state(c, conn_closing);
514+
return;
513515
}
514-
515-
*p = '\r';
516-
*(p+1) = '\n';
517-
*(p+2) = '\0';
518-
return (p - suffix) + 2;
516+
out_string(c, wbuf);
519517
}
520518

521-
/* ntokens is overwritten here... shrug.. */
522-
static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_cas, bool should_touch) {
523-
char *key;
524-
size_t nkey;
525-
item *it;
526-
token_t *key_token = &tokens[KEY_TOKEN];
527-
int32_t exptime_int = 0;
519+
static void process_get_command(conn *c, LIBEVENT_THREAD *t, mcp_parser_t *pr, parser_storage_get_cb storage_cb, bool return_cas, bool should_touch) {
520+
uint32_t keyoff = pr->tok.tokens[pr->keytoken];
521+
const char *curkey = pr->request + keyoff;
522+
int klen = pr->klen;
523+
const char *kend = NULL;
528524
rel_time_t exptime = 0;
529-
bool fail_length = false;
530-
assert(c != NULL);
531-
mc_resp *resp = c->resp;
532525

533526
if (should_touch) {
534-
// For get and touch commands, use first token as exptime
535-
if (!safe_strtol(tokens[1].value, &exptime_int)) {
527+
int32_t exptime_int = 0;
528+
if (!safe_strtol(&pr->request[pr->tok.tokens[1]], &exptime_int)) {
536529
out_string(c, "CLIENT_ERROR invalid exptime argument");
537530
return;
538531
}
539-
key_token++;
540532
exptime = realtime(EXPTIME_TO_POSITIVE_TIME(exptime_int));
541533
}
542534

543-
do {
544-
while(key_token->length != 0) {
545-
bool overflow; // not used here.
546-
key = key_token->value;
547-
nkey = key_token->length;
548-
549-
if (nkey > KEY_MAX_LENGTH) {
550-
fail_length = true;
551-
goto stop;
552-
}
553-
554-
it = limited_get(key, nkey, c->thread, exptime, should_touch, DO_UPDATE, &overflow);
555-
if (settings.detail_enabled) {
556-
stats_prefix_record_get(key, nkey, NULL != it);
557-
}
558-
if (it) {
559-
/*
560-
* Construct the response. Each hit adds three elements to the
561-
* outgoing data list:
562-
* "VALUE "
563-
* key
564-
* " " + flags + " " + data length + "\r\n" + data (with \r\n)
565-
*/
566-
567-
{
568-
MEMCACHED_COMMAND_GET(c->sfd, ITEM_key(it), it->nkey,
569-
it->nbytes, ITEM_get_cas(it));
570-
int nbytes = it->nbytes;
571-
char *p = resp->wbuf;
572-
memcpy(p, "VALUE ", 6);
573-
p += 6;
574-
memcpy(p, ITEM_key(it), it->nkey);
575-
p += it->nkey;
576-
p += make_ascii_get_suffix(p, it, return_cas, nbytes);
577-
resp_add_iov(resp, resp->wbuf, p - resp->wbuf);
578-
579-
#ifdef EXTSTORE
580-
if (it->it_flags & ITEM_HDR) {
581-
if (storage_get_item(c->thread, it, resp) != 0) {
582-
pthread_mutex_lock(&c->thread->stats.mutex);
583-
c->thread->stats.get_oom_extstore++;
584-
pthread_mutex_unlock(&c->thread->stats.mutex);
585-
586-
item_remove(it);
587-
goto stop;
588-
} else {
589-
assert(resp->io_pending != NULL);
590-
resp->io_pending->c = c;
591-
conn_resp_suspend(c, resp);
592-
}
593-
} else if ((it->it_flags & ITEM_CHUNKED) == 0) {
594-
resp_add_iov(resp, ITEM_data(it), it->nbytes);
595-
} else {
596-
resp_add_chunked_iov(resp, it, it->nbytes);
597-
}
598-
#else
599-
if ((it->it_flags & ITEM_CHUNKED) == 0) {
600-
resp_add_iov(resp, ITEM_data(it), it->nbytes);
601-
} else {
602-
resp_add_chunked_iov(resp, it, it->nbytes);
603-
}
604-
#endif
605-
}
606-
607-
if (settings.verbose > 1) {
608-
int ii;
609-
fprintf(stderr, ">%d sending key ", c->sfd);
610-
for (ii = 0; ii < it->nkey; ++ii) {
611-
fprintf(stderr, "%c", key[ii]);
612-
}
613-
fprintf(stderr, "\n");
614-
}
535+
if (pr->request[pr->reqlen-2] == '\r') {
536+
kend = pr->request + pr->reqlen - 2;
537+
} else {
538+
kend = pr->request + pr->reqlen - 1;
539+
}
615540

616-
/* item_get() has incremented it->refcount for us */
617-
pthread_mutex_lock(&c->thread->stats.mutex);
618-
if (should_touch) {
619-
c->thread->stats.touch_cmds++;
620-
c->thread->stats.slab_stats[ITEM_clsid(it)].touch_hits++;
621-
} else {
622-
c->thread->stats.lru_hits[it->slabs_clsid]++;
623-
c->thread->stats.get_cmds++;
624-
}
625-
pthread_mutex_unlock(&c->thread->stats.mutex);
626-
#ifdef EXTSTORE
627-
/* If ITEM_HDR, an io_wrap owns the reference. */
628-
if ((it->it_flags & ITEM_HDR) == 0) {
629-
resp->item = it;
630-
}
631-
#else
632-
resp->item = it;
633-
#endif
541+
while (klen != 0) {
542+
mc_resp *resp = c->resp;
543+
if (process_get_cmd(t, curkey, klen, c->resp, storage_get_item, exptime, return_cas, should_touch) != 0) {
544+
process_get_command_err(c, NULL);
545+
return;
546+
}
547+
if (resp->io_pending) {
548+
resp->io_pending->c = c;
549+
conn_resp_suspend(c, resp);
550+
}
551+
curkey += klen;
552+
klen = 0;
553+
while (curkey != kend) {
554+
if (*curkey == ' ') {
555+
curkey++;
634556
} else {
635-
pthread_mutex_lock(&c->thread->stats.mutex);
636-
if (should_touch) {
637-
c->thread->stats.touch_cmds++;
638-
c->thread->stats.touch_misses++;
557+
const char *s = memchr(curkey, ' ', kend - curkey);
558+
if (s != NULL) {
559+
klen = s - curkey;
639560
} else {
640-
c->thread->stats.get_misses++;
641-
c->thread->stats.get_cmds++;
642-
}
643-
MEMCACHED_COMMAND_GET(c->sfd, key, nkey, -1, 0);
644-
pthread_mutex_unlock(&c->thread->stats.mutex);
645-
}
646-
647-
key_token++;
648-
if (key_token->length != 0) {
649-
if (!resp_start(c)) {
650-
goto stop;
561+
klen = kend - curkey;
651562
}
652-
resp = c->resp;
653-
}
654-
}
655-
656-
/*
657-
* If the command string hasn't been fully processed, get the next set
658-
* of tokens.
659-
*/
660-
if (key_token->value != NULL) {
661-
ntokens = tokenize_command(key_token->value, tokens, MAX_TOKENS);
662-
key_token = tokens;
663-
if (!resp_start(c)) {
664-
goto stop;
563+
break;
665564
}
666-
resp = c->resp;
667565
}
668-
} while(key_token->value != NULL);
669-
stop:
670-
671-
if (settings.verbose > 1)
672-
fprintf(stderr, ">%d END\n", c->sfd);
673566

674-
/*
675-
If the loop was terminated because of out-of-memory, it is not
676-
reliable to add END\r\n to the buffer, because it might not end
677-
in \r\n. So we send SERVER_ERROR instead.
678-
*/
679-
if (key_token->value != NULL) {
680-
// Kill any stacked responses we had.
681-
conn_release_items(c);
682-
// Start a new response object for the error message.
683-
if (!resp_start(c)) {
684-
// severe out of memory error.
685-
conn_set_state(c, conn_closing);
567+
if (klen && !resp_start(c)) {
568+
// This may succeed because it first frees existing resp objects.
569+
process_get_command_err(c, "SERVER_ERROR out of memory writing get response");
686570
return;
687571
}
688-
if (fail_length) {
689-
out_string(c, "CLIENT_ERROR bad command line format");
690-
} else {
691-
out_of_memory(c, "SERVER_ERROR out of memory writing get response");
692-
}
693-
} else {
694-
// Tag the end token onto the most recent response object.
695-
resp_add_iov(resp, "END\r\n", 5);
696-
conn_set_state(c, conn_new_cmd);
697572
}
573+
resp_add_iov(c->resp, "END\r\n", 5);
574+
conn_set_state(c, conn_new_cmd);
575+
return;
698576
}
699577

700578
inline static void process_stats_detail(conn *c, const char *command) {
@@ -1664,24 +1542,6 @@ static void _process_command_ascii(conn *c, char *command) {
16641542
out_string(c, "ERROR");
16651543
break;
16661544
}
1667-
} else if (first == 'g') {
1668-
// Various get commands are very common.
1669-
WANT_TOKENS_MIN(ntokens, 3);
1670-
if (strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) {
1671-
1672-
process_get_command(c, tokens, ntokens, false, false);
1673-
} else if (strcmp(tokens[COMMAND_TOKEN].value, "gets") == 0) {
1674-
1675-
process_get_command(c, tokens, ntokens, true, false);
1676-
} else if (strcmp(tokens[COMMAND_TOKEN].value, "gat") == 0) {
1677-
1678-
process_get_command(c, tokens, ntokens, false, true);
1679-
} else if (strcmp(tokens[COMMAND_TOKEN].value, "gats") == 0) {
1680-
1681-
process_get_command(c, tokens, ntokens, true, true);
1682-
} else {
1683-
out_string(c, "ERROR");
1684-
}
16851545
} else if (first == 's') {
16861546
if (strcmp(tokens[COMMAND_TOKEN].value, "stats") == 0) {
16871547

@@ -1813,6 +1673,22 @@ void process_command_ascii(conn *c, char *command, char *el) {
18131673
process_mset_command(c, &pr, resp);
18141674
handled = true;
18151675
break;
1676+
case CMD_GET:
1677+
process_get_command(c, t, &pr, storage_get_item, _NO_CAS, _NO_TOUCH);
1678+
handled = true;
1679+
break;
1680+
case CMD_GETS:
1681+
process_get_command(c, t, &pr, storage_get_item, _DO_CAS, _NO_TOUCH);
1682+
handled = true;
1683+
break;
1684+
case CMD_GAT:
1685+
process_get_command(c, t, &pr, storage_get_item, _NO_CAS, _DO_TOUCH);
1686+
handled = true;
1687+
break;
1688+
case CMD_GATS:
1689+
process_get_command(c, t, &pr, storage_get_item, _DO_CAS, _DO_TOUCH);
1690+
handled = true;
1691+
break;
18161692
case CMD_DELETE:
18171693
process_delete_cmd(t, &pr, resp);
18181694
conn_set_state(c, conn_new_cmd);

0 commit comments

Comments
 (0)
0