Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

file 69 lines (58 sloc) 11.774 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
    <head>
        <link type="text/css" rel="stylesheet" href="style.css" />
    </head>
    <body>
        <div id="page">
        
            <div id='header'>
            <a href="index.html">
            <img style="border:none" alt="Redis Documentation" src="redis.png">
            </a>
            </div>
        
            <div id="pagecontent">
                <div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>RedisEventLibrary: Contents</b><br>&nbsp;&nbsp;<a href="#Redis Event Library">Redis Event Library</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Event Loop Initialization">Event Loop Initialization</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#aeCreateEventLoop">aeCreateEventLoop</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#aeCreateTimeEvent">aeCreateTimeEvent</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#aeCreateFileEvent">aeCreateFileEvent</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Event Loop Processing">Event Loop Processing</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#aeProcessEvents">aeProcessEvents</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#processTimeEvents">processTimeEvents</a>
                </div>
                
                <h1 class="wikiname">RedisEventLibrary</h1>

                <div class="summary">
                    
                </div>

                <div class="narrow">
                    &iuml;&raquo;&iquest;#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>
<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">
aeEventLoop *el
</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:
<pre class="codeblock python python" name="code">
typedef struct aeEventLoop
{
    int maxfd;
    long long timeEventNextId;
    aeFileEvent events[AE_SETSIZE]; /* Registered events */
    aeFiredEvent fired[AE_SETSIZE]; /* Fired events */
    aeTimeEvent *timeEventHead;
    int stop;
    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep;
} aeEventLoop;
</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">.

</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.

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>
<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">
aeCreateTimeEvent(server.el /*eventLoop*/, 1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);
</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>:
<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-&gt;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-&gt;events[server.fd]-&gt;rfileProc</code>. </li></ul>
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-&gt;fired</code> table with the details:
<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>
<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-&gt;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">
    if (aeCreateFileEvent(server.el, c-&gt;fd, AE_READABLE,
        readQueryFromClient, c) == AE_ERR) {
        freeClient(c);
        return NULL;
    }
</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-&gt;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-&gt;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.

                </div>
        
            </div>
        </div>
    </body>
</html>
Something went wrong with that request. Please try again.