深入redis内部--事件处理机制

1. redis事件的定义

maxfd; setsize; *events; *fired; */*定时器事件链表的首部*/ *apidata;
*

  1.1 事件定义

/* File event structure */typedef struct aeFileEvent { int mask; /* one of AE_(READABLE|WRITABLE) */ aeFileProc *rfileProc; aeFileProc *wfileProc; void *clientData;} aeFileEvent;


/* Time event structure */typedef struct aeTimeEvent { long long id; /* time event identifier. */ long when_sec; /* seconds */ long when_ms; /* milliseconds */ aeTimeProc *timeProc; aeEventFinalizerProc *finalizerProc; void *clientData; struct aeTimeEvent *next;} aeTimeEvent;


/* A fired event */typedef struct aeFiredEvent { int fd; int mask;} aeFiredEvent;

2.封装事件处理的实现

 3.事件处理的主函数

aeMain(aeEventLoop *->stop = (!eventLoop-> (eventLoop->beforesleep !=->

  3.1事件处理过程

aeProcessEvents(aeEventLoop *eventLoop, processed = </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Nothing to do? return ASAP </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (!(flags &amp; AE_TIME_EVENTS) &amp;&amp; !(flags &amp; AE_FILE_EVENTS)) <span style="color: #0000ff;"&gt;return</span> <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Note that we want call select() even if there are no * file events to process as long as we want to process time * events,in order to sleep until the next time event is ready * to fire. </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (eventLoop->maxfd != -<span style="color: #800080;"&gt;1</span> ||<span style="color: #000000;"&gt; ((flags </span>&amp; AE_TIME_EVENTS) &amp;&amp; !(flags &amp;<span style="color: #000000;"&gt; AE_DONT_WAIT))) { </span><span style="color: #0000ff;"&gt;int</span><span style="color: #000000;"&gt; j; aeTimeEvent </span>*shortest =<span style="color: #000000;"&gt; NULL; </span><span style="color: #0000ff;"&gt;struct</span> timeval tv,*<span style="color: #000000;"&gt;tvp; </span><span style="color: #0000ff;"&gt;if</span> (flags &amp; AE_TIME_EVENTS &amp;&amp; !(flags &amp;<span style="color: #000000;"&gt; AE_DONT_WAIT)) shortest </span>=<span style="color: #000000;"&gt; aeSearchNearestTimer(eventLoop); </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; (shortest) { </span><span style="color: #0000ff;"&gt;long</span><span style="color: #000000;"&gt; now_sec,now_ms; </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Calculate the time missing for the nearest * timer to fire. </span><span style="color: #008000;"&gt;*/</span><span style="color: #000000;"&gt; aeGetTime(</span>&amp;now_sec,&amp;<span style="color: #000000;"&gt;now_ms); tvp </span>= &amp;<span style="color: #000000;"&gt;tv; tvp</span>->tv_sec = shortest->when_sec -<span style="color: #000000;"&gt; now_sec; </span><span style="color: #0000ff;"&gt;if</span> (shortest->when_ms <<span style="color: #000000;"&gt; now_ms) { tvp</span>->tv_usec = ((shortest->when_ms+<span style="color: #800080;"&gt;1000</span>) - now_ms)*<span style="color: #800080;"&gt;1000</span><span style="color: #000000;"&gt;; tvp</span>->tv_sec --<span style="color: #000000;"&gt;; } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; { tvp</span>->tv_usec = (shortest->when_ms - now_ms)*<span style="color: #800080;"&gt;1000</span><span style="color: #000000;"&gt;; } </span><span style="color: #0000ff;"&gt;if</span> (tvp->tv_sec < <span style="color: #800080;"&gt;0</span>) tvp->tv_sec = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; </span><span style="color: #0000ff;"&gt;if</span> (tvp->tv_usec < <span style="color: #800080;"&gt;0</span>) tvp->tv_usec = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; { </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; If we have to check for events but need to return * ASAP because of AE_DONT_WAIT we need to set the timeout * to zero </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (flags &amp;<span style="color: #000000;"&gt; AE_DONT_WAIT) { tv.tv_sec </span>= tv.tv_usec = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; tvp </span>= &amp;<span style="color: #000000;"&gt;tv; } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; { </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Otherwise we can block </span><span style="color: #008000;"&gt;*/</span><span style="color: #000000;"&gt; tvp </span>= NULL; <span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; wait forever </span><span style="color: #008000;"&gt;*/</span><span style="color: #000000;"&gt; } } numevents </span>=<span style="color: #000000;"&gt; aeApiPoll(eventLoop,tvp); </span><span style="color: #0000ff;"&gt;for</span> (j = <span style="color: #800080;"&gt;0</span>; j < numevents; j++<span style="color: #000000;"&gt;) { aeFileEvent </span>*fe = &amp;eventLoop->events[eventLoop-><span style="color: #000000;"&gt;fired[j].fd]; </span><span style="color: #0000ff;"&gt;int</span> mask = eventLoop-><span style="color: #000000;"&gt;fired[j].mask; </span><span style="color: #0000ff;"&gt;int</span> fd = eventLoop-><span style="color: #000000;"&gt;fired[j].fd; </span><span style="color: #0000ff;"&gt;int</span> rfired = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; note the fe->mask &amp; mask &amp; ... code: maybe an already processed * event removed an element that fired and we still didn't * processed,so we check if the event is still valid. </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (fe->mask &amp; mask &amp;<span style="color: #000000;"&gt; AE_READABLE) { rfired </span>= <span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;; fe</span>->rfileProc(eventLoop,fd,fe-><span style="color: #000000;"&gt;clientData,mask); } </span><span style="color: #0000ff;"&gt;if</span> (fe->mask &amp; mask &amp;<span style="color: #000000;"&gt; AE_WRITABLE) { </span><span style="color: #0000ff;"&gt;if</span> (!rfired || fe->wfileProc != fe-><span style="color: #000000;"&gt;rfileProc) fe</span>->wfileProc(eventLoop,mask); } processed</span>++<span style="color: #000000;"&gt;; } } </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Check time events </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (flags &amp;<span style="color: #000000;"&gt; AE_TIME_EVENTS) processed </span>+=<span style="color: #000000;"&gt; processTimeEvents(eventLoop); </span><span style="color: #0000ff;"&gt;return</span> processed; <span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; return the number of processed file/time events </span><span style="color: #008000;"&gt;*/</span><span style="color: #000000;"&gt;

}

processTimeEvents(aeEventLoop * processed = * =</span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; If the system clock is moved to the future,and then set back to the * right value,time events may be delayed in a random way. Often this * means that scheduled operations will not be performed soon enough. * * Here we try to detect system clock skews,and force all the time * events to be processed ASAP when this happens: the idea is that * processing events earlier is less dangerous than delaying them * indefinitely,and practice suggests it is. </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (now < eventLoop-><span style="color: #000000;"&gt;lastTime) { te </span>= eventLoop-><span style="color: #000000;"&gt;timeEventHead; </span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt;(te) { te</span>->when_sec = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; te </span>= te-><span style="color: #000000;"&gt;next; } } eventLoop</span>->lastTime =<span style="color: #000000;"&gt; now; te </span>= eventLoop-><span style="color: #000000;"&gt;timeEventHead; maxId </span>= eventLoop->timeEventNextId-<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;; </span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt;(te) { </span><span style="color: #0000ff;"&gt;long</span><span style="color: #000000;"&gt; now_sec,now_ms; </span><span style="color: #0000ff;"&gt;long</span> <span style="color: #0000ff;"&gt;long</span><span style="color: #000000;"&gt; id; </span><span style="color: #0000ff;"&gt;if</span> (te->id ><span style="color: #000000;"&gt; maxId) { te </span>= te-><span style="color: #000000;"&gt;next; </span><span style="color: #0000ff;"&gt;continue</span><span style="color: #000000;"&gt;; } aeGetTime(</span>&amp;now_sec,&amp;<span style="color: #000000;"&gt;now_ms); </span><span style="color: #0000ff;"&gt;if</span> (now_sec > te->when_sec ||<span style="color: #000000;"&gt; (now_sec </span>== te->when_sec &amp;&amp; now_ms >= te-><span style="color: #000000;"&gt;when_ms)) { </span><span style="color: #0000ff;"&gt;int</span><span style="color: #000000;"&gt; retval; id </span>= te-><span style="color: #000000;"&gt;id; retval </span>= te->timeProc(eventLoop,id,te-><span style="color: #000000;"&gt;clientData); processed</span>++<span style="color: #000000;"&gt;; </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; After an event is processed our time event list may * no longer be the same,so we restart from head. * Still we make sure to don't process events registered * by event handlers itself in order to don't loop forever. * To do so we saved the max ID we want to handle. * * FUTURE OPTIMIZATIONS: * Note that this is NOT great algorithmically. Redis uses * a single time event so it's not a problem but the right * way to do this is to add the new elements on head,and * to flag deleted elements in a special way for later * deletion (putting references to the nodes to delete into * another linked list). </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (retval !=<span style="color: #000000;"&gt; AE_NOMORE) { aeAddMillisecondsToNow(retval,</span>&amp;te->when_sec,&amp;te-><span style="color: #000000;"&gt;when_ms); } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; { aeDeleteTimeEvent(eventLoop,id); } te </span>= eventLoop-><span style="color: #000000;"&gt;timeEventHead; } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; { te </span>= te-><span style="color: #000000;"&gt;next; } } </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; processed;

}

相关文章

文章浏览阅读1.3k次。在 Redis 中,键(Keys)是非常重要的概...
文章浏览阅读3.3k次,点赞44次,收藏88次。本篇是对单节点的...
文章浏览阅读8.4k次,点赞8次,收藏18次。Spring Boot 整合R...
文章浏览阅读978次,点赞25次,收藏21次。在Centos上安装Red...
文章浏览阅读1.2k次,点赞21次,收藏22次。Docker-Compose部...
文章浏览阅读2.2k次,点赞59次,收藏38次。合理的JedisPool资...