您的位置:首页 > 数据库 > Redis

Redis源码分析系列十六:processCommand研究

2013-10-24 00:00 267 查看
现在让我们回到processInputBuffer函数。

剩下的代码是:

/* 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);
}

假设我们已经取到了一些命令,那么c->argc则大于0

那就会执行processCommand函数。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/* The QUIT command is handled separately. Normal command procs will
* go through checking for replication and QUIT will cause trouble
* when FORCE_REPLICATION is enabled and would be implemented in
* a regular command proc. */
//解释说明

if (!strcasecmp(c->argv[0]->ptr,"quit"))
{
addReply(c,shared.ok);
c->flags |= REDIS_CLOSE_AFTER_REPLY;
return REDIS_ERR;
}
//quit命令暂且不看,后面再解释。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在网上搜到了一篇罗列redis命令的文章
http://redis.readthedocs.org/en/latest/
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

继续往下走,下面的代码是:

c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr);

//查找命令的作用

这个函数最终调用了dictFetchValue(server.commands, name);

让我们想想server.commands里存的是什么?

我翻了我之前的代码记录,发现这里面存的是:redisCommandTable里的命令

name是什么,是client发给服务器的字符串的第一个字符串命令。

自然用这个来查找对应的命令了。

好,现在我们已经取到了相关命令,剩下自然是执行这个命令了。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr);

执行前先保存起来做个记录。

~~~~~~~~

if (!c->cmd)
{
flagTransaction(c);
addReplyErrorFormat(c,"unknown command '%s'",
(char*)c->argv[0]->ptr);
return REDIS_OK;
}
如果是无法识别的命令,则提示无法识别

~~~~

下面会对命令参数进行合法性判断,代码如下:

f ((c->cmd->arity > 0
&& c->cmd->arity != c->argc)
||
(c->argc < -c->cmd->arity))
我们来分析下具体的。

查阅redisCommandTable的定义数组,发现第3个参数arity有正有负,

这是为啥呢???

在大脑中思考了0.0001飞秒之后,我终于顿悟。

首先有些命令的个数必须一个不多一个不少,而有的命令必须至少要有多少个,

带着这样的观点来理解上面这句校验代码,就知道:

如果参数arity为正,表示一个不多一个不少。如3就表示必须=3.

如果参数为负,表示这个命令的参数至少为多少个,如-3就表示>=3.

~~~~~~~~~~~~~~~~

/* Check if the user is authenticated */
if (server.requirepass && !c->authenticated && c->cmd->proc != authCommand)
{
flagTransaction(c);
addReply(c,shared.noautherr);
return REDIS_OK;
}
判断是否需要验证。

还记得获取配置文件项的函数吗?

loadServerConfigFromString,我去翻了下这个函数的代码,

找到

else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
if (strlen(argv[1]) > REDIS_AUTHPASS_MAX_LEN) {
err = "Password is longer than REDIS_AUTHPASS_MAX_LEN";
goto loaderr;
}
server.requirepass = zstrdup(argv[1]);
}
然后我在redis.conf文件里搜索requirepass字符串,发现这个配置项没有定义

于是我们可以认为不需要认证。

好,继续执行。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

freeMemoryIfNeeded暂且不分析。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

继续执行。

下面的代码是:

if (server.stop_writes_on_bgsave_err
&&
server.saveparamslen > 0
&&
server.lastbgsave_status == REDIS_ERR
&&
c->cmd->flags & REDIS_CMD_WRITE)
{
flagTransaction(c);
addReply(c, shared.bgsaveerr);
return REDIS_OK;
}
我看了我的server.lastbgsave_status是REDIS_OK,所以这个不执行。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if (server.repl_min_slaves_to_write
&&
server.repl_min_slaves_max_lag
&&
c->cmd->flags & REDIS_CMD_WRITE
&&
server.repl_good_slaves_count < server.repl_min_slaves_to_write)
{
flagTransaction(c);
addReply(c, shared.noreplicaserr);
return REDIS_OK;
}
这个也同样不执行。

~~~~~~~~~~~~~~

/* Don't accept write commands if this is a read only slave. But
* accept write commands if this is our master. */
if (server.masterhost && server.repl_slave_ro &&
!(c->flags & REDIS_MASTER) &&
c->cmd->flags & REDIS_CMD_WRITE)
{
addReply(c, shared.roslaveerr);
return REDIS_OK;
}

这个也不执行

~~~~~~~~~~~~~~~~~~~

休息一会,待会再看!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息