redis是一个事件驱动的服务器,主要处理两类事件:文件事件和时间事件。事件驱动模型的主要数据结构
如下:
/* 文件事件数据结构*/
typedef struct aeFileEvent {
int mask; /* 文件事件的类型:READABLE|WRITABLE */
aeFileProc *rfileProc;//读事件的处理器
aeFileProc *wfileProc;//写事件的处理器
void *clientData;//client相关的数据
} aeFileEvent;
/* 时间时间数据结构 */
typedef struct aeTimeEvent {
long long id; /* 时间事件id */
long when_sec; //时间事件到达的时间,精度为秒
long when_ms; //时间事件到达的时间,精度为毫秒
aeTimeProc *timeProc;//时间事件处理器
aeEventFinalizerProc *finalizerProc;//处理完时间事件的收尾方法
void *clientData;
struct aeTimeEvent *next;//下一个注册的时间事件
} aeTimeEvent;
/* 触发事件的数据结构 */
typedef struct aeFiredEvent {
int fd;
int mask;
} aeFiredEvent;
/* 事件驱动模型的数据结构*/
typedef struct aeEventLoop {
int maxfd; /* 当前注册的文件事件的最大文件描述符*/
int setsize; /* 注册文件事件的文件描述符的最大限制 */
long long timeEventNextId;//下一次注册的时间事件的id
time_t lastTime; /* Used to detect system clock skew */
aeFileEvent *events; /* 注册的文件事件 */
aeFiredEvent *fired; /* 触发的事件*/
aeTimeEvent *timeEventHead;//注册的时间事件
int stop;//用于暂停事件驱动模型
void *apidata;//用于底层封装的多路io
aeBeforeSleepProc *beforesleep;//进入事件驱动等待事件触发前调用的函数
} aeEventLoop;
一、文件事件
服务器与客户端的通信产生的文件事件,而服务器基于reactor模式开发文件事件处理器来完成一系列文件事件的处理。 文件事件处理器主要套接字、I/O多路复用程序、文件事件调度器和文件事件处理器。文件事件是对套接字操作的抽象,套接字准备好执行连接应答、写入、读取,关闭等操作都会产生一个文件事件。
redis的多路复用程序的功能都是通过包装了常见的select、epoll、evport和kqueue这些多路复用函数库来实现。为了接口统一,redis简单封装了这些函数到对应的文件,比如ae_select.c、ae_epoll.c和kqueue.c等文件。
文件事件的注册和撤销主要基于多路复用函数库的aeApiAddEvent和aeApiDelEvent实现。
//对fd进行给定的事件的监听
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData)
{//fd大于事件驱动模型设置的上限
if (fd >= eventLoop->setsize) {
errno = ERANGE;
return AE_ERR;
}
aeFileEvent *fe = &eventLoop->events[fd];
//aeApiAddEvent为简单封装过的多路复用中的事件注册函数
if (aeApiAddEvent(eventLoop, fd, mask) == -1)
return AE_ERR;
fe->mask |= mask;
//注册事件处理器
if (mask & AE_READABLE) fe->rfileProc = proc;
if (mask & AE_WRITABLE) fe->wfileProc = proc;
fe->clientData = clie