随笔分类 - redis源码笔记
摘要:跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入、删除、查找的复杂度均为O(logN)。LevelDB的核心数据结构是用跳表实现的,redis的sorted set数据结构也是有跳表实现的。其结构如下所示:所有操作均从上向下逐层查找,越上层一次next操作跨度越大。其实现是典型的空间换时间。具体的细节,可参考维基百科http://en.wikipedia.org/wiki/Skip_list本文作者将redis的sorted set代码进行整理,将跳表部分的实现抽取出来,供参考。skiplist.h 1 #ifndef __SKIPLIST_H 2 #define __SKIP
阅读全文
摘要:hiredis是redis官方提供的c客户端库。在读代码的过程中,发现了一个bug,记录一下。hiredis里定义了一个上下文结构(struct redisContext),代码如下(deps/hiredis/hiredis.h):https://github.com/antirez/hiredis/blob/master/hiredis.h157 /* Context for a connection to Redis */158 typedef struct redisContext {159 int err; /* Error flags, 0 when there is no ...
阅读全文
摘要:serverCron是redis每隔100ms执行的一个循环事件,由ae事件框架驱动。其主要执行如下任务:1.记录循环时间:server.unixtime = time(NULL)redis使用全局状态cache了当前的时间值。在vm实现以及lru实现中,均需要对每一个对象的访问记录其时间,在这种情况下,对精度的要求并不高(100ms内的访问值一样是没有问题的)。使用cache的时间值,其代价要远远低于每次均调用time()系统调用2.更新LRUClock值:updateLRUClock()后续在执行lru淘汰策略时,作为比较的基准值。redis默认的时间精度是10s(#defineREDIS
阅读全文
摘要:initServer是redis对server进行初始化的入口,其由main调用,位于initServerConfig、命令行参数解析、守护进程判定之后,是server最重要的入口点。尽管代码看似简单(102行代码,且大量的赋值语句),但顺藤摸瓜,有很多点值得仔细看看。接下来逐行分析:函数第一件事是对信号进行处理: 899 signal(SIGHUP, SIG_IGN); 900 signal(SIGPIPE, SIG_IGN); 901 setupSignalHandlers();redis多作为守护进程运行,这时其不会有控制终端,首先忽略掉SIGHUP信号。(见AP...
阅读全文
摘要:纯文本协议,请求-响应模式。看下边链接:http://redis.io/topics/protocol《Unix编程艺术》中明确倡导使用纯文本协议。作者在specification的开头就指出,Redis的协议设计是如下三点的折中:Simple to implementFast to parse by a computerEasy enough to parse by a human一个如此重视性能的代码实现选用了如此简单易懂的协议设计,相信对仍旧执拗于使用二进制协议设计的开发者是个启发。
阅读全文
摘要:redis可以被作为类似memcached的应用级缓存使用,在内存超过限制时,按照配置的策略,淘汰掉相应的kv,使得内存可以继续留有足够的空间保存新的数据。redis的conf文件中有对该机制的一份很好的解释:194 # Don't use more memory than the specified amount of bytes.195 # When the memory limit is reached Redis will try to remove keys196 # accordingly to the eviction policy selected (see maxme
阅读全文
摘要:redis允许对key设置超时时间,实现过期key的自动淘汰。这篇blog分析下,其自适应(adaptive)的淘汰机制。redis每隔100ms定时执行的循环(serverCron function)里有如下语句: 655 /* Expire a few keys per cycle, only if this is a master. 656 * On slaves we wait for DEL operations synthesized by the master 657 * in order to guarantee a strict consisten...
阅读全文
摘要:aof是redis提供的一种数据持久化机制,通过将每一条命令dump下来,保持数据和内存中的数据一致。 1 #include "redis.h" 2 #include "bio.h" 3 4 #include <signal.h> 5 #include <fcntl.h> 6 #include <sys/stat.h> 7 #include <sys/types.h> 8 #include <sys/time.h> 9 #include <sys/resource.h> 10 #in
阅读全文
摘要:slowlog是redis提供的进行query分析的工具。它将执行时间长的命令统一以list形式保存在内存之中,使用者可以通过slowlog命令查看这些慢query,从而分析系统瓶颈。最好的分析笔记是作者的注释,除此之外,会做简要记录。slowlog.h 1 /* This structure defines an entry inside the slow log list */ 2 typedef struct slowlogEntry { 3 robj **argv; //记录query参数 4 int argc; 5 l...
阅读全文
摘要:这份代码是redis的client接口,其和server端的交互使用了deps目录下的hiredis c库,同时,在这部分代码中,应用了linenoise库完成类似history命令查询、自动补全等终端控制功能。 1 #include "fmacros.h" //用于mac下的兼容性处理 2 #include "version.h" //版本信息头文件,当前版本是2.4.10 3 4 #include <stdio.h> 5 #include <string.h> 6 #include <stdlib.h> 7 #in
阅读全文
摘要:作者在bio.c的头注释中对设计进行了详细的介绍/* Background I/O service for Redis. 这个文件是redis后台IO服务的实现 * * This file implements operations that we need to perform in the background. * Currently there is only a single operation, that is a background close(2) * system call. This is needed as when the process is the last ..
阅读全文
摘要:这部分代码是具体事件触发网络库的底层实现。Linux下有epoll设施,而且其效率是现在最高的。注意即使高效如redis,其也只是选择了自动档-水平触发(自动档和手动档的典故请自行google)。据说libevent也是使用的水平触发。废话不多说,看代码吧。 1 #include <sys/epoll.h> 2 3 typedef struct aeApiState { 4 int epfd; 5 struct epoll_event events[AE_SETSIZE]; //存的是epoll_wait返回后得到的事件列表 6 } aeApiState; //作为event...
阅读全文
摘要:ae.c是redis事件框架的具体实现,这篇blog对这份源码进行简单说明。其中谈到了作者已经标记的一些未来可能做的改进。ae.c 1 #include <stdio.h> 2 #include <sys/time.h> 3 #include <sys/types.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 7 #include "ae.h" 8 #include "zmalloc.h" 9 #include "config.h&q
阅读全文
摘要:ae框架是redis作者开发的事件处理框架,其目的和libevent项目类似。redis本着最小依赖原则,自己实现了一套,而且速度更快。ae只有不到500行代码,但据说libevent有3万加的代码,实现这一个功能所付出的代码量已经超过了redis所有的代码量。ae.h 1 #ifndef __AE_H__ 2 #define __AE_H__ 3 //同时支持的连接数,其实这个还是可以设的更大一些 4 #define AE_SETSIZE (1024*10) /* Max number of fd supported */ 5 6 #define AE_OK 0 7 #defi...
阅读全文
摘要:redis配置文件的头文件,有一些和平台有关的配置,在这里边进行设置。config.h 1 #ifndef __CONFIG_H 2 #define __CONFIG_H 3 4 #ifdef __APPLE__ 5 #include <AvailabilityMacros.h> 6 #endif 7 8 /* Define redis_fstat to fstat or fstat64() */ 9 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)10 #define redis_fstat fst
阅读全文
摘要:对于目标机是大端字节序的机器,进行字节码的转换,提供了16byte、32byte、64byte字节的转换。在intset\ziplist\zipmap三种数据结构中使用,使得不同字节序机器生成的rdb文件格式都是统一的(小端字节序),便于兼容。代码实在是太简单了,贴上来,不多说了。endian.h 1 #ifndef __ENDIAN_H 2 #define __ENDIAN_H 3 4 void memrev16(void *p); 5 void memrev32(void *p); 6 void memrev64(void *p); 7 8 /* variants of the fun..
阅读全文
摘要:anet库是redis对tcp网络层以及unix域实现的一个封装。redis的客户端和server端通信使用的均为TCP协议。Basic TCP socket stuff made a bit less boringanet.h 1 #ifndef ANET_H 2 #define ANET_H 3 4 #define ANET_OK 0 5 #define ANET_ERR -1 6 #define ANET_ERR_LEN 256 7 8 #if defined(__sun) 9 #define AF_LOCAL AF_UNIX10 #endif11 12 i...
阅读全文
摘要:这篇blog介绍dict的实现。dict.c 1 #include "fmacros.h" 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <stdarg.h> 7 #include <assert.h> 8 #include <limits.h> 9 #include <sys/time.h> 10 #include <ctype.h> 11 12 #include &q
阅读全文
摘要:这篇介绍redis最后一个基础数据结构——hash表。可以毫不夸张的说,hash表是redis一切存储的基础,也是redis得以快如飞的基础。注:其实还有个intset,不过intset是在持久化dump到硬盘时为节省空间设计的,和我们这里谈的不一样。dict的设计呢,简单的说是一个双表,“一主一从”,不定时rehash,建议大家在读代码前能够对这个设计有所了解。Anyway,随便搜一搜,很多文章的。dict.h 1 #ifndef __DICT_H 2 #define __DICT_H 3 4 #define DICT_OK 0 5 #define DICT_ERR 1 6 ...
阅读全文
摘要:testhelp.h是作者为redis量身定做的单元测试框架,对于redis这种规模的项目,就没有必要上GTEST这种大杀器了,作者18行代码搞定。不过很遗憾,在2.4.10这个版本的版本的redis中,只有sds用了这个测试框架,不知其他代码作者是如何做测试的。我慢慢摸索,摸索到了告诉大家。 1 #ifndef __TESTHELP_H 2 #define __TESTHELP_H 3 4 int __failed_tests = 0; //失败的测试用例数 5 int __test_num = 0; //总的测试用例数 6 #defin...
阅读全文