Redis 拥有它自己的事件驱动模块,叫做 ae.c 。想要理解 Redis 的事件模块最好的办法是弄懂 Redis 是如何调用这个模块的。

epoll 为例,从 Event Loop Initialization 说起。

redis 的 initServer 函数初始化了很多 redis 服务器的 struct 。其中一个 struct 叫做 aeEventLoop *el , 定义在 ae.h 文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* State of an event based program */
typedef struct aeEventLoop {
int maxfd; /* highest file descriptor currently registered */
int setsize; /* 最多能监听的文件描述法个数 */
long long timeEventNextId;
time_t lastTime; /* Used to detect system clock skew */
aeFileEvent *events; /* Registered events 文件事件的数组 */
aeFiredEvent *fired; /* Fired events */
aeTimeEvent *timeEventHead;
int stop;
void *apidata; /* This is used for polling API specific data */
aeBeforeSleepProc *beforesleep;
aeBeforeSleepProc *aftersleep;
} aeEventLoop;

通过调用 ae.c 文件中的 aeCreateEventLoop 函数,initServer 定义了 server.el 值。
aeCreateEventLoop 先用 malloc 函数给 aeEventLoop 分配了内存,然后调用了 ae_epoll.c 文件中的 aeApiCreate 函数。aeApiCreate 函数给 aeApiState struct 分配相应的内存。
aeApiState 有两个成员,分别是:

  • epfd: 用来存储通过 epoll 触发生成的文件描述符。文件描述符通过调用 Linux kernel 的 epoll_create 函数生成。
  • epoll_event: 成员 epoll_event 通过 linux kernel 中的 epoll 定义。

aeCreateTimeEvent

1
aeCreateTimeEvent(server.el /*eventLoop*/, 1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);

新建定时事件通过调用 ae.c 文件中的 aeCreateTimeEvent 来实现。在我们初始化服务器之前,先需要调用 anet.c 文件中的 anetTcpServer 函数来新建并监听 socket 连接, socket 连接的默认端口是6379,socket 的文件描述符将会在 server.fd 成员中存储。

aeCreateTimeEvent 函数接受的参数包括以下几个:

  • eventLoop
  • milliseconds: 存储定时器有效毫秒时间
  • proc: 函数指针,存储定时器到期后需要调用的函数的地址。
  • clientData: 常常为空
  • finalizerProc: 指向定时事件从定时事件列表中被删除之前必须被调用的函数的地址。

initServer 调用 aeCreateTimeEvent 来新建定时事件到 timeEventHead 成员中,timeEventHeadaeEventLoop 的成员变量,初始化服务后存储在 server.el 中。timeEventHead 指向一系列定时事件的地址。

接下来的内容是:

aeCreateFileEvent
Event Loop Processing
processTimeEvents

以后有空再更…