简介
需要了解Redis命令执行过程,请先了解Redis启动过程和Redis事件监听。
Redis启动过程分析 Redis事件监听
在Redis事件监听中我们了解到在创建文件监听事件的时候 acceptTcpHandler
就是的执行函数。具体实现如下:
for (j = 0; j < server.ipfd_count; j ) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler,NULL) == AE_ERR){
erverPanic("Unrecoverable error creating server.ipfd file event.");
}
}
总体处理流程
创建连接
当有命令执行的时候,acceptTcpHandler函数中会调用acceptCommonHandler函数。acceptCommonHandler函数会判断已经连接的客户端时候已经超过10000(maxclients配置的值,默认为10000)。
创建Redis连接。代码如下:
代码语言:javascript复制if ((c = createClient(conn)) == NULL) {
char conninfo[100];
serverLog(LL_WARNING,
"Error registering fd event for the new client: %s (conn: %s)",
connGetLastError(conn),
connGetInfo(conn, conninfo, sizeof(conninfo)));
connClose(conn); /* May be already closed, just ignore errors */
return;
}
接受命令
函数readQueryFromClient用于接受已经创建好的连接的命令。最后处理命令的函数为processCommand,执行命令:
代码语言:javascript复制int processCommand(client *c) {
moduleCallCommandFilters(c);
/* 优先处理退出命令 */
if (!strcasecmp(c->argv[0]->ptr,"quit")) {
addReply(c,shared.ok);
c->flags |= CLIENT_CLOSE_AFTER_REPLY;
return C_ERR;
}
/* 在命令表里面查找命令*/
c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr);
if (!c->cmd) {
// 找不到命令
return C_OK;
} else if ((c->cmd->arity > 0 && c->cmd->arity != c->argc) ||
(c->argc < -c->cmd->arity)) {
// 命令参数不对
return C_OK;
}
/* 是否已经认证 */
int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
(DefaultUser->flags & USER_FLAG_DISABLED)) &&
!c->authenticated;
if (auth_required) {
/* 没有认证返回*/
if (!(c->cmd->flags & CMD_NO_AUTH)) {
flagTransaction(c);
addReply(c,shared.noautherr);
return C_OK;
}
}
/* 检查是否已经超过最大内存*/
if (server.maxmemory && !server.lua_timedout) {
// return 错误;
}
// 进行其他检查项
/* 执行命令 */
if (c->flags & CLIENT_MULTI &&
c->cmd->proc != execCommand && c->cmd->proc != discardCommand &&
c->cmd->proc != multiCommand && c->cmd->proc != watchCommand)
{
queueMultiCommand(c);
addReply(c,shared.queued);
} else {
// 调用命令表里面吗对应命令的实现函数。
call(c,CMD_CALL_FULL);
c->woff = server.master_repl_offset;
if (listLength(server.ready_keys))
handleClientsBlockedOnKeys();
}
return C_OK;
}
命令表详见:《Redis 启动过程分析》中,初始化命令表部分。
至此,命令处理的整个过程完成。