Run pending callbacks with a NULL reply on redisAsyncFree()

This commit is contained in:
Pieter Noordhuis 2010-12-28 20:49:18 +01:00
parent 29ea901b24
commit 8cb4d52cd2

49
async.c
View File

@ -154,16 +154,29 @@ static int __redisShiftCallback(redisCallbackList *list, redisCallback *target)
/* Helper function to free the context. */ /* Helper function to free the context. */
static void __redisAsyncFree(redisAsyncContext *ac) { static void __redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c); redisContext *c = &(ac->c);
redisCallback cb;
/* Clear callback list */ /* Execute pending callbacks with NULL reply. */
while (__redisShiftCallback(&ac->replies,NULL) == REDIS_OK); while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) {
if (cb.fn != NULL) {
c->flags |= REDIS_IN_CALLBACK;
cb.fn(ac,NULL,cb.privdata);
c->flags &= ~REDIS_IN_CALLBACK;
}
}
/* Signal event lib to clean up */ /* Signal event lib to clean up */
if (ac->evCleanup) ac->evCleanup(ac->_adapter_data); if (ac->evCleanup) ac->evCleanup(ac->_adapter_data);
/* Execute callback with proper status */ /* Execute disconnect callback. When redisAsyncFree() initiated destroying
if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) * this context, the status will always be REDIS_OK. */
ac->onDisconnect(ac, (ac->err == 0) ? REDIS_OK : REDIS_ERR); if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
if (c->flags & REDIS_FREEING) {
ac->onDisconnect(ac,REDIS_OK);
} else {
ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
}
}
/* Cleanup self */ /* Cleanup self */
redisFree(c); redisFree(c);
@ -175,39 +188,29 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
* redisProcessCallbacks(). Otherwise, the context is immediately free'd. */ * redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
void redisAsyncFree(redisAsyncContext *ac) { void redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c); redisContext *c = &(ac->c);
if (c->flags & REDIS_IN_CALLBACK) {
c->flags |= REDIS_FREEING; c->flags |= REDIS_FREEING;
} else { if (!(c->flags & REDIS_IN_CALLBACK))
__redisAsyncFree(ac); __redisAsyncFree(ac);
}
} }
/* Helper function to make the disconnect happen and clean up. */ /* Helper function to make the disconnect happen and clean up. */
static void __redisAsyncDisconnect(redisAsyncContext *ac) { static void __redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c); redisContext *c = &(ac->c);
redisCallback cb;
/* Make sure error is accessible if there is any */ /* Make sure error is accessible if there is any */
__redisAsyncCopyError(ac); __redisAsyncCopyError(ac);
if (ac->err == 0) { if (ac->err == 0) {
/* When the connection is cleanly disconnected, there should not /* For clean disconnects, there should be no pending callbacks. */
* be pending callbacks. */
assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR); assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
} else { } else {
/* Callbacks should not be able to issue new commands. */ /* Disconnection is caused by an error, make sure that pending
* callbacks cannot call new commands. */
c->flags |= REDIS_DISCONNECTING; c->flags |= REDIS_DISCONNECTING;
/* Execute pending callbacks with NULL reply. */
while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) {
if (cb.fn != NULL) {
c->flags |= REDIS_IN_CALLBACK;
cb.fn(ac,NULL,cb.privdata);
c->flags &= ~REDIS_IN_CALLBACK;
}
}
} }
/* For non-clean disconnects, __redisAsyncFree() will execute pending
* callbacks with a NULL-reply. */
__redisAsyncFree(ac); __redisAsyncFree(ac);
} }
@ -219,11 +222,9 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
* when there are no pending callbacks. */ * when there are no pending callbacks. */
void redisAsyncDisconnect(redisAsyncContext *ac) { void redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c); redisContext *c = &(ac->c);
if (c->flags & REDIS_IN_CALLBACK || ac->replies.head != NULL) {
c->flags |= REDIS_DISCONNECTING; c->flags |= REDIS_DISCONNECTING;
} else { if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
__redisAsyncDisconnect(ac); __redisAsyncDisconnect(ac);
}
} }
void redisProcessCallbacks(redisAsyncContext *ac) { void redisProcessCallbacks(redisAsyncContext *ac) {