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

我是如何通过添加一条命令学习redis源码的

2017-04-09 22:28 447 查看

准备工作

这篇文章不会告诉你啥是redis,如果不了解请自行搜索学习。

我的操作环境是cent OS 6.5系统,vim编辑器。

我打算下载一个比较稳定的redis源码包进行修改测试。

$ wget http://download.redis.io/redis-stable.tar.gz 
$ tar -zxvf redis-stable.tar.gz

$ cd redis-stable


进入redis-stable目录可以看到src目录,里面是redis的实现源码,我下面的工作基本就是修改这里面的内容。

我打算增加一条自定义的命令,并希望由此学习redis究竟是如何处理一条命令的。在此之前先看看redis自带的命令是怎么玩的。

[root@localhost bin]# redis-server /etc/redis/redis.conf
[root@localhost bin]# redis-cli
127.0.0.1:6379> set "pony" "大帅哥"
OK
127.0.0.1:6379> get "pony"
"大帅哥"
127.0.0.1:6379>


正式开始

我打算加入的命令叫STRUPPER,这条命令后面跟一个参数,也是key,返回key所对应的value的字母大写转换后的结果。比如key的值是”test”,那么strupper key就返回”TEST”。

看起来似乎是一条没有任何意义的命令(事实也是这样,哈哈), 但是请明白我在意的不是命令本身,而是redis的命令处理机制。

在src/server.c中定义了redis的命令表,

struct redisCommand redisCommandTable[] = {
{"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},
{"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},
{"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0},
{"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},

...


从代码中的注释,我了解到如果要增加一条命令,应该首先在这个表中增加一行定义。并且我还了解到结构体的每个字段的意义。

拿第一行举例,”get”是命令的名字,getCommand是一个函数指针,类型是:

typedef void redisCommandProc(client *c);


2表示参数的数量,比如get命令的用法是get后面跟key,第一个参数是get本身,第二个参数是key。

“rF”是标识命令的属性,r表示只读,也就是这条命令不能修改key对应的value值。F表示这是条”快命令”,就是时间复杂度是O(1)或者O(log(N))。

紧接着的0暂时不用管,总是设置为0就行。

接下来的NULL域,大部分时候这个域都应该是NULL。少数时候可以放一个函数指针,用在命令后面参数比较多的时候,分不清哪个是key。

接下来的三个数字,对于get命令,第一个参数(key)在位置1上,最后一个参数(也是key)在位置1上,从第一个参数到最后一个参数的增量也是1。

最后两个域总是初始化为0。

基于以上分析,我加了命令表底部加了一条命令:

{"strupper",strupperCommand,2,"w",0,NULL,1,1,1,0,0}


然后我需要在server.h中声明下命令处理函数,

void strupperCommand(client *c);


函数的实现应该放在哪里? redis是根据命令的类型来分类存放的,比如像getCommand和setCommand这样的字符串操作函数都是放在t_string.c文件中实现的,strupper也算是字符串处理函数,所以自然也是定义到这里,我先定义一个空函数。

void strupperCommand(client *c)
{
}


到这里,我先编译下看看效果。

[root@localhost redis-stable]# make
[root@localhost redis-stable]# make install

[root@localhost bin]# redis-server /etc/redis/redis.conf
[root@localhost bin]# redis-cli
127.0.0.1:6379>
127.0.0.1:6379> set pony "test"
OK
127.0.0.1:6379> strupper
(error) ERR wrong number of arguments for 'strupper' command
127.0.0.1:6379> strupper pony


可以看出,当我执行strupper pony时卡住了,是因为函数是空的还没实现。实现也是非常简单,

void strupperCommand(client *c)
{
robj *o;

if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
return;

if (o->type != OBJ_STRING) {
addReply(c,shared.wrongtypeerr);
return;
} else {

if (sdsEncodedObject(o))
{
sdstoupper(o->ptr);
}
addReplyBulk(c,o);
return;
}
}


大部分代码都是参考了get命令(因为这两个命令实在是太像了),我只需把get取出来的value值转换成大写就行了,当然一些基本的检查也是必须的。

lookupKeyReadOrReply函数根据传入的key(c->argv[1])查找,如果找到了会返回一个redis object对象,我们要的value就在这个对象里。

addReply负责响应结果到客户端。

sdsEncodedObject确保只对OBJ_ENCODING_RAW和OBJ_ENCODING_EMBSTR编码的string对象进行操作,这样才能用sdsXXX这样的函数操作。

sdstoupper可以对字符串整体进行大写转换。

重新编译下,测试。

127.0.0.1:6379> set pony "test"
OK
127.0.0.1:6379>
127.0.0.1:6379> get pony
"test"
127.0.0.1:6379> strupper pony
"TEST"


结果跟预想的一样。是个好的开始,后面再慢慢深入研究redis。

参考

A quick look at the Redis source code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: