【Redis源碼】Redis命令執行過(guò)程

簡(jiǎn)介
需要了解Redis命令執行過(guò)程,請先了解Redis啟動(dòng)過(guò)程和Redis事件監聽(tīng)。
在Redis事件監聽(tīng)中我們了解到在創(chuàng )建文件監聽(tīng)事件的時(shí)候 acceptTcpHandler就是的執行函數。具體實(shí)現如下:
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.");
}
}
總體處理流程

創(chuàng )建連接
當有命令執行的時(shí)候,acceptTcpHandler函數中會(huì )調用acceptCommonHandler函數。acceptCommonHandler函數會(huì )判斷已經(jīng)連接的客戶(hù)端時(shí)候已經(jīng)超過(guò)10000(maxclients配置的值,默認為10000)。
創(chuàng )建Redis連接。代碼如下:
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用于接受已經(jīng)創(chuàng )建好的連接的命令。最后處理命令的函數為processCommand,執行命令:
int processCommand(client *c) {
moduleCallCommandFilters(c);
/* 優(yōu)先處理退出命令 */
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;
}
/* 是否已經(jīng)認證 */
int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
(DefaultUser->flags & USER_FLAG_DISABLED)) &&
!c->authenticated;
if (auth_required) {
/* 沒(méi)有認證返回*/
if (!(c->cmd->flags & CMD_NO_AUTH)) {
flagTransaction(c);
addReply(c,shared.noautherr);
return C_OK;
}
}
/* 檢查是否已經(jīng)超過(guò)最大內存*/
if (server.maxmemory && !server.lua_timedout) {
// return 錯誤;
}
// 進(jìn)行其他檢查項
/* 執行命令 */
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 {
// 調用命令表里面嗎對應命令的實(shí)現函數。
call(c,CMD_CALL_FULL);
c->woff = server.master_repl_offset;
if (listLength(server.ready_keys))
handleClientsBlockedOnKeys();
}
return C_OK;
}
命令表詳見(jiàn):《Redis 啟動(dòng)過(guò)程分析》中,初始化命令表部分。
至此,命令處理的整個(gè)過(guò)程完成。
評論
0 評論