学习redis 源代码,使用哪个版本好

redis的一些介绍,麻烦阅读前面的几篇文章,想对redis的详细实现有所了解,强力推荐《redis设计与实现》(不仅仅从作者那儿学习到redis的实现,还有项目的管理、思想等,作者可能比你我都年轻欧)。如果阅读了上面的文档,激起你对redis的强力好奇,那么就只能阅读源码了。不管是在校学生,还是已工作的,redis的代码都值得阅读。我们可以了解如何编写一个工程可用软件,可以学习一些开源常用软件,通过redis丰富的数据结构,可以熟悉大学学习的那点儿数据结构,可以了解如何实现一个自己高效的网络框架等等。
我看到有人介绍redis源代码的阅读方法如下:
自底向上:从耦合关系最小的模块开始读,然后逐渐过度到关系紧密的模块。就好像写程序的测试一样,先从单元测试开始,然后才到功能测试。我在刚开始读 Redis 源码的时候,使用的就是这种方法:先从单独的数据结构模块开始,然后再过渡到高层的功能模块。
从功能入手:通过文件名(模块名)和函数名,快速定位到一个功能的具体实现,然后追踪整个实现的运作流程,从而了解该功能的实现方式。我在读阻塞列表、数据库这种流程和功能都比较复杂,和其他文件耦合也比较多的模块时,使用的就是这样的方法。
自顶向下:从程序的 main() 函数,或者某个特别大的调用者函数为入口,以深度优先或者广度优先的方式阅读它的源码。我在阅读 redis.c/serverCron() 、 redis.c/main() 和 ae.c/aeMain() 这种有明显调用者性质的函数时,使用的就是这样的方法。
我觉得不错,可以作为参考欧。
你是吧现在就准备动手了,但是一个人阅读代码,写文档比较枯燥,害怕自己坚持不住,并且个人能力有些,有可能对有些代码理解错误或者不能觉察作者的用意。因此准备探索一种新的代码阅读模式,通过一个开源项目和一个qq群把大家团结起来,开源项目的提交人必须是有限的,但是正在阅读代码的人可能很多,发现了问题不能及时反馈或者咨询,QQ群比较及时。开源项目是一个代码分析的文档,restructured text格式,使用sphinx进行生成各种文档格式。sphinx的使用可以参考:( )等。寻找四个有兴趣的小伙伴可以进行编辑,别的小伙伴就不好意思了,因为bitbucket只能免费支持五个,只能在qq群反馈意见。
为了建立信任,就做一下自我介绍:2012年毕业于西安电子科技大学,现在就职于一家深圳网络公司,从一进公司就是做数据仓库这一块儿的,公司使用的是自研的系统,详细就不太方便介绍。对大数据比较感兴趣,同时也在了解一些hadoop、spark的知识。但是,这是第一次进行这样的尝试,若有什么好的建议欢迎提给楼主欧。
项目地址:
redis源码解析
如果想成为文档编辑者可邮件,最好做一下简单自我介绍:(at)qq.com
http://redissrc.readthedocs.org/en/latest/
阅读(...) 评论()redis源码好在哪里之命令处理 - 推酷
redis源码好在哪里之命令处理
redis的命令处理流程代码写得非常好,值得我们借鉴学习。
为啥要学习redis的命令处理
redis需要处理不同的命令,对于每一个命令,具体到代码实现时,就是不同的函数。这种需求是如此的常见,以致于你应该见过或者写过很多类似下面这样的代码:
if (cmd == 'a')
processA()
else if (cmd == 'b')
processB()
else if (cmd == 'C')
processC()
else if (cmd == 'd')
processD()
raise NotImplementException
考虑到redis有160+个命令,如果按照这种写法,那么,这段if语句将会非常长,长到骇人听闻,长到难以维护。
redis的命令处理流程
那么,redis是怎么处理的呢?要回答这个问题,先简单介绍一下redis的命令处理流程:
接收请求:读入客户端发送过来的请求(query_string),解析请求获取命令
查找命令:在hash表中查找命令,判断用户输入的命令是否正确、是否存在
预检查:检查命令的参数个数是否满足要求,客户端是否已经认证等
执行命令:执行命令
执行完成:发送结果到客户端,记录慢日志等
下面是redis命令处理的堆栈:
quicklistCreate () at quicklist.c:98
0xc297 in createQuicklistObject () at object.c:184
0xb08b in pushGenericCommand (c=0x7f529e11c000, where=0) at t_list.c:209
0xb1ed in lpushCommand (c=0x7f529e11c000) at t_list.c:228
0x9591 in call (c=0x7f529e11c000, flags=7) at redis.c:2091
0xa054 in processCommand (c=0x7f529e11c000) at redis.c:2341
0x90f5 in processInputBuffer (c=0x7f529e11c000) at networking.c:1171
0x93cf in readQueryFromClient (el=0x7f529e058150, fd=6, privdata=0x7f529e11c000, mask=1) at networking.c:1232
0x1ded in aeProcessEvents (eventLoop=0x7f529e058150, flags=3) at ae.c:412
0x1f77 in aeMain (eventLoop=0x7f529e058150) at ae.c:455
#10 0xddc1 in main (argc=1, argv=0x7fffbab43408) at redis.c:3889
redis的命令处理流程详解
我们直接将目光聚焦到call函数,call函数的部分内容如下:
/* Call() is the core of Redis execution of a command */
void call(redisClient *c, int flags) {
long long dirty, start,
int client_old_flags = c-&
/* Sent the command to clients in MONITOR mode, only if the commands are
* not generated from reading an AOF. */
if (listLength(server.monitors) &&
!server.loading &&
!(c-&cmd-&flags & (REDIS_CMD_SKIP_MONITOR|REDIS_CMD_ADMIN)))
replicationFeedMonitors(c,server.monitors,c-&db-&id,c-&argv,c-&argc);
/* Call the command. */
c-&flags &= ~(REDIS_FORCE_AOF|REDIS_FORCE_REPL);
redisOpArrayInit(&server.also_propagate);
dirty = server.
start = ustime();
c-&cmd-&proc(c);
duration = ustime()-
dirty = server.dirty-
if (dirty & 0) dirty = 0;
无论是什么命令,都会进入到call函数体,call函数通过调用
c-&cmd-proc(c)
执行具体的命令。那么,proc又是啥?我们看一下redisCommand结构体:
struct redisCommand {
redisCommandProc *
char * /* Flags as string representation, one char per flag. */
只是一个指针,具体指向可以看redisCommand的初始化结构体:
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},
{&psetex&,psetexCommand,4,&wm&,0,NULL,1,1,1,0,0},
{&append&,appendCommand,3,&wm&,0,NULL,1,1,1,0,0},
{&strlen&,strlenCommand,2,&rF&,0,NULL,1,1,1,0,0},
{&del&,delCommand,-2,&w&,0,NULL,1,-1,1,0,0},
这里简单解释一下,proc是一个函数指针,在命令初始化的时候,对每一个命令,传递不同的函数指针。个人觉得,将proc理解为回调函数(c语言似乎没有这种说法)更加合适。
对于每一个命令,都会有一个redisCommand结构体,该结构中的proc保存了一个回调函数,redis接收到客户端的请求以后,通过调用回调函数,执行相应的命令。这就实现了对于每个命令调用不同函数的需求,同时也保证的代码的可读性,更重要的,代码可维护性显著提高。
在面向对象的编程语言中的处理方法
类似上面的需求,在面向对象中还有更好的处理办法。例如,
中(ZooKeeper代码写得是真好啊),通过多态实现了类似的需求。
protected boolean processZKCmd(MyCommandOptions co)
throws KeeperException, IOException, InterruptedException
String[] args = co.getArgArray();
String cmd = co.getCommand();
if (!commandMap.containsKey(cmd)) {
// execute from commandMap
CliCommand cliCmd = commandMapCli.get(cmd);
if(cliCmd != null) {
cliCmd.setZk(zk);
watch = cliCmd.parse(args).exec(); // **********重点************
} else if (!commandMap.containsKey(cmd)) {
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

 

随机推荐