Add redisConnectFd() and redisFreeKeepFd()
These allows for easier integration of hiredis with external code that wants to manage its fds, say for instance in a pool. Closes #223
This commit is contained in:
parent
37d25a392c
commit
ae30d58ff9
19
hiredis.c
19
hiredis.c
@ -1010,6 +1010,13 @@ void redisFree(redisContext *c) {
|
|||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int redisFreeKeepFd(redisContext *c) {
|
||||||
|
int fd = c->fd;
|
||||||
|
c->fd = -1;
|
||||||
|
redisFree(c);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect to a Redis instance. On error the field error in the returned
|
/* Connect to a Redis instance. On error the field error in the returned
|
||||||
* context will be set to the return value of the error function.
|
* context will be set to the return value of the error function.
|
||||||
* When no set of reply functions is given, the default set will be used. */
|
* When no set of reply functions is given, the default set will be used. */
|
||||||
@ -1093,6 +1100,18 @@ redisContext *redisConnectUnixNonBlock(const char *path) {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redisContext *redisConnectFd(int fd) {
|
||||||
|
redisContext *c;
|
||||||
|
|
||||||
|
c = redisContextInit();
|
||||||
|
if (c == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
c->fd = fd;
|
||||||
|
c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set read/write timeout on a blocking socket. */
|
/* Set read/write timeout on a blocking socket. */
|
||||||
int redisSetTimeout(redisContext *c, const struct timeval tv) {
|
int redisSetTimeout(redisContext *c, const struct timeval tv) {
|
||||||
if (c->flags & REDIS_BLOCK)
|
if (c->flags & REDIS_BLOCK)
|
||||||
|
@ -179,9 +179,11 @@ redisContext *redisConnectBindNonBlock(const char *ip, int port, char *source);
|
|||||||
redisContext *redisConnectUnix(const char *path);
|
redisContext *redisConnectUnix(const char *path);
|
||||||
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
||||||
redisContext *redisConnectUnixNonBlock(const char *path);
|
redisContext *redisConnectUnixNonBlock(const char *path);
|
||||||
|
redisContext *redisConnectFd(int fd);
|
||||||
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
||||||
int redisEnableKeepAlive(redisContext *c);
|
int redisEnableKeepAlive(redisContext *c);
|
||||||
void redisFree(redisContext *c);
|
void redisFree(redisContext *c);
|
||||||
|
int redisFreeKeepFd(redisContext *c);
|
||||||
int redisBufferRead(redisContext *c);
|
int redisBufferRead(redisContext *c);
|
||||||
int redisBufferWrite(redisContext *c, int *done);
|
int redisBufferWrite(redisContext *c, int *done);
|
||||||
|
|
||||||
|
31
test.c
31
test.c
@ -14,7 +14,8 @@
|
|||||||
|
|
||||||
enum connection_type {
|
enum connection_type {
|
||||||
CONN_TCP,
|
CONN_TCP,
|
||||||
CONN_UNIX
|
CONN_UNIX,
|
||||||
|
CONN_FD
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
@ -64,7 +65,7 @@ static redisContext *select_database(redisContext *c) {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disconnect(redisContext *c) {
|
static int disconnect(redisContext *c, int keep_fd) {
|
||||||
redisReply *reply;
|
redisReply *reply;
|
||||||
|
|
||||||
/* Make sure we're on DB 9. */
|
/* Make sure we're on DB 9. */
|
||||||
@ -75,8 +76,11 @@ static void disconnect(redisContext *c) {
|
|||||||
assert(reply != NULL);
|
assert(reply != NULL);
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply);
|
||||||
|
|
||||||
/* Free the context as well. */
|
/* Free the context as well, but keep the fd if requested. */
|
||||||
|
if (keep_fd)
|
||||||
|
return redisFreeKeepFd(c);
|
||||||
redisFree(c);
|
redisFree(c);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static redisContext *connect(struct config config) {
|
static redisContext *connect(struct config config) {
|
||||||
@ -86,6 +90,14 @@ static redisContext *connect(struct config config) {
|
|||||||
c = redisConnect(config.tcp.host, config.tcp.port);
|
c = redisConnect(config.tcp.host, config.tcp.port);
|
||||||
} else if (config.type == CONN_UNIX) {
|
} else if (config.type == CONN_UNIX) {
|
||||||
c = redisConnectUnix(config.unix.path);
|
c = redisConnectUnix(config.unix.path);
|
||||||
|
} else if (config.type == CONN_FD) {
|
||||||
|
/* Create a dummy connection just to get an fd to inherit */
|
||||||
|
redisContext *dummy_ctx = redisConnectUnix(config.unix.path);
|
||||||
|
if (dummy_ctx) {
|
||||||
|
int fd = disconnect(dummy_ctx, 1);
|
||||||
|
printf("Connecting to inherited fd %d\n", fd);
|
||||||
|
c = redisConnectFd(fd);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(NULL);
|
assert(NULL);
|
||||||
}
|
}
|
||||||
@ -383,7 +395,7 @@ static void test_blocking_connection(struct config config) {
|
|||||||
strcasecmp(reply->element[1]->str,"pong") == 0);
|
strcasecmp(reply->element[1]->str,"pong") == 0);
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply);
|
||||||
|
|
||||||
disconnect(c);
|
disconnect(c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_blocking_io_errors(struct config config) {
|
static void test_blocking_io_errors(struct config config) {
|
||||||
@ -523,7 +535,7 @@ static void test_throughput(struct config config) {
|
|||||||
free(replies);
|
free(replies);
|
||||||
printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||||
|
|
||||||
disconnect(c);
|
disconnect(c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static long __test_callback_flags = 0;
|
// static long __test_callback_flags = 0;
|
||||||
@ -636,6 +648,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
int throughput = 1;
|
int throughput = 1;
|
||||||
|
int test_inherit_fd = 1;
|
||||||
|
|
||||||
/* Ignore broken pipe signal (for I/O error tests). */
|
/* Ignore broken pipe signal (for I/O error tests). */
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
@ -654,6 +667,8 @@ int main(int argc, char **argv) {
|
|||||||
cfg.unix.path = argv[0];
|
cfg.unix.path = argv[0];
|
||||||
} else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) {
|
} else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) {
|
||||||
throughput = 0;
|
throughput = 0;
|
||||||
|
} else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) {
|
||||||
|
test_inherit_fd = 0;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid argument: %s\n", argv[0]);
|
fprintf(stderr, "Invalid argument: %s\n", argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -678,6 +693,12 @@ int main(int argc, char **argv) {
|
|||||||
test_blocking_io_errors(cfg);
|
test_blocking_io_errors(cfg);
|
||||||
if (throughput) test_throughput(cfg);
|
if (throughput) test_throughput(cfg);
|
||||||
|
|
||||||
|
if (test_inherit_fd) {
|
||||||
|
printf("\nTesting against inherited fd (%s):\n", cfg.unix.path);
|
||||||
|
cfg.type = CONN_FD;
|
||||||
|
test_blocking_connection(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
if (fails) {
|
if (fails) {
|
||||||
printf("*** %d TESTS FAILED ***\n", fails);
|
printf("*** %d TESTS FAILED ***\n", fails);
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user