mirror of
https://github.com/kennethreitz-archive/redis-docs.git
synced 2026-06-05 15:30:19 +00:00
181 lines
7.4 KiB
ReStructuredText
181 lines
7.4 KiB
ReStructuredText
`|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 |