diff options
| author | Pieter Noordhuis <pcnoordhuis@gmail.com> | 2010-10-31 14:42:48 +0100 | 
|---|---|---|
| committer | Pieter Noordhuis <pcnoordhuis@gmail.com> | 2010-10-31 14:42:48 +0100 | 
| commit | 3f0394b8a91dd77560a2d1ae7bcafced0cbcffcf (patch) | |
| tree | 3aabf79d1b097b16482cacc24243ab24cf0da767 | |
| parent | 8a80b89232dbad6445b1286b580275b8f91b5cbc (diff) | |
| download | hiredict-3f0394b8a91dd77560a2d1ae7bcafced0cbcffcf.tar.xz | |
Use a fixed size stack instead of a dynamic list for read tasks
| -rw-r--r-- | hiredis.c | 111 | ||||
| -rw-r--r-- | hiredis.h | 1 | 
2 files changed, 60 insertions, 52 deletions
| @@ -47,9 +47,8 @@ typedef struct redisReader {      sds buf; /* read buffer */      unsigned int pos; /* buffer cursor */ -    redisReadTask *rlist; /* list of items to process */ -    unsigned int rlen; /* list length */ -    unsigned int rpos; /* list cursor */ +    redisReadTask rstack[3]; /* stack of read tasks */ +    int ridx; /* index of stack */  } redisReader;  static redisReply *createReplyObject(int type); @@ -183,8 +182,33 @@ static char *readLine(redisReader *r, int *_len) {      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) { -    redisReadTask *cur = &(r->rlist[r->rpos]); +    redisReadTask *cur = &(r->rstack[r->ridx]);      void *obj;      char *p;      int len; @@ -199,14 +223,14 @@ static int processLineItem(redisReader *r) {          /* If there is no root yet, register this object as root. */          if (r->reply == NULL)              r->reply = obj; -        r->rpos++; +        moveToNextTask(r);          return 0;      }      return -1;  }  static int processBulkItem(redisReader *r) { -    redisReadTask *cur = &(r->rlist[r->rpos]); +    redisReadTask *cur = &(r->rstack[r->ridx]);      void *obj = NULL;      char *p, *s;      long len; @@ -235,7 +259,7 @@ static int processBulkItem(redisReader *r) {              r->pos += bytelen;              if (r->reply == NULL)                  r->reply = obj; -            r->rpos++; +            moveToNextTask(r);              return 0;          }      } @@ -243,53 +267,42 @@ static int processBulkItem(redisReader *r) {  }  static int processMultiBulkItem(redisReader *r) { -    redisReadTask *cur = &(r->rlist[r->rpos]); +    redisReadTask *cur = &(r->rstack[r->ridx]);      void *obj;      char *p; -    long elements, j; +    long elements;      if ((p = readLine(r,NULL)) != NULL) {          elements = strtol(p,NULL,10);          if (elements == -1) {              obj = r->fn->createNil(cur); +            moveToNextTask(r);          } else {              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) { -                /* Append elements to the read list. */ -                r->rlen += elements; -                if ((r->rlist = realloc(r->rlist,sizeof(redisReadTask)*r->rlen)) == NULL) -                    redisOOM(); - -                /* Move existing items backwards. */ -                memmove(&(r->rlist[r->rpos+1+elements]), -                        &(r->rlist[r->rpos+1]), -                        (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; -                } +                cur->elements = elements; +                r->ridx++; +                r->rstack[r->ridx].type = -1; +                r->rstack[r->ridx].elements = -1; +                r->rstack[r->ridx].parent = obj; +                r->rstack[r->ridx].idx = 0; +            } else { +                moveToNextTask(r);              }          } -        if (obj != NULL) { -            if (r->reply == NULL) -                r->reply = obj; -            r->rpos++; -            return 0; -        } +        /* Object was created, so we can always continue. */ +        if (r->reply == NULL) +            r->reply = obj; +        return 0;      }      return -1;  }  static int processItem(redisReader *r) { -    redisReadTask *cur = &(r->rlist[r->rpos]); +    redisReadTask *cur = &(r->rstack[r->ridx]);      char *p;      sds byte; @@ -347,7 +360,7 @@ void *redisReplyReaderCreate(redisReplyObjectFunctions *fn) {      r->error = NULL;      r->fn = fn == NULL ? &defaultFunctions : fn;      r->buf = sdsempty(); -    r->rlist = malloc(sizeof(redisReadTask)*1); +    r->ridx = -1;      return r;  } @@ -368,8 +381,6 @@ void redisReplyReaderFree(void *reader) {          r->fn->freeObject(r->reply);      if (r->buf != NULL)          sdsfree(r->buf); -    if (r->rlist != NULL) -        free(r->rlist);      free(r);  } @@ -383,7 +394,7 @@ static void redisSetReplyReaderError(redisReader *r, sds err) {          r->buf = sdsempty();          r->pos = 0;      } -    r->rlen = r->rpos = 0; +    r->ridx = -1;      r->error = err;  } @@ -408,18 +419,17 @@ int redisReplyReaderGetReply(void *reader, void **reply) {      if (sdslen(r->buf) == 0)          return REDIS_OK; -    /* Create first item to process when the item list is empty. */ -    if (r->rlen == 0) { -        r->rlist = realloc(r->rlist,sizeof(redisReadTask)*1); -        r->rlist[0].type = -1; -        r->rlist[0].parent = NULL; -        r->rlist[0].idx = -1; -        r->rlen = 1; -        r->rpos = 0; +    /* Set first item to process when the stack is empty. */ +    if (r->ridx == -1) { +        r->rstack[0].type = -1; +        r->rstack[0].elements = -1; +        r->rstack[0].parent = NULL; +        r->rstack[0].idx = -1; +        r->ridx = 0;      }      /* Process items in reply. */ -    while (r->rpos < r->rlen) +    while (r->ridx >= 0)          if (processItem(r) < 0)              break; @@ -436,7 +446,7 @@ int redisReplyReaderGetReply(void *reader, void **reply) {      }      /* Emit a reply when there is one. */ -    if (r->rpos == r->rlen) { +    if (r->ridx == -1) {          void *aux = r->reply;          r->reply = NULL; @@ -447,9 +457,6 @@ int redisReplyReaderGetReply(void *reader, void **reply) {              r->pos = 0;          } -        /* Set list of items to read to be empty. */ -        r->rlen = r->rpos = 0; -          /* Check if there actually *is* a reply. */          if (r->error != NULL) {              return REDIS_ERR; @@ -61,6 +61,7 @@ typedef struct redisReply {  typedef struct redisReadTask {      int type; +    int elements; /* number of elements in multibulk container */      void *parent; /* optional pointer to parent object */      int idx; /* index in parent (array) object */  } redisReadTask; | 
