Commit ae30d58f authored by Eddy Jansson's avatar Eddy Jansson Committed by Matt Stancliff
Browse files

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
parent 37d25a39
...@@ -1010,6 +1010,13 @@ void redisFree(redisContext *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) { ...@@ -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); ...@@ -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);
......
...@@ -14,7 +14,8 @@ ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment