我是如何通过添加一条命令学习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
相关文章推荐
- redis源码分析(三)redis命令学习总结—string字符串
- redis源码分析(七)、redis命令学习总结—Redis 有序集合(sorted set)
- 结合redis设计与实现的redis源码学习-11.1-命令的实现(Db.c)
- redis源码分析(四)、redis命令学习总结—链表List
- Redis源码学习-Master&Slave的命令交互
- redis系列:通过队列案例学习list命令
- redis源码学习2 功能性命令及其实现
- redis系列:通过日志案例学习string命令
- 2018/01/01Java基础学习——如何通过dos系统的javadoc命令生成API文档
- redis源码分析(五)、redis命令学习总结—哈希Hash
- redis系列:通过文章点赞排名案例学习sortedset命令
- redis系列:通过共同好友案例学习set命令
- Redis源码学习之【命令协议格式】
- OGRE学习之路02:手把手教你如何通过Doxygen从源码生成OGRE 1.10.11 的离线API文档
- redis源码分析(六)、redis命令学习总结—Redis 集合(Set)
- redis系列:通过日志案例学习string命令
- redis系列:通过通讯录案例学习hash命令
- Linux一条刚接触的命令该如何去学习它?
- Redis源码学习-Master&Slave的命令交互
- 如何通过maven命令将本地的jar包添加到maven依赖库中