Files
redis-docs/docs/RedisEventLibrary.rst
Kenneth Reitz 525e9fd3d3 all into sphinx
2011-04-06 13:27:48 -04:00

181 lines
7.4 KiB
ReStructuredText
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
`|Redis Documentation| <index.html>`_
**RedisEventLibrary: Contents**
  `Redis Event Library <#Redis%20Event%20Library>`_
    `Event Loop Initialization <#Event%20Loop%20Initialization>`_
      `aeCreateEventLoop <#aeCreateEventLoop>`_
      `aeCreateTimeEvent <#aeCreateTimeEvent>`_
      `aeCreateFileEvent <#aeCreateFileEvent>`_
    `Event Loop Processing <#Event%20Loop%20Processing>`_
      `aeProcessEvents <#aeProcessEvents>`_
      `processTimeEvents <#processTimeEvents>`_
RedisEventLibrary
=================
#sidebar `RedisInternals <RedisInternals.html>`_
Redis Event Library
===================
Redis implements its own event library. The event library is
implemented in **ae.c**.
The best way to understand how the Redis event library works is to
understand how Redis uses it.
Event Loop Initialization
-------------------------
``initServer`` function defined in **redis.c** initializes the
numerous fields of the ``redisServer`` structure variable. One such
field is the Redis event loop ``el``:
::
aeEventLoop *el
``initServer`` initializes ``server.el`` field by calling
``aeCreateEventLoop`` defined in **ae.c**. The definition of
``aeEventLoop`` is below:
::
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;
aeCreateEventLoop
~~~~~~~~~~~~~~~~~
``aeCreateEventLoop`` first mallocs aeEventLoop structure then
calls
ae\_epoll.c:aeApiCreate``.``aeApiCreate``mallocs``aeApiState``that has two fields -``epfd``that holds the epoll file descriptor returned by a call from [http://man.cx/epoll_create%282%29 epoll_create] and``events``that is of type``struct
epoll\_event``define by the Linux epoll library. The use of the``events``field will be described later. Next is 'ae.c:aeCreateTimeEvent``.
But before that ``initServer`` call ``anet.c:anetTcpServer`` that
creates and returns a *listening descriptor*. The descriptor is
listens to **port 6379** by default. The returned
*listening descriptor* is stored in ``server.fd`` field.
aeCreateTimeEvent
~~~~~~~~~~~~~~~~~
``aeCreateTimeEvent`` accepts the following as parameters:
- eventLoop: This is ``server.el`` in **redis.c**
- milliseconds: The number of milliseconds from the curent time
after which the timer expires.
- proc: Function pointer. Stores the address of the function that
has to be called after the timer expires.
- clientData: Mostly NULL.
- finalizerProc: Pointer to the function that has to be called
before the timed event is removed from the list of timed events.
``initServer`` calls ``aeCreateTimeEvent`` to add a timed event to
``timeEventHead`` field of ``server.el``. ``timeEventHead`` is a
pointer to a list of such timed events. The call to
``aeCreateTimeEvent`` from ``redis.c:initServer`` function is given
below:
::
aeCreateTimeEvent(server.el /*eventLoop*/, 1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);
``redis.c:serverCron`` performs many operations that helps keep
Redis running properly.
aeCreateFileEvent
~~~~~~~~~~~~~~~~~
The essence of ``aeCreateFileEvent`` function is to execute
`epoll\_ctl <http://man.cx/epoll_ctl>`_ system call which adds a
watch for ``EPOLLIN`` event on the *listening descriptor* create by
``anetTcpServer`` and associate it with the epoll descriptor
created by a call to ``aeCreateEventLoop``.
Following is an explanation of what precisely ``aeCreateFileEvent``
does when called from ``redis.c:initServer``.
``initServer`` passes the following arguments to
``aeCreateFileEvent``:
- server.el: The event loop created by ``aeCreateEventLoop``. The
epoll descriptor is got from server.el.
- server.fd: The *listening descriptor* that also serves as an
index to access the relevant file event structure from the
``eventLoop->events`` table and store extra information like the
callback function.
- AE\_READABLE: Signifies that server.fd has to be watched for
EPOLLIN event.
- acceptHandler: The function that has to be executed when the
event being watched for is ready. This function pointer is stored
in ``eventLoop->events[server.fd]->rfileProc``.
This completes the initialization of Redis event loop.
Event Loop Processing
---------------------
``ae.c:aeMain`` called from ``redis.c:main`` does the job of
processing the event loop that is initialized in the previous
phase.
``ae.c:aeMain`` calls ``ae.c:aeProcessEvents`` in a while loop that
processes pending time and file events.
aeProcessEvents
~~~~~~~~~~~~~~~
``ae.c:aeProcessEvents`` looks for the time event that will be
pending in the smallest amount of time by calling
``ae.c:aeSearchNearestTimer`` on the event loop. In our case there
is only one timer event in the event loop that was created by
``ae.c:aeCreateTimeEvent``.
Remember, that timer event created by ``aeCreateTimeEvent`` 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 ``tvp`` timeval structure variable is
initialized to zero.
The ``tvp`` structure variable along with the event loop variable
is passed to ``ae_epoll.c:aeApiPoll``.
``aeApiPoll`` functions does a
`epoll\_wait <http://man.cx/epoll_wait>`_ on the epoll descriptor
and populates the ``eventLoop->fired`` table with the details:
- fd: The descriptor that is now ready to do a read/write
operation depending on the mask value. The
- mask: The read/write event that can now be performed on the
corresponding descriptor.
``aeApiPoll`` 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 ``eventLoop->fired`` table with an entry of the
descriptor being the *listening descriptor* and mask being
``AE_READABLE``.
Now, ``aeProcessEvents`` calls the ``redis.c:acceptHandler``
registered as the callback. ``acceptHandler`` executes
[`http://man.cx/accept(2 <http://man.cx/accept(2>`_) accept] on the
*listening descriptor* returning a *connected descriptor* with the
client. ``redis.c:createClient`` adds a file event on the
*connected descriptor* through a call to ``ae.c:aeCreateFileEvent``
like below:
::
if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
readQueryFromClient, c) == AE_ERR) {
freeClient(c);
return NULL;
}
``c`` is the ``redisClient`` structure variable and ``c->fd`` is
the connected descriptor.
Next the ``ae.c:aeProcessEvent`` calls ``ae.c:processTimeEvents``
processTimeEvents
~~~~~~~~~~~~~~~~~
``ae.processTimeEvents`` iterates over list of time events starting
at ``eventLoop->timeEventHead``.
For every timed event that has elapsed ``processTimeEvents`` calls
the registered callback. In this case it calls the only timed event
callback registered, that is, ``redis.c:serverCron``. The callback
returns the time in milliseconds after which the callback must be
called again. This change is recorded via a call to
``ae.c:aeAddMilliSeconds`` and will be handled on the next
iteration of ``ae.c:aeMain`` while loop.
That's all.
.. |Redis Documentation| image:: redis.png