Redis源码阅读【3-Redis编译与GDB调试】

Redis源码阅读【1-简单动态字符串】
Redis源码阅读【2-跳跃表】
Redis源码阅读【3-Redis编译与GDB调试】
Redis源码阅读【4-压缩列表】
Redis源码阅读【5-字典】
Redis源码阅读【6-整数集合】
Redis源码阅读【7-quicklist】
Redis源码阅读【8-命令处理生命周期-1】
Redis源码阅读【8-命令处理生命周期-2】
Redis源码阅读【8-命令处理生命周期-3】
Redis源码阅读【8-命令处理生命周期-4】
Redis源码阅读【番外篇-Redis的多线程】
建议搭配源码阅读:源码地址

文章目录

  • 1、介绍
  • 2、Redis编译
    • 2.1、获取源码
    • 2.2、目录介绍
    • 2.3、编译前的准备
    • 2.4、开始编译
  • 3、GDB调试
    • 3.1、安装GDB
    • 3.2、GDB调试编译好的Redis
      • 3.2.1、GDB模式启动
      • 3.2.2、在Redis源码上打断点
  • 4、结束

1、介绍

本章主要是为了介绍Redis的编译方式,以及使用GDB对Redis进行调试的方法,为后面讲解源码打下基础,同时也介绍GDB这个C语言代码调试利器的部分使用

2、Redis编译

Redis编译应该是一个必须掌握的技能,毕竟很多时候我们并不一定会直接使用Redis编译好的包类型,可能会更具当前操作系统的情况,调整部分源码编译后再使用,例如Redis5当前的版本是不支持Windows的,如果大家想要使用Windows版本的Redis最好去官网下载Redis3以及之前的版本去自行编译使用,此外当大家希望能在Redis中加入一些日志或者其它东西的时候,一样需要修改源码进行编译,那么下面就介绍一下官方的推荐的编译步骤(很简单的)

2.1、获取源码

自行编译的第一步当然就算获取源码,Redis获取源码的方式最直接的就是github,这里我贴出Redis的github地址:https://github.com/antirez/redis,或者你可以通过github搜索Redis:Redis源码阅读【3-Redis编译与GDB调试】_第1张图片
当然github上面的是最新版本的代码,并非稳定版本代码,许多新版本的特性会先在github中放出,让大家下载调试体验,当然线上稳定版本还是建议去官网下载Stable版本,地址:https://redis.io/download
Redis源码阅读【3-Redis编译与GDB调试】_第2张图片

2.2、目录介绍

其中这个antirez/redis就是Redis在github上面官方的地址了。下载好后源码,我们可以随便导入到一个IDE里面查看,这里我使用的是Clion
Redis源码阅读【3-Redis编译与GDB调试】_第3张图片
项目结构如上图所示:

目录/文件 说明
deps Hiredis 模块(轻量级访问redis的客户端),linenoise模块(命令行编辑辅助,能实现自动补全) ,字典的定义实现,sds的定义实现,redis封装的malloc,Lua等
src 核心源码,大多功能都在这块实现,其中Redis自行实现了网络框架在这个目录中(ae_开头的文件),Redis并未使用libevent作为网络模块
tests 测试模块,用来测试Redis的代码,大多测试用例和脚本都在这里面
utils Redis的工具实现
redis.conf Redis官方源码默认提供的配置文件
Makefile Redis C语言编译使用的Makefile,当然你也可以使用Cmake进行管理,当然Cmake支持的不是很好

2.3、编译前的准备

在编译前,我们需要进行一些准备工作,我们本人是在Ubuntu-18上面进行编译的,Linux环境是推荐环境,Redis5目前只适配了Linux,并没有适配Windows,那么在Linux上进行编译本身我们也需要准备和更新一些内库,这里我当且认为你已经按照好了Ubuntu

1、更新Ubuntu到最新版本

sudo apt update

更新系统自带内库等等

2、下载编译必备内库,内包含一些C/C++必备的库

sudo apt install build-essential
sudo apt install gcc-c++

3、除此外可能会使用到的内库

apt-get install libqt4-* libqml*

4、如果出现has no member named(这个问题是由于官方升级了gcc导致的)

升级到 5.3及以上版本
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
//这里退出xhell会恢复gcc版本
scl enable devtoolset-9 bash
//永久替换
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile

5、安装测试工具tcl

sudo apt install tcl

2.4、开始编译

一切准备好后,准备开始编译,进入到源码目录底下,项目的根目录

直接编译

make #直接编译

make MALLOC=libc # 指定使用 libc对 malloc 编译

make MALLOC=jemalloc # 指定使用 jemalloc 编译但是要先安装jemalloc依赖

当然你也可以编译成32位版本

 make 32bit

执行后结果如下:
Redis源码阅读【3-Redis编译与GDB调试】_第4张图片
这里会提示你需要使用 make test 来执行内部的自测用例(test文件夹里面),来判断本次编译是否完全成功

执行 make test

sudo apt install tcl # 需要先安装tcl
make test

过程如下:
Redis源码阅读【3-Redis编译与GDB调试】_第5张图片
当出现这句化的时候证明自测已经成功
Redis源码阅读【3-Redis编译与GDB调试】_第6张图片
All tests passed withour errors!

这个时候进入项目根目录底下的src目录中你会发现几个已经编译好的二进制文件,是可以直接运行的
Redis源码阅读【3-Redis编译与GDB调试】_第7张图片
这两个就是服务端和客户端的运行入口了,其中默认的配置文件在外层根目录(redis.conf)

运行 ./redis-server 或者 ./redis-server …/redis.conf

./redis-server

结果如下
Redis源码阅读【3-Redis编译与GDB调试】_第8张图片
这个时候Redis服务端已经运行起来了。我们再打开一个终端,运行下面的指令:

root@zengshilin-virtual-machine:/home/test/redis-5.0.7/src# ./redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> set test hello
OK
127.0.0.1:6379> get test
"hello"

到这里我们的Redis已经完全编译成功了

3、GDB调试

GDB是unix/linux的常用调试工具,其中GDB支持man手册查阅,在Liunx这种经常没有可视化界面的操作系统底下,GDB是一种经常使用的调试工具,那么这里我也推荐大家使用GDB来调试已经编译好的Redis代码,其中Redis官网对GDB的介绍如下:http://redis.io/topics/debuggingRedis源码阅读【3-Redis编译与GDB调试】_第9张图片
可见官方也是推荐GDB来调试Redis

3.1、安装GDB

在Ubuntu底下安装GDB使用这条指令即可

sudo apt-get install gdb

3.2、GDB调试编译好的Redis

3.2.1、GDB模式启动

进入到刚刚编译好的Redis目录src底下,输入指令

gdb redis-server

结果如下:
Redis源码阅读【3-Redis编译与GDB调试】_第10张图片
此时刚刚编译好的redis-server已经进入到gdb的调试模式下,但是当前还未运行,然后我们启动以下redis服务端,使用 r 或者 r …/redis.conf

(gdb) r ../redis.conf

Redis源码阅读【3-Redis编译与GDB调试】_第11张图片
可以看到当前的Redis在GDB调试模式下启动了,这个使用我们再开一个新的窗口运行redis-cli查看效果如下:

127.0.0.1:6379> set test hello
OK
127.0.0.1:6379> get test
"hello"
127.0.0.1:6379> keys *
1) "test"
127.0.0.1:6379> 

可见服务端当前也是可用状态的

3.2.2、在Redis源码上打断点

GDB个其它调试一样,可以打断点在目标代码上面,同时也支持单步调试等操作,我们在服务断t_string.c文件上面的set命令打上断点看看是否生效,代码位置如图所示:
Redis源码阅读【3-Redis编译与GDB调试】_第12张图片
我们将断点打在setCommand上面,在gdb模式下执行:

(gdb) b setCommand
Breakpoint 1 at 0x609c0: file t_string.c, line 96.

断点已经打好,这时候我们在gdb模式下启动Redis

(gdb) r ../redis.conf

然后我们打开一个新终端,运行 redis-cli 输入以下命令

127.0.0.1:6379> set test hello

可以看到服务断那边已经执行到断点的位置
在这里插入图片描述
这时我们查看以下redis的运行栈
Redis源码阅读【3-Redis编译与GDB调试】_第13张图片
了解计算机操作系统的同学应该都知道,程序调用是基于栈的,所以这里打印出当前线程运行所经历的调用栈

我们通过以下指令来尝试GDB调试:

(gdb) n # 单步执行
102	    for (j = 3; j < c->argc; j++) {
(gdb) n
100	    int flags = OBJ_SET_NO_FLAGS;
(gdb) n
99	    int unit = UNIT_SECONDS;
(gdb) n
98	    robj *expire = NULL;
(gdb) n
138	    c->argv[2] = tryObjectEncoding(c->argv[2]);
(gdb) s # 进入函数内部
tryObjectEncoding (o=0x7ffff6c0e0c0) at object.c:431
431	robj *tryObjectEncoding(robj *o) {
(gdb) p *o # p 是 print的意思 打印当前变量
$1 = {type = 0, encoding = 8, lru = 454090, refcount = 1, ptr = 0x7ffff6c0e0d3}
(gdb) p o->type # 打印变量的成员属性
$2 = 0
(gdb) 

以上就算GDB调试的大致用法,也介绍大家可以多去官网看看gdb的其它使用技巧:http://www.gnu.org/software/gdb/

4、结束

这篇文章我们介绍了Redis在linux低下使用源码编译的过程,以及如何使用GDB调试工具来断点调试已经编译好的Redis,后续文章我也会不时使用GDB的方式来调试Redis的代码运行过程,以便更好的理解Redis的源码执行过程。

你可能感兴趣的:(源码阅读,redis)