void redisProcessCallbacks(redisAsyncContext *ac) { redisContext *c = &(ac->c); redisCallback cb; void *reply = NULL; int status; while((status = redisGetReply(c,&reply)) == REDIS_OK) { if (reply == NULL) { /* When the connection is being disconnected and there are * no more replies, this is the cue to really disconnect. */ if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) { __redisAsyncDisconnect(ac); return; } /* When the connection is not being disconnected, simply stop * trying to get replies and wait for the next loop tick. */ break; } /* Even if the context is subscribed, pending regular callbacks will * get a reply before pub/sub messages arrive. */ if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) { /* No more regular callbacks, the context *must* be subscribed. */ /* assert(c->flags & REDIS_SUBSCRIBED); */ if (c->flags & REDIS_SUBSCRIBED) { __redisGetSubscribeCallback(ac,reply,&cb); } /* lig: monitor callback */ if (c->flags & REDIS_MONITOR) { __redisGetMonitorCallback(ac,&cb); } } if (cb.fn != NULL) { __redisRunCallback(ac,&cb,reply); c->fn->freeObject(reply); /* Proceed with free'ing when redisAsyncFree() was called. */ if (c->flags & REDIS_FREEING) { __redisAsyncFree(ac); return; } } else { /* No callback for this reply. This can either be a NULL callback, * or there were no callbacks to begin with. Either way, don't * abort with an error, but simply ignore it because the client * doesn't know what the server will spit out over the wire. */ c->fn->freeObject(reply); } } /* Disconnect when there was an error reading the reply */ if (status != REDIS_OK) __redisAsyncDisconnect(ac); }
/* Helper function to make the disconnect happen and clean up. */ static void __redisAsyncDisconnect(redisAsyncContext *ac) { redisContext *c = &(ac->c); /* Make sure error is accessible if there is any */ __redisAsyncCopyError(ac); if (ac->err == 0) { /* For clean disconnects, there should be no pending callbacks. */ assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR); } else { /* Disconnection is caused by an error, make sure that pending * callbacks cannot call new commands. */ c->flags |= REDIS_DISCONNECTING; } /* For non-clean disconnects, __redisAsyncFree() will execute pending * callbacks with a NULL-reply. */ __redisAsyncFree(ac); }
void redisProcessCallbacks(redisAsyncContext *ac) { redisContext *c = &(ac->c); redisCallback cb; void *reply = NULL; int status; while((status = redisGetReply(c,&reply)) == REDIS_OK) { // 回复内容为空 if (reply == NULL) { // REDIS_DISCONNECTING 表示连接断开的时候遇到了错误,如果此时 // 写缓冲区为空,会再次尝试断开。之后的回调函数都得不到执行 // 的机会 /* When the connection is being disconnected and there are * no more replies, this is the cue to really disconnect. */ if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) { __redisAsyncDisconnect(ac); return; } // 监视模式下 /* If monitor mode, repush callback */ if(c->flags & REDIS_MONITORING) { __redisPushCallback(&ac->replies,&cb); } /* When the connection is not being disconnected, simply stop * trying to get replies and wait for the next loop tick. */ break; } /* Even if the context is subscribed, pending regular callbacks will * get a reply before pub/sub messages arrive. */ // 获取回调函数 redisCallback if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) { /* * A spontaneous reply in a not-subscribed context can be the error * reply that is sent when a new connection exceeds the maximum * number of allowed connections on the server side. * * This is seen as an error instead of a regular reply because the * server closes the connection after sending it. * * To prevent the error from being overwritten by an EOF error the * connection is closed here. See issue #43. * * Another possibility is that the server is loading its dataset. * In this case we also want to close the connection, and have the * user wait until the server is ready to take our request. */ if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) { c->err = REDIS_ERR_OTHER; snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str); __redisAsyncDisconnect(ac); return; } /* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */ assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING)); if(c->flags & REDIS_SUBSCRIBED) __redisGetSubscribeCallback(ac,reply,&cb); } // 执行回调函数 if (cb.fn != NULL) { __redisRunCallback(ac,&cb,reply); c->reader->fn->freeObject(reply); // 可能是之前遇到了不可修复的错误,被标记了 REDIS_FREEING。 // 倘若是在 callback 里面遇到的错误,redis 不能立即释放连接, // 因为可能需要返回一些数据给客户端。因此 redis 选择在 callback // 执行过后,才释放(关闭)连接。这个方法好酷。 /* Proceed with free'ing when redisAsyncFree() was called. */ if (c->flags & REDIS_FREEING) { __redisAsyncFree(ac); return; } // 没有设置回调函数,直接释放收到的数据 } else { /* No callback for this reply. This can either be a NULL callback, * or there were no callbacks to begin with. Either way, don't * abort with an error, but simply ignore it because the client * doesn't know what the server will spit out over the wire. */ c->reader->fn->freeObject(reply); } } // 出错了,则直接关闭 /* Disconnect when there was an error reading the reply */ if (status != REDIS_OK) __redisAsyncDisconnect(ac); }
/* Free the async context. When this function is called from a callback, * control needs to be returned to redisProcessCallbacks() before actual * free'ing. To do so, a flag is set on the context which is picked up by * redisProcessCallbacks(). Otherwise, the context is immediately free'd. */ void redisAsyncFree(redisAsyncContext *ac) { redisContext *c = &(ac->c); c->flags |= REDIS_FREEING; if (!(c->flags & REDIS_IN_CALLBACK)) __redisAsyncFree(ac); }
void redisProcessCallbacks(redisAsyncContext *ac) { redisContext *c = &(ac->c); redisCallback cb; void *reply = NULL; int status; while((status = redisGetReply(c,&reply)) == REDIS_OK) { if (reply == NULL) { /* When the connection is being disconnected and there are * no more replies, this is the cue to really disconnect. */ if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) { __redisAsyncDisconnect(ac); return; } /* When the connection is not being disconnected, simply stop * trying to get replies and wait for the next loop tick. */ break; } /* Even if the context is subscribed, pending regular callbacks will * get a reply before pub/sub messages arrive. */ if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) { /* A spontaneous reply in a not-subscribed context can only be the * error reply that is sent when a new connection exceeds the * maximum number of allowed connections on the server side. This * is seen as an error instead of a regular reply because the * server closes the connection after sending it. To prevent the * error from being overwritten by an EOF error the connection is * closed here. See issue #43. */ if ( !(c->flags & REDIS_SUBSCRIBED) && ((redisReply*)reply)->type == REDIS_REPLY_ERROR ) { c->err = REDIS_ERR_OTHER; snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str); __redisAsyncDisconnect(ac); return; } /* No more regular callbacks and no errors, the context *must* be subscribed. */ assert(c->flags & REDIS_SUBSCRIBED); __redisGetSubscribeCallback(ac,reply,&cb); } if (cb.fn != NULL) { __redisRunCallback(ac,&cb,reply); c->reader->fn->freeObject(reply); /* Proceed with free'ing when redisAsyncFree() was called. */ if (c->flags & REDIS_FREEING) { __redisAsyncFree(ac); return; } } else { /* No callback for this reply. This can either be a NULL callback, * or there were no callbacks to begin with. Either way, don't * abort with an error, but simply ignore it because the client * doesn't know what the server will spit out over the wire. */ c->reader->fn->freeObject(reply); } } /* Disconnect when there was an error reading the reply */ if (status != REDIS_OK) __redisAsyncDisconnect(ac); }