如何搭建Redis调试环境,深入源码漂流记(二)?

2026-05-06 05:351阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计6349个文字,预计阅读时间需要26分钟。

如何搭建Redis调试环境,深入源码漂流记(二)?

《Redis源码漫谈(二)- 搭建Redis调试环境+目标+搭建Redis调试环境+简单理解Redis命令转换流程+二、前置+1、有一些c知识基础(变量命名、常用数据类型、指针等)+可以参考这篇》

如何搭建Redis调试环境,深入源码漂流记(二)?

Redis源码漂流记(二)-搭建Redis调试环境 一、目标
  • 搭建Redis调试环境
  • 简要理解Redis命令运转流程
二、前提 1、有一些c知识简单基础(变量命名、常用数据类型、指针等)

可以参考这篇简单入门C语言入门教程 , 或者B站搜索C语言相关教材(播放量最高的几个均可)。

/*引入头文件,类似java和go中的import包,C#中的using命名空间*/
#include<stdio.h>
intmain(void)/*一个简单的C程序*/
{
intnumber;/*定义个名字叫做number的变量*/
number=2022;/*给number赋一个值*/
printf("Thisyearis%d\n",number);/*调用printf()函数*/
intintsize=sizeof(int);
/*输出:intsizeofis4bytes*/
printf("intsizeofis%dbytes\n",intsize);
return0;
}

/*RedisStateofaneventbasedprogram*/
typedefstructaeEventLoop{
/*highestfiledescriptorcurrentlyregistered*/
intmaxfd;
/*maxnumberoffiledescriptorstracked*/
intsetsize;
longlongtimeEventNextId;
aeFileEvent*events;/*Registeredevents*/
aeFiredEvent*fired;/*Firedevents*/
aeTimeEvent*timeEventHead;
intstop;
/*ThisisusedforpollingAPIspecificdata*/
void*apidata;
aeBeforeSleepProc*beforesleep;
aeBeforeSleepProc*aftersleep;
intflags;
}aeEventLoop;

基本数据类型

2、了解Redis的基本使用

如 set/get等即可。

3、 本地搭建过Ubautu虚拟机或者直接有服务器。

考虑到redis一般安装到linux环境中,所以采取Ubantu进行调试。

windows下需要下载redis-windows版本的源码,IDE采用使用Clion搭建redis debug环境或Using GCC with MinGW

三、搭建IDE环境 1、安装vscode
2、安装vscode c++扩展
  • C/C++:提供C/C++支持
  • Code Runner:提供编译后程序的运行环境
  • C/C++ Snippets:提供一些常用的C/C++片段,如for(;;){},安装后写代码 方便(tip.如果想要添加自己写的代码段可以点左下角齿轮->用户代码片段)
  • EPITECH C/C++ Headers :为C/C++文件添加头部(包括作者、创建和修改日期等),并为.h头文件添加防重复的宏
  • Include Autocomplete: 头文件自动补全
3、安装 gcc/gdb

先尝试下面命令安装

sudoapt-getupdate
sudoapt-getinstallbuild-essentialgdb

如果不行就尝试下面的。

sudoapt-getinstallaptitude
sudoaptitudeinstallgccg++

如果存在依赖性报错安装失败,对建议的方案,第一个no,第二个yes. 检测是否安装成功

gcc-v
g++-v
gdb-v
make-v
四、检测c文件运行和调试

创建一个目录,用于存放演示文件

mkdirMyCode/src
cdMyCode/src

创建hello.c文件

#include<stdio.h>
intmain()
{
puts("HelloC");
return0;
}

运行:按CodeRunner快捷键运行代码:

[Running]cd"/home/fcw/MyCode/src/main/"&&gcchello.c-ohello&&"/home/fcw/MyCode/src/main/"hello
HelloC

调试: Run-->Start Debugging或 F5调试

选择环境 选择配置

五、下载和编译Redis 1.下载redis源码

//创建redis目录
mkdirMyCode/redis
cdMyCode/redis
//下载redis
wgetdownload.redis.io/releases/redis-6.2.7.tar.gz

//解压
tarxzfredis-6.2.7.tar.gz
cdredis-6.2.7/
2、编译Redis

  • 编辑Makefile (这里也可以打开vsCode编辑复制 )

vimsrc/Makefile

  • 更新 makefile 下面对应的编译项内容,修改该项的主要目的是为了防止编译优化.

O0 -->> O1 -->> O2 -->> O3 (少优化->多优化), -O0表⽰没有优化,-O1为缺省值,-O3优化级别最⾼

#--------------------
#OPTIMIZATION?=-O2
OPTIMIZATION?=-O0
#REDIS_LD=$(QUIET_LINK)$(CC)$(FINAL_LDFLAGS)
REDIS_LD=$(QUIET_LINK)$(CC)$(FINAL_LDFLAGS)$(OPTIMIZATION)
#--------------------

更新前: 更新后

  • 编译redis

makeclean;make

Makefile和Make简要说明:

需要运行/调试多文件时,Makefile可以设置你想要的编译规则,你想要编译哪些文件,哪些文件不需要编译等等都可以体现在Makefile中,而且支持多线程并发操作,可以减少编译的时间。

make是用来执行Makefile的,make根据Makefile中写的内容进行编译和链接,make更像是一个批处理的工具,可以批处理源文件,只要执行一条make命令,就可以实现自动编译。当我们编译整个项目工程的时候,make只会编译我们修改过的文件,没有修改过的就不用重新编译,使用make+Makefile极大的提高了我们的工作效率。

cmake可以生成Makefile文件,支持生成不同平台的Makefile。cmake根据一个叫CMakeLists.txt(手写)的文件生成Makefile。

3、配置launch.json

launch.json

随便选中一个c文件。点调试(F5),会提示添加配置。

{
"configurations":[
{
"name":"(gdb)启动",
"type":"cppdbg",
"request":"launch",
"program":"${workspaceFolder}/src/redis-server",
"args":["${workspaceFolder}/redis.conf"],
"stopAtEntry":false,
"cwd":"${fileDirname}",
"environment":[],
"externalConsole":false,
"MIMode":"gdb",
"setupCommands":[
{
"description":"为gdb启用整齐打印",
"text":"-enable-pretty-printing",
"ignoreFailures":true
},
{
"description":"将反汇编风格设置为Intel",
"text":"-gdb-setdisassembly-flavorintel",
"ignoreFailures":true
}
]
}
]
}
六、调试Redis源码-初探

通过Readme.md可以看到相关文件的简介,例server.c文件

server.c
---

ThisistheentrypointoftheRedisserver,wherethe`main()`function
isdefined.Thefollowingarethemostimportantstepsinordertostartup
theRedisserver.

*`initServerConfig()`setsupthedefaultvaluesofthe`server`structure.
*`initServer()`allocatesthedatastructuresneededtooperate,setupthelisteningsocket,andsoforth.
*`aeMain()`startstheeventloopwhichlistensfornewconnections.

Therearetwospecialfunctionscalledperiodicallybytheeventloop:

1.`serverCron()`iscalledperiodically(accordingto`server.hz`frequency),andperformstasksthatmustbeperformedfromtimetotime,likecheckingfortimedoutclients.
2.`beforeSleep()`iscalledeverytimetheeventloopfired,Redisservedafewrequests,andisreturningbackintotheeventloop.

Insideserver.cyoucanfindcodethathandlesothervitalthingsoftheRedisserver:

*`call()`isusedinordertocallagivencommandinthecontextofagivenclient.
*`activeExpireCycle()`handlesevictionofkeyswithatimetolivesetviathe`EXPIRE`command.
*`performEvictions()`iscalledwhenanewwritecommandshouldbeperformedbutRedisisoutofmemoryaccordingtothe`maxmemory`directive.
*Theglobalvariable`redisCommandTable`definesalltheRediscommands,specifyingthenameofthecommand,thefunctionimplementingthecommand,thenumberofargumentsrequired,andotherpropertiesofeachcommand.

找到 server.c, main 这是总入口

intmain(intargc,char**argv)

aeMain(server.el);//这里面是一个事件循环监听
aeDeleteEventLoop(server.el);

这里接收tcp或socket连接,然后将event及handler放入事件池/bus中。

/*CreateaneventhandlerforacceptingnewconnectionsinTCPorTLSdomainsockets.
*Thisworksatomicallyforallsocketfds*/
intcreateSocketAcceptHandler(socketFds*sfd,aeFileProc*accept_handler){
intj;

for(j=0;j<sfd->count;j++){
if(aeCreateFileEvent(server.el,sfd->fd[j],AE_READABLE,accept_handler,NULL)==AE_ERR){
/*Rollback*/
for(j=j-1;j>=0;j--)aeDeleteFileEvent(server.el,sfd->fd[j],AE_READABLE);
returnC_ERR;
}
}
returnC_OK;
}

另起一个终端,运行redis-cli,会链接到redis-server,从而调试redis相关源码。

cdMyCode/redis/redis-6.2.7/
./src/redis-cli

找到ae.c,这里是一个while循环监控命令,用于监听新函数的事件循环处理(server.cmain函数会调用这里)。

voidaeMain(aeEventLoop*eventLoop){
eventLoop->stop=0;
while(!eventLoop->stop){
aeProcessEvents(eventLoop,AE_ALL_EVENTS|
AE_CALL_BEFORE_SLEEP|
AE_CALL_AFTER_SLEEP);
}
}
intaeProcessEvents(aeEventLoop*eventLoop,intflags)

找到connection.c

staticvoidconnSocketEventHandler(structaeEventLoop*el,intfd,void*clientData,intmask)

找到connhelper.c

staticinlineintcallHandler(connection*conn,ConnectionCallbackFunchandler){
connIncrRefs(conn);
if(handler)handler(conn);
connDecrRefs(conn);
if(conn->flags&CONN_FLAG_CLOSE_SCHEDULED){
if(!connHasRefs(conn))connClose(conn);
return0;
}
return1;

找到networking.cprocessInputBufferprocessCommandAndResetClient 处打断点

intprocessCommandAndResetClient(client*c){
intdeadclient=0;
client*old_client=server.current_client;
server.current_client=c;
if(processCommand(c)==C_OK){
commandProcessed(c);
}

找到server.c,在 processCommandcall等处打断点

处理命令的总入口。

intprocessCommand(client*c)

经过了moduleCallCommandFilters、检查是否是quitlookupCommandauthRequiredACLCheckAllPermcluster_enabledserver.maxmemorywriteCommandsDeniedByDiskErrorrejectCommandblockClient等一系列安全检查逻辑后,来到了执行命令的地方

c->cmd=c->lastcmd=lookupCommand(c->argv[0]->ptr);
...
...
/*Execthecommand*/
if(c->flags&CLIENT_MULTI&&
c->cmd->proc!=execCommand&&c->cmd->proc!=discardCommand&&
c->cmd->proc!=multiCommand&&c->cmd->proc!=watchCommand&&
c->cmd->proc!=resetCommand)
{
queueMultiCommand(c);
addReply(c,shared.queued);
}else{
call(c,CMD_CALL_FULL);
c->woff=server.master_repl_offset;
if(listLength(server.ready_keys))
handleClientsBlockedOnKeys();
}

voidcall(client*c,intflags)
...
server.in_nested_call++;
c->cmd->proc(c);
server.in_nested_call--;

找到t_string.c

setCommand

处理命令的堆栈信息如下:

此后将结果写回到客户端

intwriteToClient(client*c,inthandler_installed){
/*Updatetotalnumberofwritesonserver*/
atomicIncr(server.stat_total_writes_processed,1);

返回结果的堆栈信息如下:

从上面的调试以及堆栈信息可以看出,处理结果和将结果写回到客户端是在两个事件中处理的。

总结redis服务端整个程序流程图如下:

七、环境问题解决
  • gcc : 依赖: gcc-7(>= 7.3.0-12~) 但是它将不会被安装

sudoapt-getinstallgcc
出现如下错误:
正在读取软件包列表…完成
正在分析软件包的依赖关系树
正在读取状态信息…完成
有一些软件包无法被安装。如果您用的是unstable发行版,这也许是
因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件
包尚未被创建或是它们已被从新到(Incoming)目录移出。
下列信息可能会对解决问题有所帮助:
下列软件包有未满足的依赖关系:
gcc:依赖:gcc-7(>=7.3.0-12~)但是它将不会被安装
E:无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

使用aptitude包依赖管理工具代替apt来处理,aptitude软件包管理工具在解决依赖性问题上更有优势,具体使用方法如下:
sudoapt-getinstallaptitude
sudoaptitudeinstallgccg++
终端中输入后会提示aptitude给出的解决方案,可以选择no,
会继续提供下一个解决方案,但前面的方案会是忽略掉依赖冲突,所以想要彻底解决的话可以跳过前面的几种方案,然后再yes解决。(个人第一次No,第二次Yes)
blog.csdn.net/zhutingting0428/article/details/51120949

  • linux ubuntu gcc编译 fatal error: bits/libc-header-start.h 错误解决

apt-getinstallgcc-multilib

其实主要是gcc安装环境没有安装完善Multilib,顾名思义,就是多重的。 用它完全可以替代原来单一的lib。 这样就既能产生32位的代码,又能生成64位的。比如:64bit机器,同时可以产生32和64两种格式,

八、引用资料
  • gcc优化选项-O1-O2-O3-Os优先级
  • 浅析Makefile、make、cmake
  • Debug Redis in VsCode with Gdb
  • 用 gdb 调试 redis
  • Ubuntu下配置VS Code C++ 环境
  • ubuntu18.04+VScode使用记录(持续更新
  • 在vscode中配置C/C++环境
  • how-to-install-and-configure-redis-on-ubuntu-20-04
  • Redis命令set学习(一)

这篇文章整理了一个从服务端和客户端两个维度流程图片

九、转载请注明出处
  • www.cnblogs.com/fancunwei
  • ”威行云栈“公众号(微信号:fundeway)

本文共计6349个文字,预计阅读时间需要26分钟。

如何搭建Redis调试环境,深入源码漂流记(二)?

《Redis源码漫谈(二)- 搭建Redis调试环境+目标+搭建Redis调试环境+简单理解Redis命令转换流程+二、前置+1、有一些c知识基础(变量命名、常用数据类型、指针等)+可以参考这篇》

如何搭建Redis调试环境,深入源码漂流记(二)?

Redis源码漂流记(二)-搭建Redis调试环境 一、目标
  • 搭建Redis调试环境
  • 简要理解Redis命令运转流程
二、前提 1、有一些c知识简单基础(变量命名、常用数据类型、指针等)

可以参考这篇简单入门C语言入门教程 , 或者B站搜索C语言相关教材(播放量最高的几个均可)。

/*引入头文件,类似java和go中的import包,C#中的using命名空间*/
#include<stdio.h>
intmain(void)/*一个简单的C程序*/
{
intnumber;/*定义个名字叫做number的变量*/
number=2022;/*给number赋一个值*/
printf("Thisyearis%d\n",number);/*调用printf()函数*/
intintsize=sizeof(int);
/*输出:intsizeofis4bytes*/
printf("intsizeofis%dbytes\n",intsize);
return0;
}

/*RedisStateofaneventbasedprogram*/
typedefstructaeEventLoop{
/*highestfiledescriptorcurrentlyregistered*/
intmaxfd;
/*maxnumberoffiledescriptorstracked*/
intsetsize;
longlongtimeEventNextId;
aeFileEvent*events;/*Registeredevents*/
aeFiredEvent*fired;/*Firedevents*/
aeTimeEvent*timeEventHead;
intstop;
/*ThisisusedforpollingAPIspecificdata*/
void*apidata;
aeBeforeSleepProc*beforesleep;
aeBeforeSleepProc*aftersleep;
intflags;
}aeEventLoop;

基本数据类型

2、了解Redis的基本使用

如 set/get等即可。

3、 本地搭建过Ubautu虚拟机或者直接有服务器。

考虑到redis一般安装到linux环境中,所以采取Ubantu进行调试。

windows下需要下载redis-windows版本的源码,IDE采用使用Clion搭建redis debug环境或Using GCC with MinGW

三、搭建IDE环境 1、安装vscode
2、安装vscode c++扩展
  • C/C++:提供C/C++支持
  • Code Runner:提供编译后程序的运行环境
  • C/C++ Snippets:提供一些常用的C/C++片段,如for(;;){},安装后写代码 方便(tip.如果想要添加自己写的代码段可以点左下角齿轮->用户代码片段)
  • EPITECH C/C++ Headers :为C/C++文件添加头部(包括作者、创建和修改日期等),并为.h头文件添加防重复的宏
  • Include Autocomplete: 头文件自动补全
3、安装 gcc/gdb

先尝试下面命令安装

sudoapt-getupdate
sudoapt-getinstallbuild-essentialgdb

如果不行就尝试下面的。

sudoapt-getinstallaptitude
sudoaptitudeinstallgccg++

如果存在依赖性报错安装失败,对建议的方案,第一个no,第二个yes. 检测是否安装成功

gcc-v
g++-v
gdb-v
make-v
四、检测c文件运行和调试

创建一个目录,用于存放演示文件

mkdirMyCode/src
cdMyCode/src

创建hello.c文件

#include<stdio.h>
intmain()
{
puts("HelloC");
return0;
}

运行:按CodeRunner快捷键运行代码:

[Running]cd"/home/fcw/MyCode/src/main/"&&gcchello.c-ohello&&"/home/fcw/MyCode/src/main/"hello
HelloC

调试: Run-->Start Debugging或 F5调试

选择环境 选择配置

五、下载和编译Redis 1.下载redis源码

//创建redis目录
mkdirMyCode/redis
cdMyCode/redis
//下载redis
wgetdownload.redis.io/releases/redis-6.2.7.tar.gz

//解压
tarxzfredis-6.2.7.tar.gz
cdredis-6.2.7/
2、编译Redis

  • 编辑Makefile (这里也可以打开vsCode编辑复制 )

vimsrc/Makefile

  • 更新 makefile 下面对应的编译项内容,修改该项的主要目的是为了防止编译优化.

O0 -->> O1 -->> O2 -->> O3 (少优化->多优化), -O0表⽰没有优化,-O1为缺省值,-O3优化级别最⾼

#--------------------
#OPTIMIZATION?=-O2
OPTIMIZATION?=-O0
#REDIS_LD=$(QUIET_LINK)$(CC)$(FINAL_LDFLAGS)
REDIS_LD=$(QUIET_LINK)$(CC)$(FINAL_LDFLAGS)$(OPTIMIZATION)
#--------------------

更新前: 更新后

  • 编译redis

makeclean;make

Makefile和Make简要说明:

需要运行/调试多文件时,Makefile可以设置你想要的编译规则,你想要编译哪些文件,哪些文件不需要编译等等都可以体现在Makefile中,而且支持多线程并发操作,可以减少编译的时间。

make是用来执行Makefile的,make根据Makefile中写的内容进行编译和链接,make更像是一个批处理的工具,可以批处理源文件,只要执行一条make命令,就可以实现自动编译。当我们编译整个项目工程的时候,make只会编译我们修改过的文件,没有修改过的就不用重新编译,使用make+Makefile极大的提高了我们的工作效率。

cmake可以生成Makefile文件,支持生成不同平台的Makefile。cmake根据一个叫CMakeLists.txt(手写)的文件生成Makefile。

3、配置launch.json

launch.json

随便选中一个c文件。点调试(F5),会提示添加配置。

{
"configurations":[
{
"name":"(gdb)启动",
"type":"cppdbg",
"request":"launch",
"program":"${workspaceFolder}/src/redis-server",
"args":["${workspaceFolder}/redis.conf"],
"stopAtEntry":false,
"cwd":"${fileDirname}",
"environment":[],
"externalConsole":false,
"MIMode":"gdb",
"setupCommands":[
{
"description":"为gdb启用整齐打印",
"text":"-enable-pretty-printing",
"ignoreFailures":true
},
{
"description":"将反汇编风格设置为Intel",
"text":"-gdb-setdisassembly-flavorintel",
"ignoreFailures":true
}
]
}
]
}
六、调试Redis源码-初探

通过Readme.md可以看到相关文件的简介,例server.c文件

server.c
---

ThisistheentrypointoftheRedisserver,wherethe`main()`function
isdefined.Thefollowingarethemostimportantstepsinordertostartup
theRedisserver.

*`initServerConfig()`setsupthedefaultvaluesofthe`server`structure.
*`initServer()`allocatesthedatastructuresneededtooperate,setupthelisteningsocket,andsoforth.
*`aeMain()`startstheeventloopwhichlistensfornewconnections.

Therearetwospecialfunctionscalledperiodicallybytheeventloop:

1.`serverCron()`iscalledperiodically(accordingto`server.hz`frequency),andperformstasksthatmustbeperformedfromtimetotime,likecheckingfortimedoutclients.
2.`beforeSleep()`iscalledeverytimetheeventloopfired,Redisservedafewrequests,andisreturningbackintotheeventloop.

Insideserver.cyoucanfindcodethathandlesothervitalthingsoftheRedisserver:

*`call()`isusedinordertocallagivencommandinthecontextofagivenclient.
*`activeExpireCycle()`handlesevictionofkeyswithatimetolivesetviathe`EXPIRE`command.
*`performEvictions()`iscalledwhenanewwritecommandshouldbeperformedbutRedisisoutofmemoryaccordingtothe`maxmemory`directive.
*Theglobalvariable`redisCommandTable`definesalltheRediscommands,specifyingthenameofthecommand,thefunctionimplementingthecommand,thenumberofargumentsrequired,andotherpropertiesofeachcommand.

找到 server.c, main 这是总入口

intmain(intargc,char**argv)

aeMain(server.el);//这里面是一个事件循环监听
aeDeleteEventLoop(server.el);

这里接收tcp或socket连接,然后将event及handler放入事件池/bus中。

/*CreateaneventhandlerforacceptingnewconnectionsinTCPorTLSdomainsockets.
*Thisworksatomicallyforallsocketfds*/
intcreateSocketAcceptHandler(socketFds*sfd,aeFileProc*accept_handler){
intj;

for(j=0;j<sfd->count;j++){
if(aeCreateFileEvent(server.el,sfd->fd[j],AE_READABLE,accept_handler,NULL)==AE_ERR){
/*Rollback*/
for(j=j-1;j>=0;j--)aeDeleteFileEvent(server.el,sfd->fd[j],AE_READABLE);
returnC_ERR;
}
}
returnC_OK;
}

另起一个终端,运行redis-cli,会链接到redis-server,从而调试redis相关源码。

cdMyCode/redis/redis-6.2.7/
./src/redis-cli

找到ae.c,这里是一个while循环监控命令,用于监听新函数的事件循环处理(server.cmain函数会调用这里)。

voidaeMain(aeEventLoop*eventLoop){
eventLoop->stop=0;
while(!eventLoop->stop){
aeProcessEvents(eventLoop,AE_ALL_EVENTS|
AE_CALL_BEFORE_SLEEP|
AE_CALL_AFTER_SLEEP);
}
}
intaeProcessEvents(aeEventLoop*eventLoop,intflags)

找到connection.c

staticvoidconnSocketEventHandler(structaeEventLoop*el,intfd,void*clientData,intmask)

找到connhelper.c

staticinlineintcallHandler(connection*conn,ConnectionCallbackFunchandler){
connIncrRefs(conn);
if(handler)handler(conn);
connDecrRefs(conn);
if(conn->flags&CONN_FLAG_CLOSE_SCHEDULED){
if(!connHasRefs(conn))connClose(conn);
return0;
}
return1;

找到networking.cprocessInputBufferprocessCommandAndResetClient 处打断点

intprocessCommandAndResetClient(client*c){
intdeadclient=0;
client*old_client=server.current_client;
server.current_client=c;
if(processCommand(c)==C_OK){
commandProcessed(c);
}

找到server.c,在 processCommandcall等处打断点

处理命令的总入口。

intprocessCommand(client*c)

经过了moduleCallCommandFilters、检查是否是quitlookupCommandauthRequiredACLCheckAllPermcluster_enabledserver.maxmemorywriteCommandsDeniedByDiskErrorrejectCommandblockClient等一系列安全检查逻辑后,来到了执行命令的地方

c->cmd=c->lastcmd=lookupCommand(c->argv[0]->ptr);
...
...
/*Execthecommand*/
if(c->flags&CLIENT_MULTI&&
c->cmd->proc!=execCommand&&c->cmd->proc!=discardCommand&&
c->cmd->proc!=multiCommand&&c->cmd->proc!=watchCommand&&
c->cmd->proc!=resetCommand)
{
queueMultiCommand(c);
addReply(c,shared.queued);
}else{
call(c,CMD_CALL_FULL);
c->woff=server.master_repl_offset;
if(listLength(server.ready_keys))
handleClientsBlockedOnKeys();
}

voidcall(client*c,intflags)
...
server.in_nested_call++;
c->cmd->proc(c);
server.in_nested_call--;

找到t_string.c

setCommand

处理命令的堆栈信息如下:

此后将结果写回到客户端

intwriteToClient(client*c,inthandler_installed){
/*Updatetotalnumberofwritesonserver*/
atomicIncr(server.stat_total_writes_processed,1);

返回结果的堆栈信息如下:

从上面的调试以及堆栈信息可以看出,处理结果和将结果写回到客户端是在两个事件中处理的。

总结redis服务端整个程序流程图如下:

七、环境问题解决
  • gcc : 依赖: gcc-7(>= 7.3.0-12~) 但是它将不会被安装

sudoapt-getinstallgcc
出现如下错误:
正在读取软件包列表…完成
正在分析软件包的依赖关系树
正在读取状态信息…完成
有一些软件包无法被安装。如果您用的是unstable发行版,这也许是
因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件
包尚未被创建或是它们已被从新到(Incoming)目录移出。
下列信息可能会对解决问题有所帮助:
下列软件包有未满足的依赖关系:
gcc:依赖:gcc-7(>=7.3.0-12~)但是它将不会被安装
E:无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

使用aptitude包依赖管理工具代替apt来处理,aptitude软件包管理工具在解决依赖性问题上更有优势,具体使用方法如下:
sudoapt-getinstallaptitude
sudoaptitudeinstallgccg++
终端中输入后会提示aptitude给出的解决方案,可以选择no,
会继续提供下一个解决方案,但前面的方案会是忽略掉依赖冲突,所以想要彻底解决的话可以跳过前面的几种方案,然后再yes解决。(个人第一次No,第二次Yes)
blog.csdn.net/zhutingting0428/article/details/51120949

  • linux ubuntu gcc编译 fatal error: bits/libc-header-start.h 错误解决

apt-getinstallgcc-multilib

其实主要是gcc安装环境没有安装完善Multilib,顾名思义,就是多重的。 用它完全可以替代原来单一的lib。 这样就既能产生32位的代码,又能生成64位的。比如:64bit机器,同时可以产生32和64两种格式,

八、引用资料
  • gcc优化选项-O1-O2-O3-Os优先级
  • 浅析Makefile、make、cmake
  • Debug Redis in VsCode with Gdb
  • 用 gdb 调试 redis
  • Ubuntu下配置VS Code C++ 环境
  • ubuntu18.04+VScode使用记录(持续更新
  • 在vscode中配置C/C++环境
  • how-to-install-and-configure-redis-on-ubuntu-20-04
  • Redis命令set学习(一)

这篇文章整理了一个从服务端和客户端两个维度流程图片

九、转载请注明出处
  • www.cnblogs.com/fancunwei
  • ”威行云栈“公众号(微信号:fundeway)