Redis源码分析系列十六:processCommand研究
2013-10-24 00:00
337 查看
现在让我们回到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;
}
这个也不执行
~~~~~~~~~~~~~~~~~~~
休息一会,待会再看!
剩下的代码是:
/* 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;
}
这个也不执行
~~~~~~~~~~~~~~~~~~~
休息一会,待会再看!
相关文章推荐
- Redis源码分析系列十五:processInlineBuffer
- Redis源码分析系列十四:processInputBuffer
- jQuery-1.9.1源码分析系列(十六)ajax——响应数据处理和api整理
- Redis源码分析系列十一:createClient后面内容
- Redis源码分析系列二十一: 4 select---selectCommand
- Redis源码分析系列七:initServer下
- Redis源码分析系列
- Redis源码分析系列十:acceptTcpHandler
- redis客户端Jedis源码分析系列——从缓存池中获取资源和销毁资源
- redis客户端Jedis源码分析系列——连接池的创建过程
- [置顶] Spring Boot系列十二 通过redis实现Tomcat集群的Session同步及从源码分析其原理
- jQuery1.9.1源码分析系列(十六)ajax之ajax框架
- 转载_LKM backdoor研究linux系列--insmod源码分析篇
- ElasticStack系列之十六 & ElasticSearch5.x index/create 和 update 源码分析
- Redis 源码分析系列1-main函数相关调用分析
- Tcpdump源码分析系列6: main函数研究
- [转]LKM backdoor研究linux系列--insmod源码分析篇
- Tcpdump源码分析系列 5 : main函数研究
- Redis源码分析系列二十:3 命令"ping"---pingCommand
- Tcpdump源码分析系列4:main函数继续研究