Redis Event Library (事件库)-翻译

Redis implements its own event library. The event library is implemented in ae.c.

redis实现了自己的事件库,这个事件库实现类在ae.c中

The best way to understand how the Redis event library works is to understand how Redis uses it.

理解redis事件库怎么工作的最好方式是理解redis怎么使用了它

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 mallocaeEventLoop structure then calls ae_epoll.c:aeApiCreate.

aeCreateEventLoop 首先分配 aeEventLoop 结构体,然后调用 ae_epoll.c:aeApiCreate

aeApiCreate mallocaeApiState that has two fields - epfd that holds the epoll file descriptor

aeApiCreate 分配 aeApiState ,它的epfd 字段绑定了一个 epoll  的文件描述符

returned by a call from 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 listens on port 6379 by default. The returned listening descriptor is stored in server.fd field.

redis的事件库是依赖linux的epoll 模型,自己封装的一套事件库

aeCreateTimeEvent 创建定时事件的参数

aeCreateTimeEvent accepts the following as parameters:

  • eventLoop: This is server.el in redis.c  执行定时事件的eventLoop
  • milliseconds: The number of milliseconds from the current 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.eltimeEventHead is a pointer to a list of such timed events. The call to aeCreateTimeEvent from redis.c:initServer function is given below:

initServer初始化服务 调用 aeCreateTimeEvent  创建一个定时事件赋值给server.el的timeEventHead字段
timeEventHead
 是一个指针,它执行一个定时事件列表,所有的定时事件都存到这里面。

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

aeCreateFileEvent 本质上是通过  epoll_ctl 系统调用监听一个EPOLLIN event 事件,这个EPOLLIN event就是一个被anetTcpServer 创建的fd描述符,关联通过epoll 创建的aeCreateEventLoop描述符。
有点绕,用自己的话理解就是:
 aeCreateEventLoop创建的时候通过epoll_creat创建了描述符fd0,然后aeCreateFileEvent将EPOLLIN 事件绑定的fd1,fd2.....描述符添加到fd0中,fd0来监听管理,模型可以参考:

【多路复用器 - 3】epoll_泰山与水-CSDN博客

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.当监听的事件fd准备好了后执行的回调函数

This completes the initialization of Redis event loop.
这就完成了Redis事件循环的初始化。

  • Event Loop本身初始化
  • 初始化定时任务事件aeCreateTimeEvent
  • 初始化文件事件aeCreateFileEvent

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中开启一个while循环,在循环中处理事件事件和文件事件

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 the timer event created by aeCreateTimeEvent has probably elapsed by now because it had an 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.

创建定时事件的时候,如果和当前事件比较,创建好了久过期了,时间字段久直接设置成0
 

The tvp structure variable along with the event loop variable is passed to ae_epoll.c:aeApiPoll.

aeApiPoll functions does an epoll_wait on the epoll descriptor and populates the eventLoop->fired table with the details:通过包装系统调用epoll_wait非阻塞获取准备好的fd列表

  • fd: The descriptor that is now ready to do a read/write operation depending on the mask value.
  • 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 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.

redis.c:serverCron 执行时间事件,每次执行返回下一次过多久再执行

That's all. 就这些吧!

  • redis的事件库就是封装了linux的epoll系统调用,自己搞了一套事件模型
  • 通过一个主eventLoop来执行文件事件和定时事件
  • 文件事件就是fd的监听和回调处理
  • 时间事件就是按照过期时间来创建的一个时间轮模型,A定时10s后执行,B定时20s后执行,C定时50s后执行,ABC按照过期时间的先后顺序组成一个时间环,主函数循环打捞执行
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值