diff -b -u memcachedb-0.1.0.orig/memcachedb.c memcachedb-0.1.0/memcachedb.c --- memcachedb-0.1.0.orig/memcachedb.c 2007-12-18 00:20:11.000000000 +0000 +++ memcachedb-0.1.0/memcachedb.c 2007-12-17 23:56:55.000000000 +0000 @@ -138,20 +138,22 @@ perror("malloc()"); return 0; } - c->rbuf = c->wbuf = 0; + c->rbuf = c->wbuf = c->pbuf = 0; c->rbuf = (char *) malloc(DATA_BUFFER_SIZE); c->wbuf = (char *) malloc(DATA_BUFFER_SIZE); + c->pbuf = (char *) malloc(DATA_BUFFER_SIZE); - if (c->rbuf == 0 || c->wbuf == 0) { + if (c->rbuf == 0 || c->wbuf == 0 || c->pbuf == 0) { if (c->rbuf != 0) free(c->rbuf); if (c->wbuf != 0) free(c->wbuf); + if (c->pbuf != 0) free(c->pbuf); free(c); perror("malloc()"); return 0; } - c->rsize = c->wsize = DATA_BUFFER_SIZE; + c->rsize = c->wsize = c->psize = DATA_BUFFER_SIZE; stats.conn_structs++; } @@ -273,7 +275,7 @@ stats.set_cmds++; while (1) { - if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) { + if (strncmp(c->pbuf + it->nbytes - 2, "\r\n", 2) != 0) { out_string(c, "CLIENT_ERROR bad data chunk"); break; } @@ -299,8 +301,8 @@ cleanup_dbt(); dbkey.data = ITEM_key(it); dbkey.size = strlen(ITEM_key(it)); - dbdata.data = ITEM_data(it); - dbdata.size = it->nbytes; + dbdata.data = c->pbuf; /* ITEM_data(it) is too small */ + dbdata.size = it->nbytes; /* SMELL, do we really want to store the \r\n as well? */ if ((ret = dbp->put(dbp, NULL, &dbkey, &dbdata, 0)) == 0) { /* some future code? */ @@ -410,21 +412,24 @@ &len); if (res != 4 || strlen(key) == 0) { - out_string(c, "CLIENT_ERROR bad command line format"); + out_string(c, "CLIENT_ERROR bad command line format (or key too long)"); return; } it->nkey = strlen(key) + 1; it->nbytes = len + 2; - if (END_LEN < it->nbytes + it->nkey) { + + if (c->psize < it->nbytes) { + /* TODO perhaps malloc a bigger buffer for c->pbuf ? */ out_string(c, "CLIENT_ERROR data too long"); return; } c->item_comm = comm; - c->rcurr = ITEM_data(it); - c->rlbytes = it->nbytes; - c->state = conn_nread; + /* don't need to memset(c->pbuf, 0 ,c->psize); clear buffer. Is this necessary? */ + c->rcurr = c->pbuf; /* tell the state machine to read the payload into pbuf */ + c->rlbytes = it->nbytes; /* how many bytes to read */ + c->state = conn_nread; /* change state machine state to read bytes from connection */ return; } @@ -484,6 +489,7 @@ } if (END_LEN <= putit->nkey + 12) { + /* SMELL could use c->pbuf instead (for *really* long numbers :-) */ out_string(c, "CLIENT_ERROR data too long"); return; } @@ -517,8 +523,8 @@ dbkey.data = key; dbkey.size = strlen(key); it->nkey = dbkey.size + 1; - dbdata.data = ITEM_data(it); - dbdata.ulen = END_LEN - it->nkey; + dbdata.data = c->pbuf; /* ITEM_data(it) is too small */ + dbdata.ulen = c->psize; if ((ret = dbp->get(dbp, NULL, &dbkey, &dbdata, 0)) == 0) { it->nbytes = dbdata.size; @@ -936,10 +942,10 @@ case conn_mwrite: /* * we're writing ibytes bytes from iptr. iptr alternates between - * ibuf, where we build a string "VALUE...", and ITEM_data(it) for the + * ibuf, where we build a string "VALUE...", and c->pbuf for the * current item. When we finish a chunk, we choose the next one using * ipart, which has the following semantics: 0 - start the loop, 1 - - * we finished ibuf, go to current ITEM_data(it); 2 - we finished ITEM_data(it), + * we finished ibuf, go to current c->pbuf; 2 - we finished c->pbuf, * move to the next item and build its ibuf; 3 - we finished all items, * write "END". */ @@ -974,7 +980,7 @@ switch (c->ipart) { case 1: it = &(c->item); - c->iptr = ITEM_data(it); + c->iptr = c->pbuf; c->ibytes = it->nbytes; c->ipart = 2; break; diff -b -u memcachedb-0.1.0.orig/memcachedb.h memcachedb-0.1.0/memcachedb.h --- memcachedb-0.1.0.orig/memcachedb.h 2007-12-18 00:20:11.000000000 +0000 +++ memcachedb-0.1.0/memcachedb.h 2007-12-17 23:56:57.000000000 +0000 @@ -60,18 +60,19 @@ extern struct stats stats; extern struct settings settings; -#define END_LEN 32 -#define END_LEN_STR "31" +#define END_LEN 64 +#define END_LEN_STR "63" typedef struct _stritem { - int nbytes; /* size of data */ - int nkey; - char end[END_LEN]; + int nbytes; /* size of payload data */ + int nkey; /* size of key */ + char end[END_LEN]; /* buffer for key */ } item; #define ITEM_key(item) ((char*)&((item)->end[0])) /* warning: don't use these macros with a function, as it evals its arg twice */ +/* only used for short payloads, like incr & decr, that can fit into the key buffer */ #define ITEM_data(item) ((char*) &((item)->end[0]) + (item)->nkey) #define ITEM_ntotal(item) sizeof(struct _stritem) @@ -96,11 +97,11 @@ short ev_flags; short which; /* which events were just triggered */ - char *rbuf; + char *rbuf; /* DATA_BUFFER_SIZE */ int rsize; int rbytes; - char *wbuf; + char *wbuf; /* DATA_BUFFER_SIZE */ char *wcurr; int wsize; int wbytes; @@ -119,8 +120,10 @@ * data. The data is read into ITEM_data(item) to avoid extra copying. */ - item item; + item item; /* current command: holds key, key len, payload len */ int item_comm; /* which one is it: set/add/replace */ + char *pbuf; /* payload buffer, DATA_BUFFER_SIZE */ + int psize; /* data for the swallow state */ int sbytes; /* how many bytes to swallow */