Refactor internal function flow and add redisAppendCommand* family
This commit is contained in:
parent
298e9325d7
commit
47e1f77149
167
hiredis.c
167
hiredis.c
|
@ -730,15 +730,6 @@ int redisBufferRead(redisContext *c) {
|
|||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisGetReply(redisContext *c, void **reply) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Write the output buffer to the socket.
|
||||
*
|
||||
* Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
|
||||
|
@ -774,69 +765,137 @@ int redisBufferWrite(redisContext *c, int *done) {
|
|||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int redisCommandWriteBlock(redisContext *c, void **reply, char *str, size_t len) {
|
||||
int wdone = 0;
|
||||
void *aux = NULL;
|
||||
assert(c->flags & REDIS_BLOCK);
|
||||
c->obuf = sdscatlen(c->obuf,str,len);
|
||||
|
||||
/* Write until done. */
|
||||
do {
|
||||
if (redisBufferWrite(c,&wdone) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
} while (!wdone);
|
||||
|
||||
/* Read until there is a reply. */
|
||||
do {
|
||||
if (redisBufferRead(c) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
if (redisGetReply(c,&aux) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
} while (aux == NULL);
|
||||
|
||||
/* Set reply object. */
|
||||
if (reply != NULL)
|
||||
*reply = aux;
|
||||
|
||||
/* Internal helper function to try and get a reply from the reader,
|
||||
* or set an error in the context otherwise. */
|
||||
static int __redisGetReply(redisContext *c, void **reply) {
|
||||
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;
|
||||
}
|
||||
|
||||
static int redisCommandWriteNonBlock(redisContext *c, char *str, size_t len) {
|
||||
assert(!(c->flags & REDIS_BLOCK));
|
||||
c->obuf = sdscatlen(c->obuf,str,len);
|
||||
int redisGetReply(redisContext *c, void **reply) {
|
||||
int wdone = 0;
|
||||
void *aux = NULL;
|
||||
|
||||
/* Try to read pending replies */
|
||||
if (__redisGetReply(c,&aux) == REDIS_ERR) {
|
||||
return REDIS_ERR;
|
||||
} else {
|
||||
/* Return immediately if there was a pending reply */
|
||||
if (aux != NULL) return REDIS_OK;
|
||||
}
|
||||
|
||||
/* For the blocking context, flush output buffer and read reply */
|
||||
if (c->flags & REDIS_BLOCK) {
|
||||
/* Write until done */
|
||||
do {
|
||||
if (redisBufferWrite(c,&wdone) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
} while (!wdone);
|
||||
|
||||
/* Read until there is a reply */
|
||||
do {
|
||||
if (redisBufferRead(c) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
if (__redisGetReply(c,&aux) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
} while (aux == NULL);
|
||||
|
||||
/* Set reply object */
|
||||
if (reply != NULL) *reply = aux;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Helper function for the redisAppendCommand* family of functions.
|
||||
*
|
||||
* Write a formatted command to the output buffer. When this family
|
||||
* is used, you need to call redisGetReply yourself to retrieve
|
||||
* the reply (or replies in pub/sub).
|
||||
*/
|
||||
void __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
|
||||
c->obuf = sdscatlen(c->obuf,cmd,len);
|
||||
|
||||
/* Fire write callback */
|
||||
if (c->cbCommand.fn != NULL)
|
||||
c->cbCommand.fn(c,c->cbCommand.privdata);
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
/* Write a formatted command to the output buffer. If the given context is
|
||||
void redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
|
||||
char *cmd;
|
||||
int len;
|
||||
len = redisvFormatCommand(&cmd,format,ap);
|
||||
__redisAppendCommand(c,cmd,len);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
void redisAppendCommand(redisContext *c, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,format);
|
||||
redisvAppendCommand(c,format,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
|
||||
char *cmd;
|
||||
int len;
|
||||
len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
|
||||
__redisAppendCommand(c,cmd,len);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
/* Helper function for the redisCommand* family of functions.
|
||||
*
|
||||
* 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 the
|
||||
* command is simply appended to the write buffer.
|
||||
*
|
||||
* Returns the reply when a reply was succesfully retrieved. Returns NULL
|
||||
* otherwise. When NULL is returned in a blocking context, the error field
|
||||
* in the context will be set. */
|
||||
void *redisCommand(redisContext *c, const char *format, ...) {
|
||||
va_list ap;
|
||||
* in the context will be set.
|
||||
*/
|
||||
static void *__redisCommand(redisContext *c, char *cmd, size_t len) {
|
||||
void *aux = NULL;
|
||||
__redisAppendCommand(c,cmd,len);
|
||||
|
||||
if (c->flags & REDIS_BLOCK) {
|
||||
if (redisGetReply(c,&aux) == REDIS_OK)
|
||||
return aux;
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *redisvCommand(redisContext *c, const char *format, va_list ap) {
|
||||
char *cmd;
|
||||
int len;
|
||||
void *reply = NULL;
|
||||
va_start(ap,format);
|
||||
len = redisvFormatCommand(&cmd,format,ap);
|
||||
va_end(ap);
|
||||
|
||||
if (c->flags & REDIS_BLOCK) {
|
||||
if (redisCommandWriteBlock(c,&reply,cmd,len) == REDIS_OK) {
|
||||
free(cmd);
|
||||
return reply;
|
||||
}
|
||||
} else {
|
||||
redisCommandWriteNonBlock(c,cmd,len);
|
||||
}
|
||||
reply = __redisCommand(c,cmd,len);
|
||||
free(cmd);
|
||||
return NULL;
|
||||
return reply;
|
||||
}
|
||||
|
||||
void *redisCommand(redisContext *c, const char *format, ...) {
|
||||
va_list ap;
|
||||
void *reply = NULL;
|
||||
va_start(ap,format);
|
||||
reply = redisvCommand(c,format,ap);
|
||||
va_end(ap);
|
||||
return reply;
|
||||
}
|
||||
|
||||
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
|
||||
char *cmd;
|
||||
int len;
|
||||
void *reply = NULL;
|
||||
len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
|
||||
reply = __redisCommand(c,cmd,len);
|
||||
free(cmd);
|
||||
return reply;
|
||||
}
|
||||
|
|
23
hiredis.h
23
hiredis.h
|
@ -120,6 +120,11 @@ void redisDisconnect(redisContext *c);
|
|||
void redisFree(redisContext *c);
|
||||
int redisBufferRead(redisContext *c);
|
||||
int redisBufferWrite(redisContext *c, int *done);
|
||||
|
||||
/* In a blocking context, this function first checks if there are unconsumed
|
||||
* replies to return and returns one if so. Otherwise, it flushes the output
|
||||
* buffer to the socket and reads until it has a reply. In a non-blocking
|
||||
* context, it will return unconsumed replies until there are no more. */
|
||||
int redisGetReply(redisContext *c, void **reply);
|
||||
|
||||
/* The disconnect callback is called *immediately* when redisDisconnect()
|
||||
|
@ -136,11 +141,19 @@ void redisSetCommandCallback(redisContext *c, redisContextCallbackFn *fn, void *
|
|||
* release resources that depend/use the redisContext that is being free'd. */
|
||||
void redisSetFreeCallback(redisContext *c, redisContextCallbackFn *fn, void *privdata);
|
||||
|
||||
/* Issue a command to Redis. In a blocking context, it returns the reply. When
|
||||
* an error occurs, it returns NULL and you should read redisContext->error
|
||||
* to find out what's wrong. In a non-blocking context, it has the same effect
|
||||
* as calling redisCommandWithCallback() with a NULL callback, and will always
|
||||
* return NULL. */
|
||||
/* Write a command to the output buffer. Use these functions in blocking mode
|
||||
* to get a pipeline of commands. */
|
||||
void redisvAppendCommand(redisContext *c, const char *format, va_list ap);
|
||||
void redisAppendCommand(redisContext *c, const char *format, ...);
|
||||
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
|
||||
/* Issue a command to Redis. In a blocking context, it is identical to calling
|
||||
* redisAppendCommand, followed by redisGetReply. The function will return
|
||||
* NULL if there was an error in performing the request, otherwise it will
|
||||
* return the reply. In a non-blocking context, it is identical to calling
|
||||
* only redisAppendCommand and will always return NULL. */
|
||||
void *redisvCommand(redisContext *c, const char *format, va_list ap);
|
||||
void *redisCommand(redisContext *c, const char *format, ...);
|
||||
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue