[PATCH 2/3] Use callback functions to process commands.
Paul Lindner
lindner at inuus.com
Sat Nov 10 14:27:51 UTC 2007
I agree on the main points below. Performance patches without actual
benchmarks are not going to get applied.
It's not that hard. There's a benchmark script included in the perl
client libraries. Plus there's memslap at
http://tangent.org/552/libmemcached.html
I'll spend some time reviewing the bug fix patches posted, but I would
appreciate it if someone took the time to do benchmarks.
On Fri, Nov 09, 2007 at 09:37:47AM -0800, Marc wrote:
> Sorry I didn¹t reply to this sooner. It wound up in my junk folder.
>
> What is the ultimate goal of all these changes? The switch wasn¹t that
> huge, nor do I think a bunch of callbacks is particularly cleaner or more
> readable - especially when you start throwing macros into the mix. I don¹t
> mind taking cleanup changes that are included with feature and, more
> importantly, performance and scalability enhancements. But these seem
> gratuitous. Are you actually testing them in a production environment?
> Given the size of our operation, pushing out even a one-line critical fixes
> is a major undertaking. I¹m sure the same is true for many other people on
> this list. To push new code out means we need to go through detailed code
> review, regression test and then be on call 24x7 for several days to react
> to any problems that come up as software is pushed into production. Why
> would I do that for this update or any of the patches you have submitted to
> this list?
>
> On 11/7/07 11:51 AM, "Tomash Brechko" <tomash.brechko at gmail.com> wrote:
>
> > Replace huge switch() in process_command() with callback functions
> > for each command. From now on, to add new command its processing
> > function should be defined, this function should be declared in
> > command.h, and command should be registered in command.gperf.
> >
> > diff --git a/trunk/server/command.gperf b/trunk/server/command.gperf
> > index 028e4b1..037dc5b 100644
> > +++ b/trunk/server/command.gperf
> > @@ -1,5 +1,6 @@
> > %language=ANSI-C
> > %define lookup-function-name get_command
> > +%define hash-function-name command_hash
> > %compare-lengths
> > %compare-strncmp
> > %readonly-tables
> > @@ -14,26 +15,26 @@
> > struct command;
> > %%
> > #
> > -# keyword command code ntokens (negative means no less then -ntokens)
> > +# keyword command code callback
> > #
> > -add, CMD_ADD, 6
> > -append, CMD_APPEND, 6
> > -bg, CMD_BG, 3
> > -bget, CMD_BGET, -3
> > -cas, CMD_CAS, 6
> > -decr, CMD_DECR, 4
> > -delete, CMD_DELETE, -3
> > -disown, CMD_DISOWN, 3
> > -flush_all, CMD_FLUSH_ALL, -2
> > -get, CMD_GET, -3
> > -gets, CMD_GETS, -3
> > -incr, CMD_INCR, 4
> > -own, CMD_OWN, 3
> > -prepend, CMD_PREPEND, 6
> > -quit, CMD_QUIT, 2
> > -replace, CMD_REPLACE, 6
> > -set, CMD_SET, 6
> > -slabs, CMD_SLABS, 5
> > -stats, CMD_STATS, -2
> > -verbosity, CMD_VERBOSITY, 3
> > -version, CMD_VERSION, 2
> > +add, CMD_ADD, process_update_command
> > +append, CMD_APPEND, process_update_command
> > +bg, CMD_BG, process_manage_command
> > +bget, CMD_BGET, process_get_command
> > +cas, CMD_CAS, process_update_command
> > +decr, CMD_DECR, process_arithmetic_command
> > +delete, CMD_DELETE, process_delete_command
> > +disown, CMD_DISOWN, process_manage_command
> > +flush_all, CMD_FLUSH_ALL, process_flush_all_command
> > +get, CMD_GET, process_get_command
> > +gets, CMD_GETS, process_get_command
> > +incr, CMD_INCR, process_arithmetic_command
> > +own, CMD_OWN, process_manage_command
> > +prepend, CMD_PREPEND, process_update_command
> > +quit, CMD_QUIT, process_quit_command
> > +replace, CMD_REPLACE, process_update_command
> > +set, CMD_SET, process_update_command
> > +slabs, CMD_SLABS, process_slabs_command
> > +stats, CMD_STATS, process_stat
> > +verbosity, CMD_VERBOSITY, process_verbosity_command
> > +version, CMD_VERSION, process_version_command
> > diff --git a/trunk/server/command.h b/trunk/server/command.h
> > index 4d46a3a..52f8611 100644
> > +++ b/trunk/server/command.h
> > @@ -1,6 +1,8 @@
> > #ifndef COMMAND_H
> > #define COMMAND_H 1
> >
> > +#include "memcached.h"
> > +
> >
> > enum command_code
> > {
> > @@ -31,7 +33,8 @@ struct command
> > {
> > const char *name;
> > enum command_code code;
> > - int ntokens;
> > + void (*callback)(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens);
> > };
> >
> >
> > @@ -68,4 +71,21 @@ const struct param *
> > get_param(const char *str, unsigned int len);
> >
> >
> > +#define DECLARE_CALLBACK(callback) \
> > + extern void callback(enum command_code code, conn *c, \
> > + token_t *tokens, size_t ntokens)
> > +
> > +DECLARE_CALLBACK(process_get_command);
> > +DECLARE_CALLBACK(process_update_command);
> > +DECLARE_CALLBACK(process_arithmetic_command);
> > +DECLARE_CALLBACK(process_verbosity_command);
> > +DECLARE_CALLBACK(process_stat);
> > +DECLARE_CALLBACK(process_delete_command);
> > +DECLARE_CALLBACK(process_manage_command);
> > +DECLARE_CALLBACK(process_version_command);
> > +DECLARE_CALLBACK(process_quit_command);
> > +DECLARE_CALLBACK(process_flush_all_command);
> > +DECLARE_CALLBACK(process_slabs_command);
> > +
> > +
> > #endif /* ! COMMAND_H */
> > diff --git a/trunk/server/memcached.c b/trunk/server/memcached.c
> > index 4d464f1..1aa8af8 100644
> > +++ b/trunk/server/memcached.c
> > @@ -793,11 +793,6 @@ int do_store_item(item *it, int comm) {
> > return stored;
> > }
> >
> > -typedef struct token_s {
> > - char *value;
> > - size_t length;
> > -} token_t;
> > -
> > #define COMMAND_TOKEN 0
> > #define SUBCOMMAND_TOKEN 1
> > #define KEY_TOKEN 1
> > @@ -906,13 +901,15 @@ inline static void process_stats_detail(conn *c, token_t
> > *tokens) {
> > }
> > }
> >
> > -static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
> > +void process_stat(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > rel_time_t now = current_time;
> > struct param *param;
> >
> > assert(c != NULL);
> >
> > - if(ntokens < 2) {
> > + /* FIXME: why not "ERROR" as other commands do? */
> > + if (ntokens < 2) {
> > out_string(c, "CLIENT_ERROR bad command line");
> > return;
> > }
> > @@ -1075,6 +1072,7 @@ static void process_stat(conn *c, token_t *tokens, const
> > size_t ntokens) {
> > return;
> >
> > case PARAM_DETAIL:
> > + /* FIXME: why not "ERROR" as other commands do? */
> > if (ntokens < 4)
> > out_string(c, "CLIENT_ERROR usage: stats detail on|off|dump");
> > else
> > @@ -1097,7 +1095,8 @@ static void process_stat(conn *c, token_t *tokens, const
> > size_t ntokens) {
> > }
> >
> > /* ntokens is overwritten here... shrug.. */
> > -static inline void process_get_command(conn *c, token_t *tokens, size_t
> > ntokens, bool return_key_ptr) {
> > +void process_get_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > char *key;
> > size_t nkey;
> > int i = 0;
> > @@ -1107,6 +1106,11 @@ static inline void process_get_command(conn *c, token_t
> > *tokens, size_t ntokens,
> > uint32_t in_memory_ptr;
> > assert(c != NULL);
> >
> > + if (ntokens < 3) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > if (settings.managed) {
> > int bucket = c->bucket;
> > if (bucket == -1) {
> > @@ -1155,7 +1159,7 @@ static inline void process_get_command(conn *c, token_t
> > *tokens, size_t ntokens,
> > * " " + flags + " " + data length + "\r\n" + data (with
> > \r\n)
> > */
> >
> > - if(return_key_ptr == true)
> > + if (code == CMD_GETS)
> > {
> > in_memory_ptr = (uint32_t)item_get(key, nkey);
> > sprintf(suffix," %d %d %lu\r\n", atoi(ITEM_suffix(it) + 1),
> > it->nbytes - 2, in_memory_ptr);
> > @@ -1226,7 +1230,8 @@ static inline void process_get_command(conn *c, token_t
> > *tokens, size_t ntokens,
> > return;
> > }
> >
> > -static void process_update_command(conn *c, token_t *tokens, const size_t
> > ntokens, int comm, bool handle_cas) {
> > +void process_update_command(enum command_code code,
> > + conn *c, token_t *tokens, const size_t ntokens) {
> > char *key;
> > size_t nkey;
> > int flags;
> > @@ -1237,6 +1242,11 @@ static void process_update_command(conn *c, token_t
> > *tokens, const size_t ntoken
> >
> > assert(c != NULL);
> >
> > + if (ntokens != 6) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
> > out_string(c, "CLIENT_ERROR bad command line format");
> > return;
> > @@ -1280,7 +1290,7 @@ static void process_update_command(conn *c, token_t
> > *tokens, const size_t ntoken
> > it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2);
> >
> > /* HANDLE_CAS VALIDATION */
> > - if (handle_cas == true)
> > + if (code == CMD_CAS)
> > {
> > item *itmp=item_get(key, it->nkey);
> > /* Release the reference */
> > @@ -1325,11 +1335,29 @@ static void process_update_command(conn *c, token_t
> > *tokens, const size_t ntoken
> > c->item = it;
> > c->ritem = ITEM_data(it);
> > c->rlbytes = it->nbytes;
> > - c->item_comm = comm;
> > + switch (code) {
> > + case CMD_ADD:
> > + c->item_comm = NREAD_ADD;
> > + break;
> > + case CMD_SET:
> > + c->item_comm = NREAD_SET;
> > + break;
> > + case CMD_REPLACE:
> > + case CMD_CAS:
> > + c->item_comm = NREAD_REPLACE;
> > + break;
> > + case CMD_PREPEND:
> > + c->item_comm = NREAD_PREPEND;
> > + break;
> > + case CMD_APPEND:
> > + c->item_comm = NREAD_APPEND;
> > + break;
> > + }
> > conn_set_state(c, conn_nread);
> > }
> >
> > -static void process_arithmetic_command(conn *c, token_t *tokens, const size_t
> > ntokens, const bool incr) {
> > +void process_arithmetic_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > char temp[sizeof("18446744073709551615")];
> > item *it;
> > int64_t delta;
> > @@ -1338,6 +1366,11 @@ static void process_arithmetic_command(conn *c, token_t
> > *tokens, const size_t nt
> >
> > assert(c != NULL);
> >
> > + if (ntokens != 4) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > if(tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
> > out_string(c, "CLIENT_ERROR bad command line format");
> > return;
> > @@ -1372,7 +1405,7 @@ static void process_arithmetic_command(conn *c, token_t
> > *tokens, const size_t nt
> > return;
> > }
> >
> > - out_string(c, add_delta(it, incr, delta, temp));
> > + out_string(c, add_delta(it, (code == CMD_INCR), delta, temp));
> > item_remove(it); /* release our reference */
> > }
> >
> > @@ -1426,7 +1459,8 @@ char *do_add_delta(item *it, const bool incr, const
> > int64_t delta, char *buf) {
> > return buf;
> > }
> >
> > -static void process_delete_command(conn *c, token_t *tokens, const size_t
> > ntokens) {
> > +void process_delete_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > char *key;
> > size_t nkey;
> > item *it;
> > @@ -1434,6 +1468,11 @@ static void process_delete_command(conn *c, token_t
> > *tokens, const size_t ntoken
> >
> > assert(c != NULL);
> >
> > + if (ntokens < 3 || ntokens > 4) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > if (settings.managed) {
> > int bucket = c->bucket;
> > if (bucket == -1) {
> > @@ -1513,15 +1552,159 @@ char *do_defer_delete(item *it, time_t exptime)
> > return "DELETED";
> > }
> >
> > -static void process_verbosity_command(conn *c, token_t *tokens, const size_t
> > ntokens) {
> > +void process_verbosity_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > unsigned int level;
> >
> > assert(c != NULL);
> >
> > + if (ntokens != 3) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > level = strtoul(tokens[1].value, NULL, 10);
> > settings.verbose = level > MAX_VERBOSITY_LEVEL ? MAX_VERBOSITY_LEVEL :
> > level;
> > out_string(c, "OK");
> > - return;
> > +}
> > +
> > +void process_manage_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > + unsigned int bucket, gen;
> > + bool res;
> > +
> > + if (ntokens != 3) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > + if (!settings.managed) {
> > + out_string(c, "CLIENT_ERROR not a managed instance");
> > + return;
> > + }
> > +
> > + switch (code) {
> > + case CMD_OWN:
> > + case CMD_BG:
> > + res = (sscanf(tokens[1].value, "%u:%u", &bucket, &gen) == 2);
> > + break;
> > + case CMD_DISOWN:
> > + res = (sscanf(tokens[1].value, "%u", &bucket) == 1);
> > + break;
> > + }
> > +
> > + if (res) {
> > + if ((bucket < 0) || (bucket >= MAX_BUCKETS)) {
> > + if (code != CMD_BG) {
> > + out_string(c, "CLIENT_ERROR bucket number out of range");
> > + return;
> > + }
> > + }
> > + switch (code) {
> > + case CMD_OWN:
> > + buckets[bucket] = gen;
> > + out_string(c, "OWNED");
> > + break;
> > + case CMD_DISOWN:
> > + buckets[bucket] = 0;
> > + out_string(c, "DISOWNED");
> > + break;
> > + case CMD_BG:
> > + if (gen > 0) {
> > + c->bucket = bucket;
> > + c->gen = gen;
> > + }
> > + conn_set_state(c, conn_read);
> > + break;
> > + }
> > + } else {
> > + out_string(c, "CLIENT_ERROR bad format");
> > + }
> > +}
> > +
> > +void process_flush_all_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > + if (ntokens < 2 || ntokens > 3) {
> > + out_string(c, "ERROR");
> > + }
> > +
> > + time_t exptime = 0;
> > + set_current_time();
> > +
> > + if (ntokens == 2) {
> > + settings.oldest_live = current_time - 1;
> > + item_flush_expired();
> > + out_string(c, "OK");
> > + return;
> > + }
> > +
> > + exptime = strtol(tokens[1].value, NULL, 10);
> > + if (errno == ERANGE) {
> > + out_string(c, "CLIENT_ERROR bad command line format");
> > + return;
> > + }
> > +
> > + settings.oldest_live = realtime(exptime) - 1;
> > + item_flush_expired();
> > + out_string(c, "OK");
> > +}
> > +
> > +void process_slabs_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > + if (ntokens != 5
> > + || strcmp(tokens[SUBCOMMAND_TOKEN].value, "reassign") != 0) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > +#ifdef ALLOW_SLABS_REASSIGN
> > +
> > + int src, dst, rv;
> > +
> > + src = strtol(tokens[2].value, NULL, 10);
> > + dst = strtol(tokens[3].value, NULL, 10);
> > +
> > + if (errno == ERANGE) {
> > + out_string(c, "CLIENT_ERROR bad command line format");
> > + return;
> > + }
> > +
> > + rv = slabs_reassign(src, dst);
> > + if (rv == 1) {
> > + out_string(c, "DONE");
> > + return;
> > + }
> > + if (rv == 0) {
> > + out_string(c, "CANT");
> > + return;
> > + }
> > + if (rv == -1) {
> > + out_string(c, "BUSY");
> > + return;
> > + }
> > +#else
> > + out_string(c, "CLIENT_ERROR Slab reassignment not supported");
> > +#endif
> > +}
> > +
> > +void process_version_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > + if (ntokens != 2) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > + out_string(c, "VERSION " VERSION);
> > +}
> > +
> > +void process_quit_command(enum command_code code,
> > + conn *c, token_t *tokens, size_t ntokens) {
> > + if (ntokens != 2) {
> > + out_string(c, "ERROR");
> > + return;
> > + }
> > +
> > + conn_set_state(c, conn_closing);
> > }
> >
> > static void process_command(conn *c, char *command) {
> > @@ -1552,190 +1735,10 @@ static void process_command(conn *c, char *command) {
> >
> > cmd = get_command(tokens[COMMAND_TOKEN].value,
> > tokens[COMMAND_TOKEN].length);
> > -
> > - if (!cmd || (cmd->ntokens > 0 && cmd->ntokens != ntokens)
> > - || (cmd->ntokens < 0 && -cmd->ntokens > ntokens)) {
> > + if (cmd) {
> > + (*cmd->callback)(cmd->code, c, tokens, ntokens);
> > + } else {
> > out_string(c, "ERROR");
> > - return;
> > - }
> > -
> > - switch (cmd->code) {
> > - case CMD_GET:
> > - case CMD_BGET:
> > - process_get_command(c, tokens, ntokens, false);
> > - break;
> > - case CMD_ADD:
> > - process_update_command(c, tokens, ntokens, NREAD_ADD, false);
> > - break;
> > - case CMD_SET:
> > - process_update_command(c, tokens, ntokens, NREAD_SET, false);
> > - break;
> > - case CMD_REPLACE:
> > - process_update_command(c, tokens, ntokens, NREAD_REPLACE, false);
> > - break;
> > - case CMD_PREPEND:
> > - process_update_command(c, tokens, ntokens, NREAD_PREPEND, false);
> > - break;
> > - case CMD_APPEND:
> > - process_update_command(c, tokens, ntokens, NREAD_APPEND, false);
> > - break;
> > - case CMD_CAS:
> > - process_update_command(c, tokens, ntokens, NREAD_REPLACE, true);
> > - break;
> > - case CMD_INCR:
> > - process_arithmetic_command(c, tokens, ntokens, 1);
> > - break;
> > - case CMD_GETS:
> > - process_get_command(c, tokens, ntokens, true);
> > - break;
> > - case CMD_DECR:
> > - process_arithmetic_command(c, tokens, ntokens, 0);
> > - break;
> > - case CMD_DELETE:
> > - if (ntokens <= 4)
> > - process_delete_command(c, tokens, ntokens);
> > - else
> > - out_string(c, "ERROR");
> > - break;
> > - case CMD_OWN:
> > - {
> > - unsigned int bucket, gen;
> > - if (!settings.managed) {
> > - out_string(c, "CLIENT_ERROR not a managed instance");
> > - return;
> > - }
> > -
> > - if (sscanf(tokens[1].value, "%u:%u", &bucket,&gen) == 2) {
> > - if ((bucket < 0) || (bucket >= MAX_BUCKETS)) {
> > - out_string(c, "CLIENT_ERROR bucket number out of range");
> > - return;
> > - }
> > - buckets[bucket] = gen;
> > - out_string(c, "OWNED");
> > - return;
> > - } else {
> > - out_string(c, "CLIENT_ERROR bad format");
> > - return;
> > - }
> > - }
> > - break;
> > - case CMD_DISOWN:
> > - {
> > - int bucket;
> > - if (!settings.managed) {
> > - out_string(c, "CLIENT_ERROR not a managed instance");
> > - return;
> > - }
> > - if (sscanf(tokens[1].value, "%u", &bucket) == 1) {
> > - if ((bucket < 0) || (bucket >= MAX_BUCKETS)) {
> > - out_string(c, "CLIENT_ERROR bucket number out of range");
> > - return;
> > - }
> > - buckets[bucket] = 0;
> > - out_string(c, "DISOWNED");
> > - return;
> > - } else {
> > - out_string(c, "CLIENT_ERROR bad format");
> > - return;
> > - }
> > - }
> > - break;
> > - case CMD_BG:
> > - {
> > - int bucket, gen;
> > - if (!settings.managed) {
> > - out_string(c, "CLIENT_ERROR not a managed instance");
> > - return;
> > - }
> > - if (sscanf(tokens[1].value, "%u:%u", &bucket, &gen) == 2) {
> > - /* we never write anything back, even if input's wrong */
> > - if ((bucket < 0) || (bucket >= MAX_BUCKETS) || (gen <= 0)) {
> > - /* do nothing, bad input */
> > - } else {
> > - c->bucket = bucket;
> > - c->gen = gen;
> > - }
> > - conn_set_state(c, conn_read);
> > - return;
> > - } else {
> > - out_string(c, "CLIENT_ERROR bad format");
> > - return;
> > - }
> > - }
> > - break;
> > - case CMD_STATS:
> > - process_stat(c, tokens, ntokens);
> > - break;
> > - case CMD_FLUSH_ALL:
> > - if (ntokens <= 3) {
> > - time_t exptime = 0;
> > - set_current_time();
> > -
> > - if(ntokens == 2) {
> > - settings.oldest_live = current_time - 1;
> > - item_flush_expired();
> > - out_string(c, "OK");
> > - return;
> > - }
> > -
> > - exptime = strtol(tokens[1].value, NULL, 10);
> > - if(errno == ERANGE) {
> > - out_string(c, "CLIENT_ERROR bad command line format");
> > - return;
> > - }
> > -
> > - settings.oldest_live = realtime(exptime) - 1;
> > - item_flush_expired();
> > - out_string(c, "OK");
> > - return;
> > - } else {
> > - out_string(c, "ERROR");
> > - }
> > - break;
> > - case CMD_VERSION:
> > - out_string(c, "VERSION " VERSION);
> > - break;
> > - case CMD_QUIT:
> > - conn_set_state(c, conn_closing);
> > - break;
> > - case CMD_SLABS:
> > - if (strcmp(tokens[SUBCOMMAND_TOKEN].value, "reassign") == 0) {
> > -#ifdef ALLOW_SLABS_REASSIGN
> > -
> > - int src, dst, rv;
> > -
> > - src = strtol(tokens[2].value, NULL, 10);
> > - dst = strtol(tokens[3].value, NULL, 10);
> > -
> > - if(errno == ERANGE) {
> > - out_string(c, "CLIENT_ERROR bad command line format");
> > - return;
> > - }
> > -
> > - rv = slabs_reassign(src, dst);
> > - if (rv == 1) {
> > - out_string(c, "DONE");
> > - return;
> > - }
> > - if (rv == 0) {
> > - out_string(c, "CANT");
> > - return;
> > - }
> > - if (rv == -1) {
> > - out_string(c, "BUSY");
> > - return;
> > - }
> > -#else
> > - out_string(c, "CLIENT_ERROR Slab reassignment not supported");
> > -#endif
> > -
> > - } else {
> > - out_string(c, "ERROR");
> > - }
> > - break;
> > - case CMD_VERBOSITY:
> > - process_verbosity_command(c, tokens, ntokens);
> > - break;
> > }
> > }
> >
> > diff --git a/trunk/server/memcached.h b/trunk/server/memcached.h
> > index 1ca73e8..7d0188f 100644
> > +++ b/trunk/server/memcached.h
> > @@ -1,6 +1,10 @@
> > /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> > /* $Id$ */
> >
> > +#ifndef MEMCACHED_H
> > +#define MEMCACHED_H 1
> > +
> > +
> > #ifdef HAVE_CONFIG_H
> > #include "config.h"
> > #endif
> > @@ -207,6 +211,11 @@ typedef struct {
> > int gen; /* generation requested for the bucket */
> > } conn;
> >
> > +typedef struct token_s {
> > + char *value;
> > + size_t length;
> > +} token_t;
> > +
> > /* number of virtual buckets for a managed instance */
> > #define MAX_BUCKETS 32768
> >
> > @@ -345,3 +354,4 @@ int mt_store_item(item *item, int comm);
> > #endif /* !USE_THREADS */
> >
> >
> > +#endif /* ! MEMCACHED_H */
> > diff --git a/trunk/server/param.gperf b/trunk/server/param.gperf
> > index cc1db38..21a1af8 100644
> > +++ b/trunk/server/param.gperf
> > @@ -1,5 +1,6 @@
> > %language=ANSI-C
> > %define lookup-function-name get_param
> > +%define hash-function-name param_hash
> > %compare-lengths
> > %compare-strncmp
> > %readonly-tables
>
>
--
Paul Lindner ||||| | | | | | | | | |
lindner at inuus.com
More information about the memcached
mailing list