Return the reply type when the reply object function set is NULL

This commit is contained in:
Pieter Noordhuis 2010-11-04 10:54:01 +01:00
parent e5a8228946
commit 2e5e9a49fd
3 changed files with 46 additions and 15 deletions

View File

@ -207,11 +207,15 @@ static int processLineItem(redisReader *r) {
int len; int len;
if ((p = readLine(r,&len)) != NULL) { if ((p = readLine(r,&len)) != NULL) {
if (r->fn) {
if (cur->type == REDIS_REPLY_INTEGER) { if (cur->type == REDIS_REPLY_INTEGER) {
obj = r->fn->createInteger(cur,strtoll(p,NULL,10)); obj = r->fn->createInteger(cur,strtoll(p,NULL,10));
} else { } else {
obj = r->fn->createString(cur,p,len); obj = r->fn->createString(cur,p,len);
} }
} else {
obj = (void*)(size_t)(cur->type);
}
/* 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)
@ -238,12 +242,14 @@ static int processBulkItem(redisReader *r) {
if (len < 0) { if (len < 0) {
/* The nil object can always be created. */ /* The nil object can always be created. */
obj = r->fn->createNil(cur); obj = r->fn ? r->fn->createNil(cur) :
(void*)REDIS_REPLY_NIL;
} else { } else {
/* Only continue when the buffer contains the entire bulk item. */ /* Only continue when the buffer contains the entire bulk item. */
bytelen += len+2; /* include \r\n */ bytelen += len+2; /* include \r\n */
if (r->pos+bytelen <= sdslen(r->buf)) { if (r->pos+bytelen <= sdslen(r->buf)) {
obj = r->fn->createString(cur,s+2,len); obj = r->fn ? r->fn->createString(cur,s+2,len) :
(void*)REDIS_REPLY_STRING;
} }
} }
@ -268,10 +274,12 @@ static int processMultiBulkItem(redisReader *r) {
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 ? r->fn->createNil(cur) :
(void*)REDIS_REPLY_NIL;
moveToNextTask(r); moveToNextTask(r);
} else { } else {
obj = r->fn->createArray(cur,elements); obj = r->fn ? r->fn->createArray(cur,elements) :
(void*)REDIS_REPLY_ARRAY;
/* Modify task stack when there are more than 0 elements. */ /* Modify task stack when there are more than 0 elements. */
if (elements > 0) { if (elements > 0) {
@ -348,15 +356,26 @@ static int processItem(redisReader *r) {
} }
} }
void *redisReplyReaderCreate(redisReplyObjectFunctions *fn) { void *redisReplyReaderCreate() {
redisReader *r = calloc(sizeof(redisReader),1); redisReader *r = calloc(sizeof(redisReader),1);
r->error = NULL; r->error = NULL;
r->fn = fn == NULL ? &defaultFunctions : fn; r->fn = &defaultFunctions;
r->buf = sdsempty(); r->buf = sdsempty();
r->ridx = -1; r->ridx = -1;
return r; return r;
} }
/* Set the function set to build the reply. Returns REDIS_OK when there
* is no temporary object and it can be set, REDIS_ERR otherwise. */
int redisReplyReaderSetReplyObjectFunctions(void *reader, redisReplyObjectFunctions *fn) {
redisReader *r = reader;
if (r->reply == NULL) {
r->fn = fn;
return REDIS_OK;
}
return REDIS_ERR;
}
/* External libraries wrapping hiredis might need access to the temporary /* External libraries wrapping hiredis might need access to the temporary
* variable while the reply is built up. When the reader contains an * variable while the reply is built up. When the reader contains an
* object in between receiving some bytes to parse, this object might * object in between receiving some bytes to parse, this object might
@ -370,7 +389,7 @@ void redisReplyReaderFree(void *reader) {
redisReader *r = reader; redisReader *r = reader;
if (r->error != NULL) if (r->error != NULL)
sdsfree(r->error); sdsfree(r->error);
if (r->reply != NULL) if (r->reply != NULL && r->fn)
r->fn->freeObject(r->reply); r->fn->freeObject(r->reply);
if (r->buf != NULL) if (r->buf != NULL)
sdsfree(r->buf); sdsfree(r->buf);
@ -695,8 +714,10 @@ int redisSetReplyObjectFunctions(redisContext *c, redisReplyObjectFunctions *fn)
/* Helper function to lazily create a reply reader. */ /* Helper function to lazily create a reply reader. */
static void __redisCreateReplyReader(redisContext *c) { static void __redisCreateReplyReader(redisContext *c) {
if (c->reader == NULL) if (c->reader == NULL) {
c->reader = redisReplyReaderCreate(c->fn); c->reader = redisReplyReaderCreate();
assert(redisReplyReaderSetReplyObjectFunctions(c->reader,c->fn) == REDIS_OK);
}
} }
/* Use this function to handle a read event on the descriptor. It will try /* Use this function to handle a read event on the descriptor. It will try

View File

@ -110,7 +110,8 @@ typedef struct redisContext {
} redisContext; } redisContext;
void freeReplyObject(void *reply); void freeReplyObject(void *reply);
void *redisReplyReaderCreate(redisReplyObjectFunctions *fn); void *redisReplyReaderCreate();
int redisReplyReaderSetReplyObjectFunctions(void *reader, redisReplyObjectFunctions *fn);
void *redisReplyReaderGetObject(void *reader); void *redisReplyReaderGetObject(void *reader);
char *redisReplyReaderGetError(void *reader); char *redisReplyReaderGetError(void *reader);
void redisReplyReaderFree(void *ptr); void redisReplyReaderFree(void *ptr);

13
test.c
View File

@ -186,11 +186,12 @@ static void test_blocking_connection() {
static void test_reply_reader() { static void test_reply_reader() {
void *reader; void *reader;
void *reply;
char *err; char *err;
int ret; int ret;
test("Error handling in reply parser: "); test("Error handling in reply parser: ");
reader = redisReplyReaderCreate(NULL); reader = redisReplyReaderCreate();
redisReplyReaderFeed(reader,(char*)"@foo\r\n",6); redisReplyReaderFeed(reader,(char*)"@foo\r\n",6);
ret = redisReplyReaderGetReply(reader,NULL); ret = redisReplyReaderGetReply(reader,NULL);
err = redisReplyReaderGetError(reader); err = redisReplyReaderGetError(reader);
@ -201,7 +202,7 @@ static void test_reply_reader() {
/* when the reply already contains multiple items, they must be free'd /* when the reply already contains multiple items, they must be free'd
* on an error. valgrind will bark when this doesn't happen. */ * on an error. valgrind will bark when this doesn't happen. */
test("Memory cleanup in reply parser: "); test("Memory cleanup in reply parser: ");
reader = redisReplyReaderCreate(NULL); reader = redisReplyReaderCreate();
redisReplyReaderFeed(reader,(char*)"*2\r\n",4); redisReplyReaderFeed(reader,(char*)"*2\r\n",4);
redisReplyReaderFeed(reader,(char*)"$5\r\nhello\r\n",11); redisReplyReaderFeed(reader,(char*)"$5\r\nhello\r\n",11);
redisReplyReaderFeed(reader,(char*)"@foo\r\n",6); redisReplyReaderFeed(reader,(char*)"@foo\r\n",6);
@ -210,6 +211,14 @@ static void test_reply_reader() {
test_cond(ret == REDIS_ERR && test_cond(ret == REDIS_ERR &&
strcasecmp(err,"protocol error, got \"@\" as reply type byte") == 0); strcasecmp(err,"protocol error, got \"@\" as reply type byte") == 0);
redisReplyReaderFree(reader); redisReplyReaderFree(reader);
test("Works with NULL functions for reply: ");
reader = redisReplyReaderCreate();
redisReplyReaderSetReplyObjectFunctions(reader,NULL);
redisReplyReaderFeed(reader,(char*)"+OK\r\n",5);
ret = redisReplyReaderGetReply(reader,&reply);
test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS);
redisReplyReaderFree(reader);
} }
static void test_throughput() { static void test_throughput() {