概念

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

开始

这里我使用的是redis-2.2.2.tar.gz版本的redis(下载地址)首先要对它进行安装,这里我选择使用cygwin工具进行安装,加入我把该压缩包放在F盘下,使用cygwin工具进行shell命令:

1
2
3
tar xzf redis-2.2.2.tar.gz
cd redis-2.2.2
make

这里的make实际上操作的是Makefile文件,Makefile按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。

浏览下Redis根目录中的Makefile文件:

+ View Code

通过make命令可以执行“cd src && make all”。而此时的make all实际上已经开始执行src目录中的Makefile文件。这个文件比较复杂,大致就是将一系列的c文件以及h文件链接起来,通过cc/gcc编译器将文件生成目标文件o,接着将相应的o目标文件在通过编译器生成exe文件,当你编译完毕后,在src的目录上将产生5个exe文件:

redis-benchmark.exe:用于做性能测试;

redis-check-aof.exe:更新日志检查;

redis-check-dump.exe:用于本地数据库检查;

redis-cli.exe:客户端程序;

redis-server.exe:服务端程序;

具体用法这里不多说了,可以参考(http://www.cnblogs.com/daizhj/articles/1956681.html)

现在来看下src包含的文件(我按照首字母顺序来讲):

adlist.h/adlist.c:用于对list的定义,它是个双向链表结构,从头文件可以找到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// list节点
typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;
// list迭代器
typedef struct listIter {
    listNode *next;
    int direction;
} listIter;
// list数据结构
typedef struct list {
    listNode *head;
    listNode *tail;
    void *(*dup)(void *ptr);
    void (*free)(void *ptr);
    int (*match)(void *ptr, void *key);
    unsigned int len;
} list;

在ListNode节点下包含prev指针和next指针,说明它通过指针将节点进行双向链接。

并且从adlist.h的头文件可以找到非常丰富的方法声明,包括list创建,list释放,list头部/尾部添加节点等等,具体在后面的系列会做出介绍。

ae.h/ae.c:用于Redis的事件处理,包括句柄事件和超时事件。

在ae.c中的头部可以发现:

1
2
3
4
5
6
7
8
9
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
    #ifdef HAVE_KQUEUE
    #include "ae_kqueue.c"
    #else
    #include "ae_select.c"
    #endif
#endif

在网络相关操作中,定义了一组公共操作接口:aeApiCreate,aeApiFree,aeApiAddEvent,aeApiDelEvent,aeApiPoll,aeApiName方法。在ae_epoll.c、ae_kqueue.c和ae_select.c中,分别实现了基于epoll/kqueue和select系统调用的接口。系统调用的选择顺序依次为epoll,kqueue,select。

anet.h/anet.c:这两个文件非常重要,作为Server/Client通信的基础封装,包括anetTcpServer,anetTcpConnect,anetTcpAccept,anetRead,anetWrite等等方法。

aof.c:aof,全称为append only file,作用就是记录每次的写操作,在遇到断电等问题时可以用它来恢复数据库状态。但是他不是bin的,而是text的。一行一行,写得很规范.如果你是一台redis,那你也能人肉通过它恢复数据。

config.h/config.c:用于将配置文件redis.conf文件中的配置读取出来的属性通过程序放到server对象中。在main函数(server服务主入口点处)可以发现里面调用loadServerConfig(char *filename)方法,这个方法就是使用config.c里面的方法实现。具体会在后面的系列中详细介绍。

db.c:对于Redis内存数据库的相关操作。

debug.c:用于调试使用。

dict.h/dict.c:也是很重要的两个文件,主要对于内存中的hash进行管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct dictEntry {
    void *key;
    void *val;
    struct dictEntry *next;
} dictEntry;
typedef struct dictType {
    unsigned int (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;
typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    int iterators; /* number of iterators currently running */
} dict;

这里dictEntry作为一个dict字段结构,里面包括key以及value,已经指向下一个dictEntry的指针。dictType作为一些dict的操作结构。dict作为一个hash结构。后面的文章会具体介绍。

fmacros.h:用于Mac下的兼容性处理。

help.h:辅助于命令的提示信息,作用于redis-cli.exe可执行文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct commandHelp {
  char *name;
  char *params;
  char *summary;
  int group;
  char *since;
} commandHelp[] = {
    "APPEND",
    "key value",
    "Append a value to a key",
    1,
    "1.3.3" },
    "AUTH",
    "password",
    "Authenticate to the server",
    8,
    "0.08" },
    "BGREWRITEAOF",
    "-",
    "Asynchronously rewrite the append-only file",
    9,
    ....
};

intset.h/intset.c:整数范围内的使用set,并包含相关set操作。

lzf.h/lzf_c.c/lzf_d.c/lzfP.h:对于本地数据库的保存,使用的是LZF压缩算法,很神奇,算法只有200-300行的代码。

multi.c:用于事务处理操作。请看这样的一个例子:

通过执行exec,可以提交整个事务过程,如果你想撤销整个事务过程,你可以使用discard命令:

可以发现get age已经取不到值了,说明discard命令让事务失效。

networking.c:网络协议传输方法定义相关的都放在这个文件里面了。包括让Client连接上Server,让Slave挂接到Master,已经Server/Client之间的信息交互的实现等等。

object.c:用于创建和释放redisObject对象,redisObject结构为:

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct redisObject {
    unsigned type:4;
    unsigned storage:2;     /* REDIS_VM_MEMORY or REDIS_VM_SWAPPING */
    unsigned encoding:4;
    unsigned lru:22;        /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;
    /* VM fields are only allocated if VM is active, otherwise the
     * object allocation function will just allocate
     * sizeof(redisObjct) minus sizeof(redisObjectVM), so using
     * Redis without VM active will not have any overhead. */
} robj;

pqsort.h/pqsort.c/sort.c:关于排序算法,sort.c具体作为Redis场景下的排序实现。

pubsub.c:用于订阅模式的实现,有点类似于Client广播发送的方式。

rdb.c:对于Redis本地数据库的相关操作,默认文件是dump.rdb(通过配置文件获得),包括的操作包括保存,移除,查询等等。

redis-benchmark.c:用于redis性能测试的实现。请看main方法以下设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
config.debug = 0;
config.numclients = 50;
config.requests = 10000;
config.liveclients = 0;
config.el = aeCreateEventLoop();
aeCreateTimeEvent(config.el,1,showThroughput,NULL,NULL);
config.keepalive = 1;
config.donerequests = 0;
config.datasize = 3;
config.randomkeys = 0;
config.randomkeys_keyspacelen = 0;
config.quiet = 0;
config.loop = 0;
config.idlemode = 0;
config.latency = NULL;
config.clients = listCreate();
config.hostip = "127.0.0.1";
config.hostport = 6379;
config.hostsocket = NULL;
parseOptions(argc,argv);
config.latency = zmalloc(sizeof(long long)*config.requests);

默认性能测试中的客户端数量为50个,并行发送的请求有10000条,你也可以通过redis-benchmark命令行参数进行设置。

redis-check-aof.c:用于更新日志检查的实现。

redis-check-dump.c:用于本地数据库检查的实现。

redis-cli.c:客户端程序的实现。具体会在后面的文章详细介绍。

redis.h/redis.c:服务端程序的实现。具体会在后面的文章详细介绍。

release.h/release.c:用于发布使用。

replication.c:用于主从数据库的复制操作的实现。

sds.h/sds.c:用于对字符串的定义,从头文件可以找到:

1
2
3
4
5
6
//字符串
struct sdshdr {
    int len;
    int free;
    char buf[];
};

还可以看到对于字符串的相关操作,包括复制,连接,清零等等。

sha1.h/sha1.c:有关于sha算法的实现。

solarisfixes.h:Solaris系统的兼容性实现。

syncio.c:用于同步Socket和文件I/O操作。

t_hash.c/t_list.c/t_set.c/t_string.c/t_zset.c:hash,list,set,string,zset在Server/Client中的应答操作。主要通过redisObject进行类型转换。

testhelp.h:一个C风格的小型测试框架。

util.c:关于通用工具的方法实现。

version.h:Redis版本号定义。

vm.c:关于虚拟内存的管理实现。

zipmap.h/zipmap.c:zipmap是一个类似于hash的存储对象。在新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销,如果field或者value的大小超出一定限制后,redis会在内部自动将zipmap替换成正常的hash实现。

ziplist.h/ziplist.c:ziplist是一个类似于list的存储对象。它的原理类似于zipmap。

zmalloc.h/zmalloc.c:关于Redis的内存分配的封装实现。

下一篇我会介绍下redis-server以及redis-cli的源码实现。

转载于:https://www.cnblogs.com/xumaojun/p/8521734.html

Redis源码解析(1)——源码目录介绍相关推荐

  1. yolov3之pytorch源码解析_springmvc源码架构解析之view

    说在前面 前期回顾 sharding-jdbc源码解析 更新完毕 spring源码解析 更新完毕 spring-mvc源码解析 更新完毕 spring-tx源码解析 更新完毕 spring-boot源 ...

  2. 源码 解析_List源码解析

    点击上方「10分钟编程」关注我呦 让我们在一起每天「博学」一点点,成为更好的自己! List源码解析 本篇文章有点长,所以先列个目录 List源码解析 1.ArrayList 2.LinkedList ...

  3. Kafka核心源码解析 - KafkaController源码解析

    在进入源码解析之前,我先来介绍一些KafkaController在Kafka集群中的作用. (1)负责监听zookeeper上所有的元数据变更请求: (2)负责topic的partition迁移任务分 ...

  4. linux WiFi源码解析,WIFIDOG 源码解析

    WIFIDOG 源码解析 openwrt wifidog是我linux c语言编程的启蒙项目,一年前折腾此项目大半年,从此爱上了linux 系统编程.现在看来,这是一个再简单不过的linux c语言项 ...

  5. Dubbo源码分析笔记-一(工程目录介绍)

    Dubbo 是阿里开发的分布式服务调用框架,提供了它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现. 工程目录 模块介绍 dubbo-common   Dubb ...

  6. 栅格化渲染源码解析-neural_renderer源码(二)光照部分

    目录 一.变量形式 1.1 light 1.3  textures变量 1.4 faces变量 二.对于light的处理 2.1 ambient_light常数化光场 2.2 directional_ ...

  7. fceux源码解析_fceux源码解析_从源代码制作deb包的两种方法以及修改已有deb包(转载)...

    1. 原理 1) deb包通常包含两部分:控制信息(DEBIAN目录).安装内容(模拟"/"目录) 2) 通过解开已有的deb包看其中内容 i. 释放安装内容到dirname目录中 ...

  8. log4j 源码解析_Log4j源码解析--框架流程+核心解析

    OK,现在我们来研究Log4j的源码: 这篇博客有参照上善若水的博客,原文出处:http://www.blogjava.net/DLevin/archive/2012/06/28/381667.htm ...

  9. java解析java源码_JAVA语言-Java源码解析-Stack源码分析

    一.简介 stack类图.png 栈是数据结构中一种很重要的数据结构类型,因为栈的后进先出功能是实际的开发中有很多的应用场景.Java API中提供了栈(Stacck)的实现.Stack类继承了Vec ...

  10. log4j 源码解析_log4j2源码解析(2)--LoggerContext

    LoggerContext作用及初始化流程 根据我们在Log4j初识中的实例可以看出,在不适用日志门面插件slf4j的情况下,获取logger的方式一般为 Logger logger = logMan ...

最新文章

  1. 【原】HTML页面元素加载顺序研究报告(2)----背景图片
  2. Chrome DevTools — Network
  3. MySQL表完整性约束
  4. 学python五大理由_学习Python的五大理由
  5. java两个字符串 相隔天数_关于Java: Joda-Time时间中两个日期之间的天数
  6. 'System.Data.SqlClient' could not be loaded解决办法
  7. 记录一下我的蓝牙遥控小车
  8. Oracle日期函数和转换函数
  9. Unity3D脚本概述
  10. 第三章 教育法律法规
  11. 电脑变慢,电脑运行速度 突然变慢是怎么回事
  12. 利用浏览器保存和下载视频
  13. 使用BeautifulSoup爬取豆瓣电影排行榜
  14. 批处理学习(一)——MS-DOS命令
  15. 西电计科计组期中复习要点
  16. 第四周项目3单链表应用(2)
  17. 安装了Visual Studio Team System Web Access 2008 Power Tool
  18. 开源开放 | 多模态地球科学知识图谱GAKG
  19. 大数据技术——Hadoop3.X入门搭建+安装调优(1.入门)
  20. 计算机常用软件工具试题,计算机常用工具软件试题-20210402163232.docx-原创力文档...

热门文章

  1. 女生在java开发和前端之间不知道选择哪个怎么办?
  2. 如何学习前端知识?优秀的前端开发工程师应该具备什么条件?
  3. 你知道前端工程师的发展方向吗?
  4. 太真实了!有个程序员男友原来是这样的!
  5. 更改主机名后mysql无法启动_主机名变更导致MySql启动失败
  6. java token redis生成算法_如何访问 Redis 中的海量数据,服务才不会挂掉?
  7. Ubuntu环境搭建二:搭建samba服务器
  8. string input must not be null解决办法
  9. QAbstractTableModel中的data()到底执行几遍???
  10. J2ME程序员容易遇到的问题!不断更新中_2008.05.17