与客户端的连接的回调函数是:readQueryFromClient,读取完数据后调用processInputBuffere,此函数中,先解析出命令,在处理命令;
一.从数据流中解析出命令
readQueryFromClient中读取数据后,调用processInputBuffere;
if (c->reqtype == REDIS_REQ_INLINE) {
if (processInlineBuffer(c) != REDIS_OK) break;
} else if (c->reqtype == REDIS_REQ_MULTIBULK) {
if (processMultibulkBuffer(c) != REDIS_OK) break;
} else {
redisPanic("Unknown request type");
}
REDIS_REQ_INLINE命令类型:
整个命令以 /r/n结尾, 命令的字段以空格间隔, 字段可以包含引号
如:
set aaa bbb\r\n
set "m n" ccc\r\n
REDIS_REQ_MULTIBULK命令类型:
set aaa bbb命令表示如下,
*3\r\n
$3\r\n
set\r\n
$3
aaa\r\n
$3
bbb\r\n
其中,*3表示命令set aaa bbb
一共有三个字段,$3表示当前字段的长度为3:
processInlineBuffer或者processMultibulkBuffer执行后,
参数个数保留在c->argc中,所有参数以redisObject结构保存在数组c->argv中;
二.处理命令
processInputBuffere中解析出命令后,调用processCommand处理保存在c->argc,c->argv
中的命令;
/* Multibulk processing could see a <= 0 length. */
if (c->argc == 0) {
resetClient(c);
} else {
/* Only reset the client when the command was executed. */
if (processCommand(c) == REDIS_OK)
resetClient(c);
}
}
如果是集群模式,processCommand中会判断,所有的key是否都在当前节点,如果不是,返回重定向命令;
/* If cluster is enabled perform the cluster redirection here.
* However we don't perform the redirection if:
* 1) The sender of this command is our master.
* 2) The command has no key arguments. */
if (server.cluster_enabled &&
!(c->flags & REDIS_MASTER) &&
!(c->flags & REDIS_LUA_CLIENT &&
server.lua_caller->flags & REDIS_MASTER) &&
!(c->cmd->getkeys_proc == NULL && c->cmd->firstkey == 0))
{
int hashslot;
if (server.cluster->state != REDIS_CLUSTER_OK) {
flagTransaction(c);
clusterRedirectClient(c,NULL,0,REDIS_CLUSTER_REDIR_DOWN_STATE);
return REDIS_OK;
} else {
int error_code;
clusterNode *n = getNodeByQuery(c,c->cmd,c->argv,c->argc,&hashslot,&error_code);
if (n == NULL || n != server.cluster->myself) {
flagTransaction(c);
clusterRedirectClient(c,n,hashslot,error_code);
return REDIS_OK;
}
}
}
命令执行:当前客户端如果在执行事务,而且当前命令不是事务中的multi,exe,watch,discard命令,则把命令缓存起来;否则,调用call(c,REDIS_CALL_FULL);执行当前命令;参考redis的设计与实现.事务.
/* Exec the command */
if (c->flags & REDIS_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,REDIS_CALL_FULL);
c->woff = server.master_repl_offset;
if (listLength(server.ready_keys))
handleClientsBlockedOnLists();
}