- 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; }
今天没啥灵感呀。。。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)