Use a fixed size stack instead of a dynamic list for read tasks
This commit is contained in:
parent
8a80b89232
commit
3f0394b8a9
105
hiredis.c
105
hiredis.c
@ -47,9 +47,8 @@ typedef struct redisReader {
|
|||||||
sds buf; /* read buffer */
|
sds buf; /* read buffer */
|
||||||
unsigned int pos; /* buffer cursor */
|
unsigned int pos; /* buffer cursor */
|
||||||
|
|
||||||
redisReadTask *rlist; /* list of items to process */
|
redisReadTask rstack[3]; /* stack of read tasks */
|
||||||
unsigned int rlen; /* list length */
|
int ridx; /* index of stack */
|
||||||
unsigned int rpos; /* list cursor */
|
|
||||||
} redisReader;
|
} redisReader;
|
||||||
|
|
||||||
static redisReply *createReplyObject(int type);
|
static redisReply *createReplyObject(int type);
|
||||||
@ -183,8 +182,33 @@ static char *readLine(redisReader *r, int *_len) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void moveToNextTask(redisReader *r) {
|
||||||
|
redisReadTask *cur, *prv;
|
||||||
|
assert(r->ridx >= 0);
|
||||||
|
|
||||||
|
/* Return a.s.a.p. when the stack is now empty. */
|
||||||
|
if (r->ridx == 0) {
|
||||||
|
r->ridx--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = &(r->rstack[r->ridx]);
|
||||||
|
prv = &(r->rstack[r->ridx-1]);
|
||||||
|
assert(prv->type == REDIS_REPLY_ARRAY);
|
||||||
|
if (cur->idx == prv->elements-1) {
|
||||||
|
r->ridx--;
|
||||||
|
moveToNextTask(r);
|
||||||
|
} else {
|
||||||
|
/* Reset the type because the next item can be anything */
|
||||||
|
assert(cur->idx < prv->elements);
|
||||||
|
cur->type = -1;
|
||||||
|
cur->elements = -1;
|
||||||
|
cur->idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int processLineItem(redisReader *r) {
|
static int processLineItem(redisReader *r) {
|
||||||
redisReadTask *cur = &(r->rlist[r->rpos]);
|
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||||
void *obj;
|
void *obj;
|
||||||
char *p;
|
char *p;
|
||||||
int len;
|
int len;
|
||||||
@ -199,14 +223,14 @@ static int processLineItem(redisReader *r) {
|
|||||||
/* If there is no root yet, register this object as root. */
|
/* If there is no root yet, register this object as root. */
|
||||||
if (r->reply == NULL)
|
if (r->reply == NULL)
|
||||||
r->reply = obj;
|
r->reply = obj;
|
||||||
r->rpos++;
|
moveToNextTask(r);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processBulkItem(redisReader *r) {
|
static int processBulkItem(redisReader *r) {
|
||||||
redisReadTask *cur = &(r->rlist[r->rpos]);
|
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||||
void *obj = NULL;
|
void *obj = NULL;
|
||||||
char *p, *s;
|
char *p, *s;
|
||||||
long len;
|
long len;
|
||||||
@ -235,7 +259,7 @@ static int processBulkItem(redisReader *r) {
|
|||||||
r->pos += bytelen;
|
r->pos += bytelen;
|
||||||
if (r->reply == NULL)
|
if (r->reply == NULL)
|
||||||
r->reply = obj;
|
r->reply = obj;
|
||||||
r->rpos++;
|
moveToNextTask(r);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,53 +267,42 @@ static int processBulkItem(redisReader *r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int processMultiBulkItem(redisReader *r) {
|
static int processMultiBulkItem(redisReader *r) {
|
||||||
redisReadTask *cur = &(r->rlist[r->rpos]);
|
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||||
void *obj;
|
void *obj;
|
||||||
char *p;
|
char *p;
|
||||||
long elements, j;
|
long elements;
|
||||||
|
|
||||||
if ((p = readLine(r,NULL)) != NULL) {
|
if ((p = readLine(r,NULL)) != NULL) {
|
||||||
elements = strtol(p,NULL,10);
|
elements = strtol(p,NULL,10);
|
||||||
if (elements == -1) {
|
if (elements == -1) {
|
||||||
obj = r->fn->createNil(cur);
|
obj = r->fn->createNil(cur);
|
||||||
|
moveToNextTask(r);
|
||||||
} else {
|
} else {
|
||||||
obj = r->fn->createArray(cur,elements);
|
obj = r->fn->createArray(cur,elements);
|
||||||
|
|
||||||
/* Modify read list when there are more than 0 elements. */
|
/* Modify task stack when there are more than 0 elements. */
|
||||||
if (elements > 0) {
|
if (elements > 0) {
|
||||||
/* Append elements to the read list. */
|
cur->elements = elements;
|
||||||
r->rlen += elements;
|
r->ridx++;
|
||||||
if ((r->rlist = realloc(r->rlist,sizeof(redisReadTask)*r->rlen)) == NULL)
|
r->rstack[r->ridx].type = -1;
|
||||||
redisOOM();
|
r->rstack[r->ridx].elements = -1;
|
||||||
|
r->rstack[r->ridx].parent = obj;
|
||||||
/* Move existing items backwards. */
|
r->rstack[r->ridx].idx = 0;
|
||||||
memmove(&(r->rlist[r->rpos+1+elements]),
|
} else {
|
||||||
&(r->rlist[r->rpos+1]),
|
moveToNextTask(r);
|
||||||
(r->rlen-(r->rpos+1+elements))*sizeof(redisReadTask));
|
|
||||||
|
|
||||||
/* Populate new read items. */
|
|
||||||
redisReadTask *t;
|
|
||||||
for (j = 0; j < elements; j++) {
|
|
||||||
t = &(r->rlist[r->rpos+1+j]);
|
|
||||||
t->type = -1;
|
|
||||||
t->parent = obj;
|
|
||||||
t->idx = j;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj != NULL) {
|
/* Object was created, so we can always continue. */
|
||||||
if (r->reply == NULL)
|
if (r->reply == NULL)
|
||||||
r->reply = obj;
|
r->reply = obj;
|
||||||
r->rpos++;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processItem(redisReader *r) {
|
static int processItem(redisReader *r) {
|
||||||
redisReadTask *cur = &(r->rlist[r->rpos]);
|
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||||
char *p;
|
char *p;
|
||||||
sds byte;
|
sds byte;
|
||||||
|
|
||||||
@ -347,7 +360,7 @@ void *redisReplyReaderCreate(redisReplyObjectFunctions *fn) {
|
|||||||
r->error = NULL;
|
r->error = NULL;
|
||||||
r->fn = fn == NULL ? &defaultFunctions : fn;
|
r->fn = fn == NULL ? &defaultFunctions : fn;
|
||||||
r->buf = sdsempty();
|
r->buf = sdsempty();
|
||||||
r->rlist = malloc(sizeof(redisReadTask)*1);
|
r->ridx = -1;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,8 +381,6 @@ void redisReplyReaderFree(void *reader) {
|
|||||||
r->fn->freeObject(r->reply);
|
r->fn->freeObject(r->reply);
|
||||||
if (r->buf != NULL)
|
if (r->buf != NULL)
|
||||||
sdsfree(r->buf);
|
sdsfree(r->buf);
|
||||||
if (r->rlist != NULL)
|
|
||||||
free(r->rlist);
|
|
||||||
free(r);
|
free(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,7 +394,7 @@ static void redisSetReplyReaderError(redisReader *r, sds err) {
|
|||||||
r->buf = sdsempty();
|
r->buf = sdsempty();
|
||||||
r->pos = 0;
|
r->pos = 0;
|
||||||
}
|
}
|
||||||
r->rlen = r->rpos = 0;
|
r->ridx = -1;
|
||||||
r->error = err;
|
r->error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,18 +419,17 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
|
|||||||
if (sdslen(r->buf) == 0)
|
if (sdslen(r->buf) == 0)
|
||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
|
|
||||||
/* Create first item to process when the item list is empty. */
|
/* Set first item to process when the stack is empty. */
|
||||||
if (r->rlen == 0) {
|
if (r->ridx == -1) {
|
||||||
r->rlist = realloc(r->rlist,sizeof(redisReadTask)*1);
|
r->rstack[0].type = -1;
|
||||||
r->rlist[0].type = -1;
|
r->rstack[0].elements = -1;
|
||||||
r->rlist[0].parent = NULL;
|
r->rstack[0].parent = NULL;
|
||||||
r->rlist[0].idx = -1;
|
r->rstack[0].idx = -1;
|
||||||
r->rlen = 1;
|
r->ridx = 0;
|
||||||
r->rpos = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process items in reply. */
|
/* Process items in reply. */
|
||||||
while (r->rpos < r->rlen)
|
while (r->ridx >= 0)
|
||||||
if (processItem(r) < 0)
|
if (processItem(r) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -436,7 +446,7 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Emit a reply when there is one. */
|
/* Emit a reply when there is one. */
|
||||||
if (r->rpos == r->rlen) {
|
if (r->ridx == -1) {
|
||||||
void *aux = r->reply;
|
void *aux = r->reply;
|
||||||
r->reply = NULL;
|
r->reply = NULL;
|
||||||
|
|
||||||
@ -447,9 +457,6 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
|
|||||||
r->pos = 0;
|
r->pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set list of items to read to be empty. */
|
|
||||||
r->rlen = r->rpos = 0;
|
|
||||||
|
|
||||||
/* Check if there actually *is* a reply. */
|
/* Check if there actually *is* a reply. */
|
||||||
if (r->error != NULL) {
|
if (r->error != NULL) {
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
|
@ -61,6 +61,7 @@ typedef struct redisReply {
|
|||||||
|
|
||||||
typedef struct redisReadTask {
|
typedef struct redisReadTask {
|
||||||
int type;
|
int type;
|
||||||
|
int elements; /* number of elements in multibulk container */
|
||||||
void *parent; /* optional pointer to parent object */
|
void *parent; /* optional pointer to parent object */
|
||||||
int idx; /* index in parent (array) object */
|
int idx; /* index in parent (array) object */
|
||||||
} redisReadTask;
|
} redisReadTask;
|
||||||
|
Loading…
Reference in New Issue
Block a user