【Redis源码】Redis命令执行过程

2022-08-26 19:31:35 浏览数 (1)

简介

需要了解Redis命令执行过程,请先了解Redis启动过程和Redis事件监听。

Redis启动过程分析 Redis事件监听

在Redis事件监听中我们了解到在创建文件监听事件的时候 acceptTcpHandler就是的执行函数。具体实现如下:

代码语言:javascript复制
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 启动过程分析》中,初始化命令表部分。

至此,命令处理的整个过程完成。

0 人点赞