Deprecate the error object for I/O and protocol errors
Rather, use the return value REDIS_OK and REDIS_ERR to designate if calling a function has a successful outcome. When there was an error in performing the call the error field will be set inside the reader or the context.
This commit is contained in:
parent
e6fb160b44
commit
a7d7618141
211
hiredis.c
211
hiredis.c
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
typedef struct redisReader {
|
typedef struct redisReader {
|
||||||
struct redisReplyObjectFunctions *fn;
|
struct redisReplyObjectFunctions *fn;
|
||||||
|
sds error; /* holds optional error */
|
||||||
void *reply; /* holds temporary reply */
|
void *reply; /* holds temporary reply */
|
||||||
|
|
||||||
sds buf; /* read buffer */
|
sds buf; /* read buffer */
|
||||||
@ -52,16 +53,14 @@ typedef struct redisReader {
|
|||||||
} redisReader;
|
} redisReader;
|
||||||
|
|
||||||
static redisReply *createReplyObject(int type, sds reply);
|
static redisReply *createReplyObject(int type, sds reply);
|
||||||
static void *createErrorObject(const char *str, size_t len);
|
|
||||||
static void *createStringObject(redisReadTask *task, char *str, size_t len);
|
static void *createStringObject(redisReadTask *task, char *str, size_t len);
|
||||||
static void *createArrayObject(redisReadTask *task, int elements);
|
static void *createArrayObject(redisReadTask *task, int elements);
|
||||||
static void *createIntegerObject(redisReadTask *task, long long value);
|
static void *createIntegerObject(redisReadTask *task, long long value);
|
||||||
static void *createNilObject(redisReadTask *task);
|
static void *createNilObject(redisReadTask *task);
|
||||||
static void redisSetReplyReaderError(redisReader *r, void *obj);
|
static void redisSetReplyReaderError(redisReader *r, sds err);
|
||||||
|
|
||||||
/* Default set of functions to build the reply. */
|
/* Default set of functions to build the reply. */
|
||||||
static redisReplyFunctions defaultFunctions = {
|
static redisReplyFunctions defaultFunctions = {
|
||||||
createErrorObject,
|
|
||||||
createStringObject,
|
createStringObject,
|
||||||
createArrayObject,
|
createArrayObject,
|
||||||
createIntegerObject,
|
createIntegerObject,
|
||||||
@ -106,24 +105,6 @@ void freeReplyObject(void *reply) {
|
|||||||
free(r);
|
free(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function that allows printf-like creation of error objects. */
|
|
||||||
static void *formatError(redisReplyFunctions *fn, const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
sds err;
|
|
||||||
void *obj;
|
|
||||||
va_start(ap,fmt);
|
|
||||||
err = sdscatvprintf(sdsempty(),fmt,ap);
|
|
||||||
va_end(ap);
|
|
||||||
obj = fn->createError(err,sdslen(err));
|
|
||||||
sdsfree(err);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *createErrorObject(const char *str, size_t len) {
|
|
||||||
redisReply *r = createReplyObject(REDIS_ERROR,sdsnewlen(str,len));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *createStringObject(redisReadTask *task, char *str, size_t len) {
|
static void *createStringObject(redisReadTask *task, char *str, size_t len) {
|
||||||
redisReply *r = createReplyObject(task->type,sdsnewlen(str,len));
|
redisReply *r = createReplyObject(task->type,sdsnewlen(str,len));
|
||||||
assert(task->type == REDIS_REPLY_ERROR ||
|
assert(task->type == REDIS_REPLY_ERROR ||
|
||||||
@ -308,7 +289,6 @@ static int processItem(redisReader *r) {
|
|||||||
redisReadTask *cur = &(r->rlist[r->rpos]);
|
redisReadTask *cur = &(r->rlist[r->rpos]);
|
||||||
char *p;
|
char *p;
|
||||||
sds byte;
|
sds byte;
|
||||||
void *err;
|
|
||||||
|
|
||||||
/* check if we need to read type */
|
/* check if we need to read type */
|
||||||
if (cur->type < 0) {
|
if (cur->type < 0) {
|
||||||
@ -331,9 +311,8 @@ static int processItem(redisReader *r) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
byte = sdscatrepr(sdsempty(),p,1);
|
byte = sdscatrepr(sdsempty(),p,1);
|
||||||
err = formatError(r->fn,
|
redisSetReplyReaderError(r,sdscatprintf(sdsempty(),
|
||||||
"protocol error, got %s as reply type byte", byte);
|
"protocol error, got %s as reply type byte", byte));
|
||||||
redisSetReplyReaderError(r,err);
|
|
||||||
sdsfree(byte);
|
sdsfree(byte);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -354,14 +333,15 @@ static int processItem(redisReader *r) {
|
|||||||
case REDIS_REPLY_ARRAY:
|
case REDIS_REPLY_ARRAY:
|
||||||
return processMultiBulkItem(r);
|
return processMultiBulkItem(r);
|
||||||
default:
|
default:
|
||||||
err = formatError(r->fn,"unknown item type '%d'", cur->type);
|
redisSetReplyReaderError(r,sdscatprintf(sdsempty(),
|
||||||
redisSetReplyReaderError(r,err);
|
"unknown item type '%d'", cur->type));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *redisReplyReaderCreate(redisReplyFunctions *fn) {
|
void *redisReplyReaderCreate(redisReplyFunctions *fn) {
|
||||||
redisReader *r = calloc(sizeof(redisReader),1);
|
redisReader *r = calloc(sizeof(redisReader),1);
|
||||||
|
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->rlist = malloc(sizeof(redisReadTask)*1);
|
||||||
@ -379,6 +359,8 @@ void *redisReplyReaderGetObject(void *reader) {
|
|||||||
|
|
||||||
void redisReplyReaderFree(void *reader) {
|
void redisReplyReaderFree(void *reader) {
|
||||||
redisReader *r = reader;
|
redisReader *r = reader;
|
||||||
|
if (r->error != NULL)
|
||||||
|
sdsfree(r->error);
|
||||||
if (r->reply != NULL)
|
if (r->reply != NULL)
|
||||||
r->fn->freeObject(r->reply);
|
r->fn->freeObject(r->reply);
|
||||||
if (r->buf != NULL)
|
if (r->buf != NULL)
|
||||||
@ -388,7 +370,7 @@ void redisReplyReaderFree(void *reader) {
|
|||||||
free(r);
|
free(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void redisSetReplyReaderError(redisReader *r, void *obj) {
|
static void redisSetReplyReaderError(redisReader *r, sds err) {
|
||||||
if (r->reply != NULL)
|
if (r->reply != NULL)
|
||||||
r->fn->freeObject(r->reply);
|
r->fn->freeObject(r->reply);
|
||||||
|
|
||||||
@ -399,7 +381,12 @@ static void redisSetReplyReaderError(redisReader *r, void *obj) {
|
|||||||
r->pos = 0;
|
r->pos = 0;
|
||||||
}
|
}
|
||||||
r->rlen = r->rpos = 0;
|
r->rlen = r->rpos = 0;
|
||||||
r->reply = obj;
|
r->error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *redisReplyReaderGetError(void *reader) {
|
||||||
|
redisReader *r = reader;
|
||||||
|
return r->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void redisReplyReaderFeed(void *reader, char *buf, int len) {
|
void redisReplyReaderFeed(void *reader, char *buf, int len) {
|
||||||
@ -410,12 +397,13 @@ void redisReplyReaderFeed(void *reader, char *buf, int len) {
|
|||||||
r->buf = sdscatlen(r->buf,buf,len);
|
r->buf = sdscatlen(r->buf,buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *redisReplyReaderGetReply(void *reader) {
|
int redisReplyReaderGetReply(void *reader, void **reply) {
|
||||||
redisReader *r = reader;
|
redisReader *r = reader;
|
||||||
|
if (reply != NULL) *reply = NULL;
|
||||||
|
|
||||||
/* When the buffer is empty, there will never be a reply. */
|
/* When the buffer is empty, there will never be a reply. */
|
||||||
if (sdslen(r->buf) == 0)
|
if (sdslen(r->buf) == 0)
|
||||||
return NULL;
|
return REDIS_OK;
|
||||||
|
|
||||||
/* Create first item to process when the item list is empty. */
|
/* Create first item to process when the item list is empty. */
|
||||||
if (r->rlen == 0) {
|
if (r->rlen == 0) {
|
||||||
@ -446,7 +434,7 @@ void *redisReplyReaderGetReply(void *reader) {
|
|||||||
|
|
||||||
/* Emit a reply when there is one. */
|
/* Emit a reply when there is one. */
|
||||||
if (r->rpos == r->rlen) {
|
if (r->rpos == r->rlen) {
|
||||||
void *reply = r->reply;
|
void *aux = r->reply;
|
||||||
r->reply = NULL;
|
r->reply = NULL;
|
||||||
|
|
||||||
/* Destroy the buffer when it is empty and is quite large. */
|
/* Destroy the buffer when it is empty and is quite large. */
|
||||||
@ -458,10 +446,15 @@ void *redisReplyReaderGetReply(void *reader) {
|
|||||||
|
|
||||||
/* Set list of items to read to be empty. */
|
/* Set list of items to read to be empty. */
|
||||||
r->rlen = r->rpos = 0;
|
r->rlen = r->rpos = 0;
|
||||||
return reply;
|
|
||||||
} else {
|
/* Check if there actually *is* a reply. */
|
||||||
return NULL;
|
if (r->error != NULL) {
|
||||||
|
return REDIS_ERR;
|
||||||
|
} else {
|
||||||
|
if (reply != NULL) *reply = aux;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function for redisCommand(). It's used to append the next argument
|
/* Helper function for redisCommand(). It's used to append the next argument
|
||||||
@ -571,11 +564,11 @@ static int redisContextConnect(redisContext *c, const char *ip, int port) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (c->fd == ANET_ERR) {
|
if (c->fd == ANET_ERR) {
|
||||||
c->error = c->fn->createError(err,strlen(err));
|
c->error = sdsnew(err);
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
if (anetTcpNoDelay(err,c->fd) == ANET_ERR) {
|
if (anetTcpNoDelay(err,c->fd) == ANET_ERR) {
|
||||||
c->error = c->fn->createError(err,strlen(err));
|
c->error = sdsnew(err);
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
@ -623,12 +616,12 @@ int redisBufferRead(redisContext *c) {
|
|||||||
/* Try again later */
|
/* Try again later */
|
||||||
} else {
|
} else {
|
||||||
/* Set error in context */
|
/* Set error in context */
|
||||||
c->error = formatError(c->fn,
|
c->error = sdscatprintf(sdsempty(),
|
||||||
"Error reading from socket: %s", strerror(errno));
|
"Error reading from socket: %s", strerror(errno));
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
} else if (nread == 0) {
|
} else if (nread == 0) {
|
||||||
c->error = formatError(c->fn,
|
c->error = sdscatprintf(sdsempty(),
|
||||||
"Server closed the connection");
|
"Server closed the connection");
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
} else {
|
} else {
|
||||||
@ -644,21 +637,34 @@ static void redisPopCallback(redisContext *c) {
|
|||||||
c->cpos--;
|
c->cpos--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *redisGetReply(redisContext *c) {
|
int redisGetReply(redisContext *c, void **reply) {
|
||||||
redisPopCallback(c);
|
redisPopCallback(c);
|
||||||
return redisReplyReaderGetReply(c->reader);
|
if (redisReplyReaderGetReply(c->reader,reply) == REDIS_ERR) {
|
||||||
|
/* Copy the (protocol) error from the reader to the context. */
|
||||||
|
c->error = sdsnew(((redisReader*)c->reader)->error);
|
||||||
|
return REDIS_ERR;
|
||||||
|
}
|
||||||
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int redisProcessCallbacks(redisContext *c) {
|
int redisProcessCallbacks(redisContext *c) {
|
||||||
void *reply;
|
void *reply = NULL;
|
||||||
redisCallback cb;
|
redisCallback cb;
|
||||||
|
|
||||||
while ((reply = redisReplyReaderGetReply(c->reader)) != NULL) {
|
do {
|
||||||
cb = c->callbacks[0];
|
cb = c->callbacks[0];
|
||||||
if (cb.fn != NULL)
|
if (redisGetReply(c,&reply) == REDIS_ERR)
|
||||||
cb.fn(c,reply,cb.privdata);
|
return REDIS_ERR;
|
||||||
redisPopCallback(c);
|
|
||||||
}
|
/* Fire callback when there is a reply. */
|
||||||
|
if (reply != NULL) {
|
||||||
|
if (cb.fn != NULL) {
|
||||||
|
cb.fn(c,reply,cb.privdata);
|
||||||
|
} else {
|
||||||
|
c->fn->freeObject(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (reply != NULL);
|
||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,7 +677,7 @@ int redisBufferWrite(redisContext *c, int *done) {
|
|||||||
/* Try again later */
|
/* Try again later */
|
||||||
} else {
|
} else {
|
||||||
/* Set error in context */
|
/* Set error in context */
|
||||||
c->error = formatError(c->fn,
|
c->error = sdscatprintf(sdsempty(),
|
||||||
"Error writing to socket: %s", strerror(errno));
|
"Error writing to socket: %s", strerror(errno));
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
@ -687,73 +693,102 @@ int redisBufferWrite(redisContext *c, int *done) {
|
|||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* redisCommandWrite(redisContext *c, redisCallback *cb, char *str, size_t len) {
|
static int redisCommandWriteBlock(redisContext *c, void **reply, char *str, size_t len) {
|
||||||
void *reply = NULL;
|
|
||||||
int wdone = 0;
|
int wdone = 0;
|
||||||
|
void *aux = NULL;
|
||||||
|
assert(c->flags & HIREDIS_BLOCK);
|
||||||
c->obuf = sdscatlen(c->obuf,str,len);
|
c->obuf = sdscatlen(c->obuf,str,len);
|
||||||
|
|
||||||
/* Read reply immediately when the context is blocking. */
|
/* Write until done. */
|
||||||
if (c->flags & HIREDIS_BLOCK) {
|
do {
|
||||||
do { /* Write until done. */
|
if (redisBufferWrite(c,&wdone) == REDIS_ERR)
|
||||||
if (redisBufferWrite(c,&wdone) == REDIS_ERR)
|
return REDIS_ERR;
|
||||||
return c->error;
|
} while (!wdone);
|
||||||
} while (!wdone);
|
|
||||||
|
|
||||||
do { /* Read until there is a reply. */
|
/* Read until there is a reply. */
|
||||||
if (redisBufferRead(c) == REDIS_ERR)
|
do {
|
||||||
return c->error;
|
if (redisBufferRead(c) == REDIS_ERR)
|
||||||
reply = redisGetReply(c);
|
return REDIS_ERR;
|
||||||
} while (reply == NULL);
|
if (redisGetReply(c,&aux) == REDIS_ERR)
|
||||||
} else {
|
return REDIS_ERR;
|
||||||
/* Make room for the callback. */
|
} while (aux == NULL);
|
||||||
assert(c->cpos <= c->clen);
|
|
||||||
if (c->cpos == c->clen) {
|
|
||||||
c->clen++;
|
|
||||||
c->callbacks = realloc(c->callbacks,c->clen*sizeof(redisCallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cb != NULL) {
|
/* Set reply object. */
|
||||||
c->callbacks[c->cpos] = *cb;
|
if (reply != NULL)
|
||||||
} else {
|
*reply = aux;
|
||||||
memset(&c->callbacks[c->cpos],0,sizeof(redisCallback));
|
|
||||||
}
|
return REDIS_OK;
|
||||||
c->cpos++;
|
|
||||||
}
|
|
||||||
return reply;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a formatted command to the output buffer, and, if the context is a
|
static int redisCommandWriteNonBlock(redisContext *c, redisCallback *cb, char *str, size_t len) {
|
||||||
* blocking connection, read the reply and return it. When this function
|
assert(!(c->flags & HIREDIS_BLOCK));
|
||||||
* is called from a non-blocking context, it will always return NULL. */
|
c->obuf = sdscatlen(c->obuf,str,len);
|
||||||
|
|
||||||
|
/* Make sure there is space for the callback. */
|
||||||
|
assert(c->cpos <= c->clen);
|
||||||
|
if (c->cpos == c->clen) {
|
||||||
|
c->clen++;
|
||||||
|
c->callbacks = realloc(c->callbacks,c->clen*sizeof(redisCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb != NULL) {
|
||||||
|
c->callbacks[c->cpos] = *cb;
|
||||||
|
} else {
|
||||||
|
memset(&c->callbacks[c->cpos],0,sizeof(redisCallback));
|
||||||
|
}
|
||||||
|
c->cpos++;
|
||||||
|
|
||||||
|
return REDIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a formatted command to the output buffer. If the given context is
|
||||||
|
* blocking, immediately read the reply into the "reply" pointer. When the
|
||||||
|
* context is non-blocking, the "reply" pointer will not be used and a
|
||||||
|
* NULL callback will be appended to the list of callbacks.
|
||||||
|
*
|
||||||
|
* Returns the reply when a reply was succesfully retrieved. Returns NULL
|
||||||
|
* otherwise. When NULL is returned in a blocking context, provided that
|
||||||
|
* the reply build functions did not return NULL when building the reply,
|
||||||
|
* the error field in the context will be set. */
|
||||||
void *redisCommand(redisContext *c, const char *format, ...) {
|
void *redisCommand(redisContext *c, const char *format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
sds cmd;
|
sds cmd;
|
||||||
void *reply;
|
void *reply = NULL;
|
||||||
va_start(ap,format);
|
va_start(ap,format);
|
||||||
cmd = redisFormatCommand(format,ap);
|
cmd = redisFormatCommand(format,ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
reply = redisCommandWrite(c,NULL,cmd,sdslen(cmd));
|
if (c->flags & HIREDIS_BLOCK) {
|
||||||
|
if (redisCommandWriteBlock(c,&reply,cmd,sdslen(cmd)) == REDIS_OK) {
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
redisCommandWriteNonBlock(c,NULL,cmd,sdslen(cmd));
|
||||||
|
}
|
||||||
sdsfree(cmd);
|
sdsfree(cmd);
|
||||||
return reply;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a formatted command to the output buffer and register the provided
|
/* Write a formatted command to the output buffer. Registers the provided
|
||||||
* callback function and argument. When this function is called in a
|
* callback function and argument in the callback list.
|
||||||
* non-blocking context, it is a no-op. Always returns NULL. */
|
*
|
||||||
|
* Always returns NULL. In a non-blocking context this will never fail because
|
||||||
|
* this function does not do any I/O. In a blocking context this function will
|
||||||
|
* have no effect (a callback in a blocking context makes no sense). */
|
||||||
void *redisCommandWithCallback(redisContext *c, redisCallbackFn *fn, void *privdata, const char *format, ...) {
|
void *redisCommandWithCallback(redisContext *c, redisCallbackFn *fn, void *privdata, const char *format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
redisCallback cb = { fn, privdata };
|
|
||||||
sds cmd;
|
sds cmd;
|
||||||
|
int status;
|
||||||
|
redisCallback cb = { fn, privdata };
|
||||||
|
|
||||||
/* Skip if the context is blocking. */
|
/* This function may only be used in a non-blocking context. */
|
||||||
if (c->flags & HIREDIS_BLOCK) return NULL;
|
if (c->flags & HIREDIS_BLOCK) return NULL;
|
||||||
|
|
||||||
va_start(ap,format);
|
va_start(ap,format);
|
||||||
cmd = redisFormatCommand(format,ap);
|
cmd = redisFormatCommand(format,ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
redisCommandWrite(c,&cb,cmd,sdslen(cmd));
|
status = redisCommandWriteNonBlock(c,&cb,cmd,sdslen(cmd));
|
||||||
sdsfree(cmd);
|
sdsfree(cmd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,6 @@ typedef struct redisReadTask {
|
|||||||
} redisReadTask;
|
} redisReadTask;
|
||||||
|
|
||||||
typedef struct redisReplyObjectFunctions {
|
typedef struct redisReplyObjectFunctions {
|
||||||
void *(*createError)(const char*, size_t);
|
|
||||||
void *(*createString)(redisReadTask*, char*, size_t);
|
void *(*createString)(redisReadTask*, char*, size_t);
|
||||||
void *(*createArray)(redisReadTask*, int);
|
void *(*createArray)(redisReadTask*, int);
|
||||||
void *(*createInteger)(redisReadTask*, long long);
|
void *(*createInteger)(redisReadTask*, long long);
|
||||||
@ -85,7 +84,7 @@ typedef struct redisCallback {
|
|||||||
typedef struct redisContext {
|
typedef struct redisContext {
|
||||||
int fd;
|
int fd;
|
||||||
int flags;
|
int flags;
|
||||||
void *error; /* Error object is set when in erronous state */
|
sds error; /* Error object is set when in erronous state */
|
||||||
sds obuf; /* Write buffer */
|
sds obuf; /* Write buffer */
|
||||||
redisReplyFunctions *fn;
|
redisReplyFunctions *fn;
|
||||||
void *reader;
|
void *reader;
|
||||||
@ -97,15 +96,16 @@ typedef struct redisContext {
|
|||||||
void freeReplyObject(void *reply);
|
void freeReplyObject(void *reply);
|
||||||
void *redisReplyReaderCreate(redisReplyFunctions *fn);
|
void *redisReplyReaderCreate(redisReplyFunctions *fn);
|
||||||
void *redisReplyReaderGetObject(void *reader);
|
void *redisReplyReaderGetObject(void *reader);
|
||||||
|
char *redisReplyReaderGetError(void *reader);
|
||||||
void redisReplyReaderFree(void *ptr);
|
void redisReplyReaderFree(void *ptr);
|
||||||
void redisReplyReaderFeed(void *reader, char *buf, int len);
|
void redisReplyReaderFeed(void *reader, char *buf, int len);
|
||||||
void *redisReplyReaderGetReply(void *reader);
|
int redisReplyReaderGetReply(void *reader, void **reply);
|
||||||
|
|
||||||
redisContext *redisConnect(const char *ip, int port, redisReplyFunctions *fn);
|
redisContext *redisConnect(const char *ip, int port, redisReplyFunctions *fn);
|
||||||
redisContext *redisConnectNonBlock(const char *ip, int port, redisReplyFunctions *fn);
|
redisContext *redisConnectNonBlock(const char *ip, int port, redisReplyFunctions *fn);
|
||||||
int redisBufferRead(redisContext *c);
|
int redisBufferRead(redisContext *c);
|
||||||
int redisBufferWrite(redisContext *c, int *done);
|
int redisBufferWrite(redisContext *c, int *done);
|
||||||
void *redisGetReply(redisContext *c);
|
int redisGetReply(redisContext *c, void **reply);
|
||||||
int redisProcessCallbacks(redisContext *c);
|
int redisProcessCallbacks(redisContext *c);
|
||||||
|
|
||||||
void *redisCommand(redisContext *c, const char *format, ...);
|
void *redisCommand(redisContext *c, const char *format, ...);
|
||||||
|
25
test.c
25
test.c
@ -25,18 +25,17 @@ static void __connect(redisContext **c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
int i, tests = 0, fails = 0;
|
int i, ret, tests = 0, fails = 0;
|
||||||
long long t1, t2;
|
long long t1, t2;
|
||||||
redisContext *c;
|
redisContext *c;
|
||||||
redisReply *reply;
|
redisReply *reply;
|
||||||
void *reader;
|
void *reader;
|
||||||
|
char *err;
|
||||||
__connect(&c);
|
__connect(&c);
|
||||||
|
|
||||||
test("Returns I/O error when the connection is lost: ");
|
test("Returns I/O error when the connection is lost: ");
|
||||||
reply = redisCommand(c,"QUIT");
|
test_cond(redisCommand(c,"QUIT") == NULL &&
|
||||||
test_cond(reply->type == REDIS_ERROR &&
|
strcmp(c->error,"Server closed the connection") == 0);
|
||||||
strcmp(reply->reply,"Server closed the connection") == 0);
|
|
||||||
freeReplyObject(reply);
|
|
||||||
__connect(&c); /* reconnect */
|
__connect(&c); /* reconnect */
|
||||||
|
|
||||||
test("Is able to deliver commands: ");
|
test("Is able to deliver commands: ");
|
||||||
@ -126,10 +125,10 @@ int main(void) {
|
|||||||
test("Error handling in reply parser: ");
|
test("Error handling in reply parser: ");
|
||||||
reader = redisReplyReaderCreate(NULL);
|
reader = redisReplyReaderCreate(NULL);
|
||||||
redisReplyReaderFeed(reader,(char*)"@foo\r\n",6);
|
redisReplyReaderFeed(reader,(char*)"@foo\r\n",6);
|
||||||
reply = redisReplyReaderGetReply(reader);
|
ret = redisReplyReaderGetReply(reader,(void*)&reply);
|
||||||
test_cond(reply->type == REDIS_ERROR &&
|
err = redisReplyReaderGetError(reader);
|
||||||
strcasecmp(reply->reply,"protocol error, got \"@\" as reply type byte") == 0);
|
test_cond(ret == REDIS_ERR &&
|
||||||
freeReplyObject(reply);
|
strcasecmp(err,"protocol error, got \"@\" as reply type byte") == 0);
|
||||||
redisReplyReaderFree(reader);
|
redisReplyReaderFree(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
|
||||||
@ -139,10 +138,10 @@ int main(void) {
|
|||||||
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);
|
||||||
reply = redisReplyReaderGetReply(reader);
|
ret = redisReplyReaderGetReply(reader,(void*)&reply);
|
||||||
test_cond(reply->type == REDIS_ERROR &&
|
err = redisReplyReaderGetError(reader);
|
||||||
strcasecmp(reply->reply,"protocol error, got \"@\" as reply type byte") == 0);
|
test_cond(ret == REDIS_ERR &&
|
||||||
freeReplyObject(reply);
|
strcasecmp(err,"protocol error, got \"@\" as reply type byte") == 0);
|
||||||
redisReplyReaderFree(reader);
|
redisReplyReaderFree(reader);
|
||||||
|
|
||||||
test("Throughput:\n");
|
test("Throughput:\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user