2 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01//EN">
5 <link type=
"text/css" rel=
"stylesheet" href=
"style.css" />
12 <img style=
"border:none" alt=
"Redis Documentation" src=
"redis.png">
16 <div id=
"pagecontent">
18 <!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
19 <b>RedisEventLibrary: Contents
</b><br> <a href=
"#Redis Event Library">Redis Event Library
</a><br> <a href=
"#Event Loop Initialization">Event Loop Initialization
</a><br> <a href=
"#aeCreateEventLoop">aeCreateEventLoop
</a><br> <a href=
"#aeCreateTimeEvent">aeCreateTimeEvent
</a><br> <a href=
"#aeCreateFileEvent">aeCreateFileEvent
</a><br> <a href=
"#Event Loop Processing">Event Loop Processing
</a><br> <a href=
"#aeProcessEvents">aeProcessEvents
</a><br> <a href=
"#processTimeEvents">processTimeEvents
</a>
22 <h1 class=
"wikiname">RedisEventLibrary
</h1>
29 #sidebar
<a href=
"RedisInternals.html">RedisInternals
</a><h1><a name=
"Redis Event Library">Redis Event Library
</a></h1>Redis implements its own event library. The event library is implemented in
<b>ae.c
</b>.
<br/><br/>The best way to understand how the Redis event library works is to understand how Redis uses it.
<h2><a name=
"Event Loop Initialization">Event Loop Initialization
</a></h2>
30 <code name=
"code" class=
"python">initServer
</code> function defined in
<b>redis.c
</b> initializes the numerous fields of the
<code name=
"code" class=
"python">redisServer
</code> structure variable. One such field is the Redis event loop
<code name=
"code" class=
"python">el
</code>:
<br/><br/><pre class=
"codeblock python" name=
"code">
32 </pre><code name=
"code" class=
"python">initServer
</code> initializes
<code name=
"code" class=
"python">server.el
</code> field by calling
<code name=
"code" class=
"python">aeCreateEventLoop
</code> defined in
<b>ae.c
</b>. The definition of
<code name=
"code" class=
"python">aeEventLoop
</code> is below:
33 <pre class=
"codeblock python python" name=
"code">
34 typedef struct aeEventLoop
37 long long timeEventNextId;
38 aeFileEvent events[AE_SETSIZE]; /* Registered events */
39 aeFiredEvent fired[AE_SETSIZE]; /* Fired events */
40 aeTimeEvent *timeEventHead;
42 void *apidata; /* This is used for polling API specific data */
43 aeBeforeSleepProc *beforesleep;
45 </pre><h3><a name=
"aeCreateEventLoop">aeCreateEventLoop
</a></h3><code name=
"code" class=
"python">aeCreateEventLoop
</code> first mallocs aeEventLoop structure then calls ae_epoll.c:aeApiCreate
<code name=
"code" class=
"python">.
47 </code>aeApiCreate
<code name=
"code" class=
"python"> mallocs
</code>aeApiState
<code name=
"code" class=
"python"> that has two fields -
</code>epfd
<code name=
"code" class=
"python"> that holds the epoll file descriptor returned by a call from [http://man.cx/epoll_create%
282%
29 epoll_create] and
</code>events
<code name=
"code" class=
"python"> that is of type
</code>struct epoll_event
<code name=
"code" class=
"python"> define by the Linux epoll library. The use of the
</code>events
<code name=
"code" class=
"python"> field will be described later.
49 Next is 'ae.c:aeCreateTimeEvent
</code>. But before that
<code name=
"code" class=
"python">initServer
</code> call
<code name=
"code" class=
"python">anet.c:anetTcpServer
</code> that creates and returns a
<i>listening descriptor
</i>. The descriptor is listens to
<b>port
6379</b> by default. The returned
<i>listening descriptor
</i> is stored in
<code name=
"code" class=
"python">server.fd
</code> field.
<h3><a name=
"aeCreateTimeEvent">aeCreateTimeEvent
</a></h3><code name=
"code" class=
"python">aeCreateTimeEvent
</code> accepts the following as parameters:
<br/><br/><ul><li> eventLoop: This is
<code name=
"code" class=
"python">server.el
</code> in
<b>redis.c
</b></li><li> milliseconds: The number of milliseconds from the curent time after which the timer expires.
</li><li> proc: Function pointer. Stores the address of the function that has to be called after the timer expires.
</li><li> clientData: Mostly NULL.
</li><li> finalizerProc: Pointer to the function that has to be called before the timed event is removed from the list of timed events.
</li></ul>
50 <code name=
"code" class=
"python">initServer
</code> calls
<code name=
"code" class=
"python">aeCreateTimeEvent
</code> to add a timed event to
<code name=
"code" class=
"python">timeEventHead
</code> field of
<code name=
"code" class=
"python">server.el
</code>.
<code name=
"code" class=
"python">timeEventHead
</code> is a pointer to a list of such timed events. The call to
<code name=
"code" class=
"python">aeCreateTimeEvent
</code> from
<code name=
"code" class=
"python">redis.c:initServer
</code> function is given below:
<br/><br/><pre class=
"codeblock python python python" name=
"code">
51 aeCreateTimeEvent(server.el /*eventLoop*/,
1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);
52 </pre><code name=
"code" class=
"python">redis.c:serverCron
</code> performs many operations that helps keep Redis running properly.
<h3><a name=
"aeCreateFileEvent">aeCreateFileEvent
</a></h3>The essence of
<code name=
"code" class=
"python">aeCreateFileEvent
</code> function is to execute
<a href=
"http://man.cx/epoll_ctl" target=
"_blank">epoll_ctl
</a> system call which adds a watch for
<code name=
"code" class=
"python">EPOLLIN
</code> event on the
<i>listening descriptor
</i> create by
<code name=
"code" class=
"python">anetTcpServer
</code> and associate it with the epoll descriptor created by a call to
<code name=
"code" class=
"python">aeCreateEventLoop
</code>.
<br/><br/>Following is an explanation of what precisely
<code name=
"code" class=
"python">aeCreateFileEvent
</code> does when called from
<code name=
"code" class=
"python">redis.c:initServer
</code>.
<br/><br/><code name=
"code" class=
"python">initServer
</code> passes the following arguments to
<code name=
"code" class=
"python">aeCreateFileEvent
</code>:
53 <ul><li> server.el: The event loop created by
<code name=
"code" class=
"python">aeCreateEventLoop
</code>. The epoll descriptor is got from server.el.
</li><li> server.fd: The
<i>listening descriptor
</i> that also serves as an index to access the relevant file event structure from the
<code name=
"code" class=
"python">eventLoop-
>events
</code> table and store extra information like the callback function.
</li><li> AE_READABLE: Signifies that server.fd has to be watched for EPOLLIN event.
</li><li> acceptHandler: The function that has to be executed when the event being watched for is ready. This function pointer is stored in
<code name=
"code" class=
"python">eventLoop-
>events[server.fd]-
>rfileProc
</code>.
</li></ul>
54 This completes the initialization of Redis event loop.
<h2><a name=
"Event Loop Processing">Event Loop Processing
</a></h2><code name=
"code" class=
"python">ae.c:aeMain
</code> called from
<code name=
"code" class=
"python">redis.c:main
</code> does the job of processing the event loop that is initialized in the previous phase.
<br/><br/><code name=
"code" class=
"python">ae.c:aeMain
</code> calls
<code name=
"code" class=
"python">ae.c:aeProcessEvents
</code> in a while loop that processes pending time and file events.
<h3><a name=
"aeProcessEvents">aeProcessEvents
</a></h3><code name=
"code" class=
"python">ae.c:aeProcessEvents
</code> looks for the time event that will be pending in the smallest amount of time by calling
<code name=
"code" class=
"python">ae.c:aeSearchNearestTimer
</code> on the event loop. In our case there is only one timer event in the event loop that was created by
<code name=
"code" class=
"python">ae.c:aeCreateTimeEvent
</code>.
<br/><br/>Remember, that timer event created by
<code name=
"code" class=
"python">aeCreateTimeEvent
</code> has by now probably elapsed because it had a expiry time of one millisecond. Since, the timer has already expired the seconds and microseconds fields of the
<code name=
"code" class=
"python">tvp
</code> timeval structure variable is initialized to zero.
<br/><br/>The
<code name=
"code" class=
"python">tvp
</code> structure variable along with the event loop variable is passed to
<code name=
"code" class=
"python">ae_epoll.c:aeApiPoll
</code>.
<br/><br/><code name=
"code" class=
"python">aeApiPoll
</code> functions does a
<a href=
"http://man.cx/epoll_wait" target=
"_blank">epoll_wait
</a> on the epoll descriptor and populates the
<code name=
"code" class=
"python">eventLoop-
>fired
</code> table with the details:
55 <ul><li> fd: The descriptor that is now ready to do a read/write operation depending on the mask value. The
</li><li> mask: The read/write event that can now be performed on the corresponding descriptor.
</li></ul>
56 <code name=
"code" class=
"python">aeApiPoll
</code> returns the number of such file events ready for operation. Now to put things in context, if any client has requested for a connection then aeApiPoll would have noticed it and populated the
<code name=
"code" class=
"python">eventLoop-
>fired
</code> table with an entry of the descriptor being the
<i>listening descriptor
</i> and mask being
<code name=
"code" class=
"python">AE_READABLE
</code>.
<br/><br/>Now,
<code name=
"code" class=
"python">aeProcessEvents
</code> calls the
<code name=
"code" class=
"python">redis.c:acceptHandler
</code> registered as the callback.
<code name=
"code" class=
"python">acceptHandler
</code> executes [
<a href=
"http://man.cx/accept(2" target=
"_blank">http://man.cx/accept(
2</a>) accept] on the
<i>listening descriptor
</i> returning a
<i>connected descriptor
</i> with the client.
<code name=
"code" class=
"python">redis.c:createClient
</code> adds a file event on the
<i>connected descriptor
</i> through a call to
<code name=
"code" class=
"python">ae.c:aeCreateFileEvent
</code> like below:
<br/><br/><pre class=
"codeblock python python python python" name=
"code">
57 if (aeCreateFileEvent(server.el, c-
>fd, AE_READABLE,
58 readQueryFromClient, c) == AE_ERR) {
62 </pre><code name=
"code" class=
"python">c
</code> is the
<code name=
"code" class=
"python">redisClient
</code> structure variable and
<code name=
"code" class=
"python">c-
>fd
</code> is the connected descriptor.
<br/><br/>Next the
<code name=
"code" class=
"python">ae.c:aeProcessEvent
</code> calls
<code name=
"code" class=
"python">ae.c:processTimeEvents
</code><h3><a name=
"processTimeEvents">processTimeEvents
</a></h3><code name=
"code" class=
"python">ae.processTimeEvents
</code> iterates over list of time events starting at
<code name=
"code" class=
"python">eventLoop-
>timeEventHead
</code>.
<br/><br/>For every timed event that has elapsed
<code name=
"code" class=
"python">processTimeEvents
</code> calls the registered callback. In this case it calls the only timed event callback registered, that is,
<code name=
"code" class=
"python">redis.c:serverCron
</code>. The callback returns the time in milliseconds after which the callback must be called again. This change is recorded via a call to
<code name=
"code" class=
"python">ae.c:aeAddMilliSeconds
</code> and will be handled on the next iteration of
<code name=
"code" class=
"python">ae.c:aeMain
</code> while loop.
<br/><br/>That's all.