Redis 拥有它自己的事件驱动模块,叫做 ae.c 。想要理解 Redis 的事件模块最好的办法是弄懂 Redis 是如何调用这个模块的。
以 epoll
为例,从 Event Loop Initialization 说起。
redis 的 initServer
函数初始化了很多 redis 服务器的 struct 。其中一个 struct 叫做 aeEventLoop *el
, 定义在 ae.h
文件中:
1 | /* State of an event based program */ |
通过调用 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
成员中,timeEventHead
是 aeEventLoop
的成员变量,初始化服务后存储在 server.el
中。timeEventHead
指向一系列定时事件的地址。
接下来的内容是:
aeCreateFileEvent
Event Loop Processing
processTimeEvents
以后有空再更…