想要分析源码,我觉得可以把它当成一个整体,或者一个函数,有输入和对应的输出。我们从输入开始分析流程。先撇开main函数,在gdb上打印下线程的堆栈是个好想法,让我们看看它都在做什么。
可以看得到它其中一条线程阻塞在epoll_wait(我的系统是ubuntu,因此选择了epoll)。在这里检测套接字事件,等待client请求。可以看到还有3条后台io服务线程,它们分别提供异步关闭描述符, 异步调用fsync/fdatasync同步AOF到文件中,异步释放较庞大的键值,如成员比较多的list,set等。由于这些操作比较耗时,或者引起阻塞。因此假设这些操作都在主线程中执行,那么将可能出现短时间无法继续处理client输入。
让我们先看事件驱动框架,主体位于src/ae.c中实现,其框架如下图所示。其依赖于与evport,epoll,kqueue,select模块,每个模块对外提供同一套接口。再依据相应的平台预编译选择对应的模块。这种制定统一的接口,再实现到各个平台,以此隔离上层业务与底层平台相关实现的方案,是值得学习的。
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqu