Maintain backward compatibiliy withour onConnect callback.
In f69fac7690
, our async onConnect
callback was improved to take a non-const redisAsyncContext allowing it
to be reentrant.
Unfortunately, this is a breaking change we can't make until hiredis
v2.0.0.
This commit creates a separate callback member and corresponding
function that allows us to use the new functionality, while maintaining
our existing API for legacy code.
Fixes #1086
master
parent
e7afd998f9
commit
6a3e96ad21
|
@ -372,6 +372,8 @@ the disconnect callback is a good point to do so.
|
|||
Setting the connect or disconnect callbacks can only be done once per context. For subsequent calls the
|
||||
api will return `REDIS_ERR`. The function to set the callbacks have the following prototype:
|
||||
```c
|
||||
/* Alternatively you can use redisAsyncSetConnectCallbackNC which will be passed a non-const
|
||||
redisAsyncContext* on invocation (e.g. allowing writes to the privdata member). */
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
```
|
||||
|
|
55
async.c
55
async.c
|
@ -140,6 +140,7 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
|
|||
ac->ev.scheduleTimer = NULL;
|
||||
|
||||
ac->onConnect = NULL;
|
||||
ac->onConnectNC = NULL;
|
||||
ac->onDisconnect = NULL;
|
||||
|
||||
ac->replies.head = NULL;
|
||||
|
@ -226,17 +227,34 @@ redisAsyncContext *redisAsyncConnectUnix(const char *path) {
|
|||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
|
||||
if (ac->onConnect == NULL) {
|
||||
ac->onConnect = fn;
|
||||
static int
|
||||
redisAsyncSetConnectCallbackImpl(redisAsyncContext *ac, redisConnectCallback *fn,
|
||||
redisConnectCallbackNC *fn_nc)
|
||||
{
|
||||
/* If either are already set, this is an error */
|
||||
if (ac->onConnect || ac->onConnectNC)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* The common way to detect an established connection is to wait for
|
||||
* the first write event to be fired. This assumes the related event
|
||||
* library functions are already set. */
|
||||
_EL_ADD_WRITE(ac);
|
||||
return REDIS_OK;
|
||||
if (fn) {
|
||||
ac->onConnect = fn;
|
||||
} else if (fn_nc) {
|
||||
ac->onConnectNC = fn_nc;
|
||||
}
|
||||
return REDIS_ERR;
|
||||
|
||||
/* The common way to detect an established connection is to wait for
|
||||
* the first write event to be fired. This assumes the related event
|
||||
* library functions are already set. */
|
||||
_EL_ADD_WRITE(ac);
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
|
||||
return redisAsyncSetConnectCallbackImpl(ac, fn, NULL);
|
||||
}
|
||||
|
||||
int redisAsyncSetConnectCallbackNC(redisAsyncContext *ac, redisConnectCallbackNC *fn) {
|
||||
return redisAsyncSetConnectCallbackImpl(ac, NULL, fn);
|
||||
}
|
||||
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) {
|
||||
|
@ -305,14 +323,23 @@ static void __redisRunPushCallback(redisAsyncContext *ac, redisReply *reply) {
|
|||
|
||||
static void __redisRunConnectCallback(redisAsyncContext *ac, int status)
|
||||
{
|
||||
if (ac->onConnect) {
|
||||
if (!(ac->c.flags & REDIS_IN_CALLBACK)) {
|
||||
ac->c.flags |= REDIS_IN_CALLBACK;
|
||||
if (ac->onConnect == NULL && ac->onConnectNC == NULL)
|
||||
return;
|
||||
|
||||
if (!(ac->c.flags & REDIS_IN_CALLBACK)) {
|
||||
ac->c.flags |= REDIS_IN_CALLBACK;
|
||||
if (ac->onConnect) {
|
||||
ac->onConnect(ac, status);
|
||||
ac->c.flags &= ~REDIS_IN_CALLBACK;
|
||||
} else {
|
||||
/* already in callback */
|
||||
ac->onConnectNC(ac, status);
|
||||
}
|
||||
ac->c.flags &= ~REDIS_IN_CALLBACK;
|
||||
} else {
|
||||
/* already in callback */
|
||||
if (ac->onConnect) {
|
||||
ac->onConnect(ac, status);
|
||||
} else {
|
||||
ac->onConnectNC(ac, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
5
async.h
5
async.h
|
@ -57,7 +57,8 @@ typedef struct redisCallbackList {
|
|||
|
||||
/* Connection callback prototypes */
|
||||
typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void (redisConnectCallback)(struct redisAsyncContext*, int status);
|
||||
typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void (redisConnectCallbackNC)(struct redisAsyncContext *, int status);
|
||||
typedef void(redisTimerCallback)(void *timer, void *privdata);
|
||||
|
||||
/* Context for an async connection to Redis */
|
||||
|
@ -93,6 +94,7 @@ typedef struct redisAsyncContext {
|
|||
|
||||
/* Called when the first write event was received. */
|
||||
redisConnectCallback *onConnect;
|
||||
redisConnectCallbackNC *onConnectNC;
|
||||
|
||||
/* Regular command callbacks */
|
||||
redisCallbackList replies;
|
||||
|
@ -121,6 +123,7 @@ redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
|||
const char *source_addr);
|
||||
redisAsyncContext *redisAsyncConnectUnix(const char *path);
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
||||
int redisAsyncSetConnectCallbackNC(redisAsyncContext *ac, redisConnectCallbackNC *fn);
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
|
||||
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn);
|
||||
|
|
8
test.c
8
test.c
|
@ -2008,7 +2008,7 @@ static redisAsyncContext *do_aconnect(struct config config, astest_no testno)
|
|||
{
|
||||
redisOptions options = {0};
|
||||
memset(&astest, 0, sizeof(astest));
|
||||
|
||||
|
||||
astest.testno = testno;
|
||||
astest.connect_status = astest.disconnect_status = -2;
|
||||
|
||||
|
@ -2039,7 +2039,7 @@ static redisAsyncContext *do_aconnect(struct config config, astest_no testno)
|
|||
c->data = &astest;
|
||||
c->dataCleanup = asCleanup;
|
||||
redisPollAttach(c);
|
||||
redisAsyncSetConnectCallback(c, connectCallback);
|
||||
redisAsyncSetConnectCallbackNC(c, connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c, disconnectCallback);
|
||||
return c;
|
||||
}
|
||||
|
@ -2058,7 +2058,7 @@ static void test_async_polling(struct config config) {
|
|||
int status;
|
||||
redisAsyncContext *c;
|
||||
struct config defaultconfig = config;
|
||||
|
||||
|
||||
test("Async connect: ");
|
||||
c = do_aconnect(config, ASTEST_CONNECT);
|
||||
assert(c);
|
||||
|
@ -2095,7 +2095,7 @@ static void test_async_polling(struct config config) {
|
|||
test_cond(astest.connect_status == REDIS_ERR);
|
||||
config = defaultconfig;
|
||||
}
|
||||
|
||||
|
||||
/* Test a ping/pong after connection */
|
||||
test("Async PING/PONG: ");
|
||||
c = do_aconnect(config, ASTEST_PINGPONG);
|
||||
|
|
Loading…
Reference in New Issue