Skip to content

Commit c2027ad

Browse files
committed
conditionally don't inline the ASCII VALUE line
missing methods of changing the value. uses what should be a high speed itoa instead of snprintf in a handful of places. Should speed up sets, reduce memory overhead, and ideally not slow down gets too much.
1 parent 1cc77e6 commit c2027ad

File tree

5 files changed

+56
-16
lines changed

5 files changed

+56
-16
lines changed

items.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,12 @@ static unsigned int noexp_lru_size(int slabs_clsid) {
138138
*/
139139
static size_t item_make_header(const uint8_t nkey, const unsigned int flags, const int nbytes,
140140
char *suffix, uint8_t *nsuffix) {
141-
/* suffix is defined at 40 chars elsewhere.. */
142-
*nsuffix = (uint8_t) snprintf(suffix, 40, " %u %d\r\n", flags, nbytes - 2);
141+
if (settings.inline_ascii_response) {
142+
/* suffix is defined at 40 chars elsewhere.. */
143+
*nsuffix = (uint8_t) snprintf(suffix, 40, " %u %d\r\n", flags, nbytes - 2);
144+
} else {
145+
*nsuffix = sizeof(flags);
146+
}
143147
return sizeof(item) + nkey + *nsuffix + nbytes;
144148
}
145149

@@ -242,7 +246,11 @@ item *do_item_alloc(char *key, const size_t nkey, const unsigned int flags,
242246
it->nbytes = nbytes;
243247
memcpy(ITEM_key(it), key, nkey);
244248
it->exptime = exptime;
245-
memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix);
249+
if (settings.inline_ascii_response) {
250+
memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix);
251+
} else {
252+
memcpy(ITEM_suffix(it), &flags, sizeof(flags));
253+
}
246254
it->nsuffix = nsuffix;
247255

248256
/* Need to shuffle the pointer stored in h_next into it->data. */

itoa_ljust.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ static inline char* itoa(uint32_t u, char* p, int d, int n) {
107107
}
108108

109109
char* itoa_u32(uint32_t u, char* p) {
110-
int d,n;
110+
int d = 0,n;
111111
if (u >=100000000) n = digits(u, 100000000, &d, &p, 10);
112112
else if (u < 100) n = digits(u, 1, &d, &p, 2);
113113
else if (u < 10000) n = digits(u, 100, &d, &p, 4);

memcached.c

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ static void settings_init(void) {
236236
settings.hot_lru_pct = 32;
237237
settings.warm_lru_pct = 32;
238238
settings.expirezero_does_not_evict = false;
239+
settings.inline_ascii_response = false;
239240
settings.idle_timeout = 0; /* disabled */
240241
settings.hashpower_init = 0;
241242
settings.slab_reassign = false;
@@ -1507,7 +1508,11 @@ static void process_bin_get_or_touch(conn *c) {
15071508
rsp->message.header.response.cas = htonll(ITEM_get_cas(it));
15081509

15091510
// add the flags
1510-
rsp->message.body.flags = htonl(strtoul(ITEM_suffix(it), NULL, 10));
1511+
if (settings.inline_ascii_response) {
1512+
rsp->message.body.flags = htonl(strtoul(ITEM_suffix(it), NULL, 10));
1513+
} else {
1514+
rsp->message.body.flags = htonl(*((uint32_t *)ITEM_suffix(it)));
1515+
}
15111516
add_iov(c, &rsp->message.body, sizeof(rsp->message.body));
15121517

15131518
if (should_return_key) {
@@ -2656,7 +2661,11 @@ enum store_item_type do_store_item(item *it, int comm, conn *c, const uint32_t h
26562661
/* we have it and old_it here - alloc memory to hold both */
26572662
/* flags was already lost - so recover them from ITEM_suffix(it) */
26582663

2659-
flags = (uint32_t) strtoul(ITEM_suffix(old_it), (char **) NULL, 10);
2664+
if (settings.inline_ascii_response) {
2665+
flags = (uint32_t) strtoul(ITEM_suffix(old_it), (char **) NULL, 10);
2666+
} else {
2667+
flags = *((uint32_t *)ITEM_suffix(old_it));
2668+
}
26602669

26612670
new_it = do_item_alloc(key, it->nkey, flags, old_it->exptime, it->nbytes + old_it->nbytes - 2 /* CRLF */);
26622671

@@ -3179,6 +3188,22 @@ static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
31793188
}
31803189
}
31813190

3191+
static inline int make_ascii_get_suffix(char *suffix, item *it, bool return_cas) {
3192+
char *p;
3193+
*suffix = ' ';
3194+
p = itoa_u32(*((uint32_t *) ITEM_suffix(it)), suffix+1);
3195+
*p = ' ';
3196+
p = itoa_u32(it->nbytes-2, p+1);
3197+
if (return_cas) {
3198+
*p = ' ';
3199+
p = itoa_u64(ITEM_get_cas(it), p+1);
3200+
}
3201+
*p = '\r';
3202+
*(p+1) = '\n';
3203+
*(p+2) = '\0';
3204+
return (p - suffix) + 2;
3205+
}
3206+
31823207
/* ntokens is overwritten here... shrug.. */
31833208
static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_cas) {
31843209
char *key;
@@ -3230,7 +3255,7 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
32303255
* " " + flags + " " + data length + "\r\n" + data (with \r\n)
32313256
*/
32323257

3233-
if (return_cas)
3258+
if (return_cas || !settings.inline_ascii_response)
32343259
{
32353260
MEMCACHED_COMMAND_GET(c->sfd, ITEM_key(it), it->nkey,
32363261
it->nbytes, ITEM_get_cas(it));
@@ -3263,12 +3288,13 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
32633288
return;
32643289
}
32653290
*(c->suffixlist + i) = suffix;
3266-
int suffix_len = snprintf(suffix, SUFFIX_SIZE,
3291+
/*int suffix_len = snprintf(suffix, SUFFIX_SIZE,
32673292
" %llu\r\n",
3268-
(unsigned long long)ITEM_get_cas(it));
3293+
(unsigned long long)ITEM_get_cas(it));*/
3294+
int suffix_len = make_ascii_get_suffix(suffix, it, return_cas);
3295+
//add_iov(c, ITEM_suffix(it), it->nsuffix - 2) != 0 ||
32693296
if (add_iov(c, "VALUE ", 6) != 0 ||
32703297
add_iov(c, ITEM_key(it), it->nkey) != 0 ||
3271-
add_iov(c, ITEM_suffix(it), it->nsuffix - 2) != 0 ||
32723298
add_iov(c, suffix, suffix_len) != 0)
32733299
{
32743300
item_remove(it);
@@ -3348,7 +3374,7 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
33483374

33493375
c->icurr = c->ilist;
33503376
c->ileft = i;
3351-
if (return_cas) {
3377+
if (return_cas || !settings.inline_ascii_response) {
33523378
c->suffixcurr = c->suffixlist;
33533379
c->suffixleft = i;
33543380
}
@@ -3639,7 +3665,12 @@ enum delta_result_type do_add_delta(conn *c, const char *key, const size_t nkey,
36393665
do_item_update(it);
36403666
} else if (it->refcount > 1) {
36413667
item *new_it;
3642-
uint32_t flags = (uint32_t) strtoul(ITEM_suffix(it)+1, (char **) NULL, 10);
3668+
uint32_t flags;
3669+
if (settings.inline_ascii_response) {
3670+
flags = (uint32_t) strtoul(ITEM_suffix(it)+1, (char **) NULL, 10);
3671+
} else {
3672+
flags = *((uint32_t *)ITEM_suffix(it));
3673+
}
36433674
new_it = do_item_alloc(ITEM_key(it), it->nkey, flags, it->exptime, res + 2);
36443675
if (new_it == 0) {
36453676
do_item_remove(it);

memcached.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@
3737
#define UDP_MAX_PAYLOAD_SIZE 1400
3838
#define UDP_HEADER_SIZE 8
3939
#define MAX_SENDBUF_SIZE (256 * 1024 * 1024)
40-
/* I'm told the max length of a 64-bit num converted to string is 20 bytes.
41-
* Plus a few for spaces, \r\n, \0 */
42-
#define SUFFIX_SIZE 24
40+
/* Up to 3 numbers (2 32bit, 1 64bit), spaces, newlines, null 0 */
41+
#define SUFFIX_SIZE 50
4342

4443
/** Initial size of list of items being returned by "get". */
4544
#define ITEM_LIST_INITIAL 200
@@ -369,6 +368,7 @@ struct settings {
369368
int warm_lru_pct; /* percentage of slab space for WARM_LRU */
370369
int crawls_persleep; /* Number of LRU crawls to run before sleeping */
371370
bool expirezero_does_not_evict; /* exptime == 0 goes into NOEXP_LRU */
371+
bool inline_ascii_response; /* pre-format the VALUE line for ASCII responses */
372372
int idle_timeout; /* Number of seconds to let connections idle */
373373
unsigned int logger_watcher_buf_size; /* size of logger's per-watcher buffer */
374374
unsigned int logger_buf_size; /* size of per-thread logger buffer */

t/issue_42.t

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ for ($key = 0; $key < 10; $key++) {
1818

1919
my $first_stats = mem_stats($sock, "slabs");
2020
my $req = $first_stats->{"1:mem_requested"};
21-
ok ($req == "640" || $req == "800", "Check allocated size");
21+
print STDERR "REQ: $req\n";
22+
ok ($req == "640" || $req == "800" || $req == "770", "Check allocated size");

0 commit comments

Comments
 (0)