]>
Commit | Line | Data |
---|---|---|
aed57a31 | 1 | |
2 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> | |
3 | <html> | |
4 | <head> | |
5 | <link type="text/css" rel="stylesheet" href="style.css" /> | |
6 | </head> | |
7 | <body> | |
8 | <div id="page"> | |
9 | ||
10 | <div id='header'> | |
11 | <a href="index.html"> | |
12 | <img style="border:none" alt="Redis Documentation" src="redis.png"> | |
13 | </a> | |
14 | </div> | |
15 | ||
16 | <div id="pagecontent"> | |
17 | <div class="index"> | |
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> | |
20 | </div> | |
21 | ||
22 | <h1 class="wikiname">RedisEventLibrary</h1> | |
23 | ||
24 | <div class="summary"> | |
25 | ||
26 | </div> | |
27 | ||
28 | <div class="narrow"> | |
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"> | |
31 | aeEventLoop *el | |
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 | |
35 | { | |
36 | int maxfd; | |
37 | long long timeEventNextId; | |
38 | aeFileEvent events[AE_SETSIZE]; /* Registered events */ | |
39 | aeFiredEvent fired[AE_SETSIZE]; /* Fired events */ | |
40 | aeTimeEvent *timeEventHead; | |
41 | int stop; | |
42 | void *apidata; /* This is used for polling API specific data */ | |
43 | aeBeforeSleepProc *beforesleep; | |
44 | } aeEventLoop; | |
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">. | |
46 | ||
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. | |
48 | ||
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) { | |
59 | freeClient(c); | |
60 | return NULL; | |
61 | } | |
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. | |
63 | ||
64 | </div> | |
65 | ||
66 | </div> | |
67 | </div> | |
68 | </body> | |
69 | </html> | |
70 |