add a command_timeout to redisContextOptions (#839)
Add an additional timeout so the user has a convenient way of controlling distinct connect and command timeouts
This commit is contained in:
parent
3bb985314d
commit
38b5ae543f
12
async.c
12
async.c
@ -868,19 +868,19 @@ redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPus
|
|||||||
}
|
}
|
||||||
|
|
||||||
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
|
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
|
||||||
if (!ac->c.timeout) {
|
if (!ac->c.command_timeout) {
|
||||||
ac->c.timeout = hi_calloc(1, sizeof(tv));
|
ac->c.command_timeout = hi_calloc(1, sizeof(tv));
|
||||||
if (ac->c.timeout == NULL) {
|
if (ac->c.command_timeout == NULL) {
|
||||||
__redisSetError(&ac->c, REDIS_ERR_OOM, "Out of memory");
|
__redisSetError(&ac->c, REDIS_ERR_OOM, "Out of memory");
|
||||||
__redisAsyncCopyError(ac);
|
__redisAsyncCopyError(ac);
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tv.tv_sec != ac->c.timeout->tv_sec ||
|
if (tv.tv_sec != ac->c.command_timeout->tv_sec ||
|
||||||
tv.tv_usec != ac->c.timeout->tv_usec)
|
tv.tv_usec != ac->c.command_timeout->tv_usec)
|
||||||
{
|
{
|
||||||
*ac->c.timeout = tv;
|
*ac->c.command_timeout = tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
|
@ -54,15 +54,14 @@
|
|||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
static inline void refreshTimeout(redisAsyncContext *ctx) {
|
static inline void refreshTimeout(redisAsyncContext *ctx) {
|
||||||
if (ctx->c.timeout && ctx->ev.scheduleTimer &&
|
if (!(ctx->c.flags & REDIS_CONNECTED)) {
|
||||||
(ctx->c.timeout->tv_sec || ctx->c.timeout->tv_usec)) {
|
if (ctx->c.connect_timeout && ctx->ev.scheduleTimer &&
|
||||||
ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.timeout);
|
(ctx->c.connect_timeout->tv_sec || ctx->c.connect_timeout->tv_usec)) {
|
||||||
// } else {
|
ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.connect_timeout);
|
||||||
// printf("Not scheduling timer.. (tmo=%p)\n", ctx->c.timeout);
|
}
|
||||||
// if (ctx->c.timeout){
|
} else if (ctx->c.command_timeout && ctx->ev.scheduleTimer &&
|
||||||
// printf("tv_sec: %u. tv_usec: %u\n", ctx->c.timeout->tv_sec,
|
(ctx->c.command_timeout->tv_sec || ctx->c.command_timeout->tv_usec)) {
|
||||||
// ctx->c.timeout->tv_usec);
|
ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.command_timeout);
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ int main (int argc, char **argv) {
|
|||||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||||
struct timeval tv = {0};
|
struct timeval tv = {0};
|
||||||
tv.tv_sec = 1;
|
tv.tv_sec = 1;
|
||||||
options.timeout = &tv;
|
options.connect_timeout = &tv;
|
||||||
|
|
||||||
|
|
||||||
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
|
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
|
||||||
|
@ -33,7 +33,7 @@ int main(int argc, char **argv) {
|
|||||||
struct timeval tv = { 1, 500000 }; // 1.5 seconds
|
struct timeval tv = { 1, 500000 }; // 1.5 seconds
|
||||||
redisOptions options = {0};
|
redisOptions options = {0};
|
||||||
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
|
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
|
||||||
options.timeout = &tv;
|
options.connect_timeout = &tv;
|
||||||
c = redisConnectWithOptions(&options);
|
c = redisConnectWithOptions(&options);
|
||||||
|
|
||||||
if (c == NULL || c->err) {
|
if (c == NULL || c->err) {
|
||||||
|
38
hiredis.c
38
hiredis.c
@ -44,6 +44,9 @@
|
|||||||
#include "async.h"
|
#include "async.h"
|
||||||
#include "win32.h"
|
#include "win32.h"
|
||||||
|
|
||||||
|
extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout);
|
||||||
|
extern int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout);
|
||||||
|
|
||||||
static redisContextFuncs redisContextDefaultFuncs = {
|
static redisContextFuncs redisContextDefaultFuncs = {
|
||||||
.free_privdata = NULL,
|
.free_privdata = NULL,
|
||||||
.async_read = redisAsyncRead,
|
.async_read = redisAsyncRead,
|
||||||
@ -723,7 +726,8 @@ void redisFree(redisContext *c) {
|
|||||||
hi_free(c->tcp.host);
|
hi_free(c->tcp.host);
|
||||||
hi_free(c->tcp.source_addr);
|
hi_free(c->tcp.source_addr);
|
||||||
hi_free(c->unix_sock.path);
|
hi_free(c->unix_sock.path);
|
||||||
hi_free(c->timeout);
|
hi_free(c->connect_timeout);
|
||||||
|
hi_free(c->command_timeout);
|
||||||
hi_free(c->saddr);
|
hi_free(c->saddr);
|
||||||
if (c->funcs->free_privdata) {
|
if (c->funcs->free_privdata) {
|
||||||
c->funcs->free_privdata(c->privdata);
|
c->funcs->free_privdata(c->privdata);
|
||||||
@ -761,18 +765,24 @@ int redisReconnect(redisContext *c) {
|
|||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ret = REDIS_ERR;
|
||||||
if (c->connection_type == REDIS_CONN_TCP) {
|
if (c->connection_type == REDIS_CONN_TCP) {
|
||||||
return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
|
ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
|
||||||
c->timeout, c->tcp.source_addr);
|
c->connect_timeout, c->tcp.source_addr);
|
||||||
} else if (c->connection_type == REDIS_CONN_UNIX) {
|
} else if (c->connection_type == REDIS_CONN_UNIX) {
|
||||||
return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
|
ret = redisContextConnectUnix(c, c->unix_sock.path, c->connect_timeout);
|
||||||
} else {
|
} else {
|
||||||
/* Something bad happened here and shouldn't have. There isn't
|
/* Something bad happened here and shouldn't have. There isn't
|
||||||
enough information in the context to reconnect. */
|
enough information in the context to reconnect. */
|
||||||
__redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
|
__redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
|
||||||
|
ret = REDIS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return REDIS_ERR;
|
if (c->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
||||||
|
redisContextSetTimeout(c, *c->command_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
redisContext *redisConnectWithOptions(const redisOptions *options) {
|
redisContext *redisConnectWithOptions(const redisOptions *options) {
|
||||||
@ -790,13 +800,19 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
|
|||||||
c->flags |= REDIS_NO_AUTO_FREE;
|
c->flags |= REDIS_NO_AUTO_FREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (redisContextUpdateConnectTimeout(c, options->connect_timeout) != REDIS_OK ||
|
||||||
|
redisContextUpdateCommandTimeout(c, options->command_timeout) != REDIS_OK) {
|
||||||
|
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
if (options->type == REDIS_CONN_TCP) {
|
if (options->type == REDIS_CONN_TCP) {
|
||||||
redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
|
redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
|
||||||
options->endpoint.tcp.port, options->timeout,
|
options->endpoint.tcp.port, options->connect_timeout,
|
||||||
options->endpoint.tcp.source_addr);
|
options->endpoint.tcp.source_addr);
|
||||||
} else if (options->type == REDIS_CONN_UNIX) {
|
} else if (options->type == REDIS_CONN_UNIX) {
|
||||||
redisContextConnectUnix(c, options->endpoint.unix_socket,
|
redisContextConnectUnix(c, options->endpoint.unix_socket,
|
||||||
options->timeout);
|
options->connect_timeout);
|
||||||
} else if (options->type == REDIS_CONN_USERFD) {
|
} else if (options->type == REDIS_CONN_USERFD) {
|
||||||
c->fd = options->endpoint.fd;
|
c->fd = options->endpoint.fd;
|
||||||
c->flags |= REDIS_CONNECTED;
|
c->flags |= REDIS_CONNECTED;
|
||||||
@ -805,6 +821,10 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
||||||
|
redisContextSetTimeout(c, *options->command_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -820,7 +840,7 @@ redisContext *redisConnect(const char *ip, int port) {
|
|||||||
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
|
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
|
||||||
redisOptions options = {0};
|
redisOptions options = {0};
|
||||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||||
options.timeout = &tv;
|
options.connect_timeout = &tv;
|
||||||
return redisConnectWithOptions(&options);
|
return redisConnectWithOptions(&options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,7 +878,7 @@ redisContext *redisConnectUnix(const char *path) {
|
|||||||
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
|
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
|
||||||
redisOptions options = {0};
|
redisOptions options = {0};
|
||||||
REDIS_OPTIONS_SET_UNIX(&options, path);
|
REDIS_OPTIONS_SET_UNIX(&options, path);
|
||||||
options.timeout = &tv;
|
options.connect_timeout = &tv;
|
||||||
return redisConnectWithOptions(&options);
|
return redisConnectWithOptions(&options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,8 +176,10 @@ typedef struct {
|
|||||||
int type;
|
int type;
|
||||||
/* bit field of REDIS_OPT_xxx */
|
/* bit field of REDIS_OPT_xxx */
|
||||||
int options;
|
int options;
|
||||||
/* timeout value. if NULL, no timeout is used */
|
/* timeout value for connect operation. if NULL, no timeout is used */
|
||||||
const struct timeval *timeout;
|
const struct timeval *connect_timeout;
|
||||||
|
/* timeout value for commands. if NULL, no timeout is used. (can be set later on with redisSetTimeout/redisAsyncSetTimeout) */
|
||||||
|
const struct timeval *command_timeout;
|
||||||
union {
|
union {
|
||||||
/** use this field for tcp/ip connections */
|
/** use this field for tcp/ip connections */
|
||||||
struct {
|
struct {
|
||||||
@ -230,7 +232,8 @@ typedef struct redisContext {
|
|||||||
redisReader *reader; /* Protocol reader */
|
redisReader *reader; /* Protocol reader */
|
||||||
|
|
||||||
enum redisConnectionType connection_type;
|
enum redisConnectionType connection_type;
|
||||||
struct timeval *timeout;
|
struct timeval *connect_timeout;
|
||||||
|
struct timeval *command_timeout;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
char *host;
|
char *host;
|
||||||
|
42
net.c
42
net.c
@ -217,7 +217,7 @@ int redisSetTcpNoDelay(redisContext *c) {
|
|||||||
|
|
||||||
static int redisContextTimeoutMsec(redisContext *c, long *result)
|
static int redisContextTimeoutMsec(redisContext *c, long *result)
|
||||||
{
|
{
|
||||||
const struct timeval *timeout = c->timeout;
|
const struct timeval *timeout = c->connect_timeout;
|
||||||
long msec = -1;
|
long msec = -1;
|
||||||
|
|
||||||
/* Only use timeout when not NULL. */
|
/* Only use timeout when not NULL. */
|
||||||
@ -328,19 +328,35 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
|||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _redisContextUpdateTimeout(redisContext *c, const struct timeval *timeout) {
|
int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout) {
|
||||||
/* Same timeval struct, short circuit */
|
/* Same timeval struct, short circuit */
|
||||||
if (c->timeout == timeout)
|
if (c->connect_timeout == timeout)
|
||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
|
|
||||||
/* Allocate context timeval if we need to */
|
/* Allocate context timeval if we need to */
|
||||||
if (c->timeout == NULL) {
|
if (c->connect_timeout == NULL) {
|
||||||
c->timeout = hi_malloc(sizeof(*c->timeout));
|
c->connect_timeout = hi_malloc(sizeof(*c->connect_timeout));
|
||||||
if (c->timeout == NULL)
|
if (c->connect_timeout == NULL)
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(c->timeout, timeout, sizeof(*c->timeout));
|
memcpy(c->connect_timeout, timeout, sizeof(*c->connect_timeout));
|
||||||
|
return REDIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout) {
|
||||||
|
/* Same timeval struct, short circuit */
|
||||||
|
if (c->command_timeout == timeout)
|
||||||
|
return REDIS_OK;
|
||||||
|
|
||||||
|
/* Allocate context timeval if we need to */
|
||||||
|
if (c->command_timeout == NULL) {
|
||||||
|
c->command_timeout = hi_malloc(sizeof(*c->command_timeout));
|
||||||
|
if (c->command_timeout == NULL)
|
||||||
|
return REDIS_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(c->command_timeout, timeout, sizeof(*c->command_timeout));
|
||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,11 +392,11 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
if (_redisContextUpdateTimeout(c, timeout) == REDIS_ERR)
|
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
|
||||||
goto oom;
|
goto oom;
|
||||||
} else {
|
} else {
|
||||||
hi_free(c->timeout);
|
hi_free(c->connect_timeout);
|
||||||
c->timeout = NULL;
|
c->connect_timeout = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
|
if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
|
||||||
@ -549,11 +565,11 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
if (_redisContextUpdateTimeout(c, timeout) == REDIS_ERR)
|
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
|
||||||
goto oom;
|
goto oom;
|
||||||
} else {
|
} else {
|
||||||
hi_free(c->timeout);
|
hi_free(c->connect_timeout);
|
||||||
c->timeout = NULL;
|
c->connect_timeout = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
|
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
|
||||||
|
Loading…
Reference in New Issue
Block a user