- redis事件机制概述
- redis的事件循环器:aeEventLoop
- redis启动
- 事件循环
1、redis使用 IO 复用 实现网络通信。
2、在Linux环境下选用epoll模式。
redis的事件循环器:aeEventLoop
acEventLoop 是 redis 的事件循环器,负责管理事件。
typedef struct aeEventLoop {
int maxfd; //当前已注册的最大文件描述符
int setsize; //该事件循环允许监听的最大文件描述符
long long timeEventNextId; //下一个时间事件ID
time_t lastTime; //用于校验系统时钟偏移
aeFileEvent *events; //已注册的文件事件表
aeFiredEvent *fired; //已就绪的事件表
aeTimeEvent *timeEventHead;
int stop;
void *apidata; //用于存放IO复用层的附加数据
aeBeforeSleepProc *beforesleep;
aeBeforeSleepProc *aftersleep;
//进程阻塞前后调用的钩子函数
int flags;
} aeEventLoop;
typedef struct aeFileEvent {
int mask;
aeFileProc *rfileProc;
aeFileProc *wfileProc;
void *clientData; //附加数据
} aeFileEvent;
acFileEvent 中没有 fd 文件描述符的消息,这是一个骚操作我们可以看一下。
首先:
1、POSIX规定了 0/1/2 三个文件描述符的去向
2、POSIX同时还规定了文件描述符的分配方式为递增
依次递增的还有什么?数组的下标嘛。
于是在 aeEventLoop.events 中,以下标为 fd,数组内存储事件。
如果事件已就绪,会被放到 aeEventLoop.fired 中,结构如下:
typedef struct aeFiredEvent {
int fd;
int mask;
} aeFiredEvent;
redis启动
redis启动时,在initServer里面会调用 aeCreateEventLoop 函数创建一个事件循环器,存储于server.el。事件循环器会监听 TCP Socket,并使用指定函数处理读写事件。
redis 启动时也调用 acCreateTimeEvent 函数创建了一个处理函数为 serverCron 的时间事件,负责处理 Redis 中的定时任务。
serverCron 时间事件负责完成大部分内部任务,包括定时持久化、清除过期数据等。另一部分任务在那俩钩子函数中触发。
事件循环
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
int processed = 0, numevents;
if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;
if (eventLoop->maxfd != -1 ||
((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
int j;
aeTimeEvent *shortest = NULL;
struct timeval tv, *tvp;
if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
shortest = aeSearchNearestTimer(eventLoop);
if (shortest) {
long now_sec, now_ms;
aeGetTime(&now_sec, &now_ms);
tvp = &tv;
long long ms =
(shortest->when_sec - now_sec)*1000 +
shortest->when_ms - now_ms;
if (ms > 0) {
tvp->tv_sec = ms/1000;
tvp->tv_usec = (ms % 1000)*1000;
} else {
tvp->tv_sec = 0;
tvp->tv_usec = 0;
}
} else {
if (flags & AE_DONT_WAIT) {
tv.tv_sec = tv.tv_usec = 0;
tvp = &tv;
} else {
tvp = NULL;
}
}
if (eventLoop->flags & AE_DONT_WAIT) {
tv.tv_sec = tv.tv_usec = 0;
tvp = &tv;
}
if (eventLoop->beforesleep != NULL && flags & AE_CALL_BEFORE_SLEEP)
eventLoop->beforesleep(eventLoop);
numevents = aeApiPoll(eventLoop, tvp);
if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP)
eventLoop->aftersleep(eventLoop);
for (j = 0; j < numevents; j++) {
aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
int mask = eventLoop->fired[j].mask;
int fd = eventLoop->fired[j].fd;
int fired = 0;
int invert = fe->mask & AE_BARRIER;
if (!invert && fe->mask & mask & AE_READABLE) {
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
fired++;
fe = &eventLoop->events[fd];
}
if (fe->mask & mask & AE_WRITABLE) {
if (!fired || fe->wfileProc != fe->rfileProc) {
fe->wfileProc(eventLoop,fd,fe->clientData,mask);
fired++;
}
}
if (invert) {
fe = &eventLoop->events[fd];
if ((fe->mask & mask & AE_READABLE) &&
(!fired || fe->wfileProc != fe->rfileProc))
{
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
fired++;
}
}
processed++;
}
}
if (flags & AE_TIME_EVENTS)
processed += processTimeEvents(eventLoop);
return processed;
}
今天没啥灵感呀。。。



