clientCron函数针对client的操作主要由以下几点:
(1)如果客户端没有在阻塞调用状态,比如说BLPOP操作等,如果客户端上次请求server的时间与server端现在时间差超过server.maxidletime,直接关闭客户端,删除和此客户端相关的任何数据,表示此客户端已经被异常关闭,或者长时间没有进行操作。
(2)如果客户端处在阻塞请求状态,并且阻塞请求的超时时间已到,回复客户端已经超时,并且从阻塞key的hash表中删除此客户端,如果此客户端还调用了BRPOPLPUSH,那么需要清除此客户端的操作的key的目得key的指针。
(3)调整此客户端的querybuf,以节省内存。
(4) 设置此客户端的flag。并将此客户端放入到unblocked_clients中。
void clientsCron(void) {
/* Make sure to process at least 1/(server.hz*10) of clients per call.
* Since this function is called server.hz times per second we are sure that
* in the worst case we process all the clients in 10 seconds.
* In normal conditions (a reasonable number of clients) we process
* all the clients in a shorter time. */
int numclients = listLength(server.clients);
int iterations = numclients/(server.hz*10);
if (iterations < 50)
iterations = (numclients < 50) ? numclients : 50;
while(listLength(server.clients) && iterations--) {
redisClient *c;
listNode *head;
/* Rotate the list, take the current head, process.
* This way if the client must be removed from the list it's the
* first element and we don't incur into O(N) computation. */
listRotate(server.clients);
head = listFirst(server.clients);
c = listNodeValue(head);
/* The following functions do different service checks on the client.
* The protocol is that they return non-zero if the client was
* terminated. */
**//处理上面提到的(1)(3)(4)**
if (clientsCronHandleTimeout(c)) continue;
//**如果客户端没有满足(1)中条件,那么调整此客户端的querybuf,以节省内存。**
if (clientsCronResizeQueryBuffer(c)) continue;
}
}
执行(1)(2)情况:
/* Check for timeouts. Returns non-zero if the client was terminated */
int clientsCronHandleTimeout(redisClient *c) {
time_t now = server.unixtime;
if (server.maxidletime &&
!(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
!(c->flags & REDIS_MASTER) && /* no timeout for masters */
!(c->flags & REDIS_BLOCKED) && /* no timeout for BLPOP */
dictSize(c->pubsub_channels) == 0 && /* no timeout for pubsub */
listLength(c->pubsub_patterns) == 0 &&
(now - c->lastinteraction > server.maxidletime))
{
//处理(1)情况
redisLog(REDIS_VERBOSE,"Closing idle client");
freeClient(c);
return 1;
//处理(2)情况
} else if (c->flags & REDIS_BLOCKED) {
if (c->bpop.timeout != 0 && c->bpop.timeout < now) {
addReply(c,shared.nullmultibulk);
unblockClientWaitingData(c);
}
}
return 0;
}