Redis事件管理

Posted 扫地猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis事件管理相关的知识,希望对你有一定的参考价值。

Redis统一的时间管理器,同时管理文件事件和定时器,

这个管理器的定义:

#if defined(__APPLE__)
#define HAVE_TASKINFO 1
#endif

/* Test for backtrace() */
#if defined(__APPLE__) || (defined(__linux__) && defined(__GLIBC__))
#define HAVE_BACKTRACE 1
#endif

/* Test for polling API */
#ifdef __linux__
#define HAVE_EPOLL 1
#endif

#if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
#define HAVE_KQUEUE 1
#endif

#ifdef __sun
#include <sys/feature_tests.h>
#ifdef _DTRACE_VERSION
#define HAVE_EVPORT 1
#endif
#endif

/*检查具体使用哪个时间模型,Redis支持四个事件模型*/
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif
#define AE_NONE 0 /*该状态表示事件中该位置没使用*/
#define AE_READABLE 1/*设置了读事件*/
#define AE_WRITABLE 2/*设置了写事件*/

#define AE_FILE_EVENTS 1/*需要监控文件的读事件*/
#define AE_TIME_EVENTS 2/*需要监控文件的写事件*/
#define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS)/*读写事件同事监控*/
#define AE_DONT_WAIT 4/*处理事件时是否设置延迟时间*/

定时器结构体和文件事件结构体

 1 /* File event structure */
 2 typedef struct aeFileEvent 
 3 {
 4     int mask; /*需要监控的读写事件标志位*/
 5     aeFileProc *rfileProc;/*读写事件处理函数*/
 6     aeFileProc *wfileProc;
 7     void *clientData;/*事件参数*/
 8 } aeFileEvent;
 9 
10 /* Time event structure */
11 typedef struct aeTimeEvent 
12 {
13     long long id; /*定时器事件的ID*/
14     long when_sec; /*触发的秒*/
15     long when_ms; /*触发的毫秒*/
16     aeTimeProc *timeProc;/*指定处理函数*/
17     aeEventFinalizerProc *finalizerProc;/*// 定时事件清理函数,当删除定时事件的时候会被调用*/
18     void *clientData;
19     struct aeTimeEvent *next;/*下一个定时器对象,整体采用链表维护,作者好像知道链表维护的效率不是很高,推荐使用跳表,为啥不推荐使用红黑树嘞。*/
20 } aeTimeEvent;

事件管理器的定义

typedef struct aeEventLoop 
{
    int maxfd;   /*事件管理器能管理的文件描述符的最大值*/
    int setsize; /*管理器能管理的文件描述符的个数*/
    long long timeEventNextId; /*定时器用的*/
    time_t lastTime;     /*定时器用的*/
    aeFileEvent *events; /*文件事件数组*/
    aeFiredEvent *fired; /*触发事件数组*/
    aeTimeEvent *timeEventHead;/*定时器链表*/
    int stop;/*该事件管理器是否有效*/
    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep;
} aeEventLoop;

具体的接口函数:

 /*创建一个事件管理器,需要初始化文件事件,触发事件,定时器事件等,stop值默认为0,最大文件描述符值为-1,并将所有的文件描述符的监控事件类型设置为NULL。 */
1
aeEventLoop *aeCreateEventLoop(int setsize) 2 { 3 aeEventLoop *eventLoop; 4 int i; 5 6 if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) 7 goto err; 8 eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);/*给文件事件申请空间*/ 9 eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize); 10 if (eventLoop->events == NULL || eventLoop->fired == NULL) 11 goto err; 12 eventLoop->setsize = setsize;/*设置可处理的事件个数*/ 13 eventLoop->lastTime = time(NULL); 14 eventLoop->timeEventHead = NULL;/*定时器链表初始化*/ 15 eventLoop->timeEventNextId = 0; 16 eventLoop->stop = 0;/*设置停用表示为无效*/ 17 eventLoop->maxfd = -1;/*设置最大文件描述符的初始化*/ 18 eventLoop->beforesleep = NULL; 19 if (aeApiCreate(eventLoop) == -1) 20 goto err; 21 /* Events with mask == AE_NONE are not set. So let‘s initialize the 22 * vector with it. */ 23 for (i = 0; i < setsize; i++) 24 eventLoop->events[i].mask = AE_NONE;/*AE_NONE代表这个事件没有启用*/ 25 return eventLoop; 26 27 err: 28 if (eventLoop) { 29 zfree(eventLoop->events); 30 zfree(eventLoop->fired); 31 zfree(eventLoop); 32 } 33 return NULL; 34 }
/*返回管理器能管理的事件的个数*/
int aeGetSetSize(aeEventLoop *eventLoop) 
{
    return eventLoop->setsize;
}
 1 /*重置管理器能管理的事件个数*/
 2 int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) 
 3 {
 4     int i;
 5     /*如果新大小等于现有的大小则直接返回成*/
 6     if (setsize == eventLoop->setsize) 
 7         return AE_OK;
 8     /*如果重置的大小小于当前管理器中最大的文件描述符大小,则不能进行重置,否则会丢失已经注册的事件。*/
 9     if (eventLoop->maxfd >= setsize) 
10         return AE_ERR;
11     /*调用已经封装好的重置大小函数*/
12     if (aeApiResize(eventLoop,setsize) == -1) 
13         return AE_ERR;
14     /*重置记录内存块大小*/
15     eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize);
16     eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize);
17     eventLoop->setsize = setsize;
18 
19     /*将新增部分的事件标记置为无效*/
20     for (i = eventLoop->maxfd+1; i < setsize; i++)
21         eventLoop->events[i].mask = AE_NONE;
22     return AE_OK;
23 }
 1 /*删除事件控制器*/
 2 void aeDeleteEventLoop(aeEventLoop *eventLoop) 
 3 {
 4     /*调用封装好的删除事件函数*/
 5     aeApiFree(eventLoop);
 6     /*逐个释放内存*/
 7     zfree(eventLoop->events);
 8     zfree(eventLoop->fired);
 9     zfree(eventLoop);
10 }
/*增加一个文件事件,参数为事件控制器,文件描述符,事件掩码,处理函数,函数参数,对一个描述符添加多个事件的时候要挨个添加*/
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
        aeFileProc *proc, void *clientData)
{
    if (fd >= eventLoop->setsize) /*检查新事件的描述符大小是否超过了设置的大小,如果超了,已经申请的内存空间中没有位置,返回错误*/
    {
        errno = ERANGE;
        return AE_ERR;
    }
    aeFileEvent *fe = &eventLoop->events[fd];

    /*设置读写事件的掩码和事件处理函数*/
    if (aeApiAddEvent(eventLoop, fd, mask) == -1)
        return AE_ERR;
    fe->mask |= mask;
    if (mask & AE_READABLE) fe->rfileProc = proc;
    if (mask & AE_WRITABLE) fe->wfileProc = proc;
    fe->clientData = clientData;
    if (fd > eventLoop->maxfd)/*更新文件最大描述符*/
        eventLoop->maxfd = fd;
    return AE_OK;
}
 1 /*删除文件事件中指定文件描述符的指定事件*/
 2 void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
 3 {
 4     /*检查文件描述符是否超限*/
 5     if (fd >= eventLoop->setsize) return;
 6     /*检查该位置是否启用了*/
 7     aeFileEvent *fe = &eventLoop->events[fd];
 8     if (fe->mask == AE_NONE) return;
 9 
10     /*先把事件从处理模型中去掉*/
11     aeApiDelEvent(eventLoop, fd, mask);
12     fe->mask = fe->mask & (~mask);/*去掉读写掩码*/
13     /*检查是否需要更新管理器中的最大文件描述符的值*/
14     if (fd == eventLoop->maxfd && fe->mask == AE_NONE) 
15     {
16         /* Update the max fd */
17         int j;
18         /*从最大位置反向找启用的位置,更新最大文件描述符*/
19         for (j = eventLoop->maxfd-1; j >= 0; j--)
20             if (eventLoop->events[j].mask != AE_NONE) break;
21         eventLoop->maxfd = j;
22     }
23 }
/*获取某个文件描述符的注册事件*/
int aeGetFileEvents(aeEventLoop *eventLoop, int fd) 
{
    if (fd >= eventLoop->setsize) return 0;
    aeFileEvent *fe = &eventLoop->events[fd];

    return fe->mask;
}
 1 /*处理控制器中的所有时间,算是最核心的函数了,参数2为要处理的事件类型*/
 2 int aeProcessEvents(aeEventLoop *eventLoop, int flags)
 3 {
 4     int processed = 0, numevents;
 5 
 6     /*参数2设置的是不处理任何事件就直接返回*/
 7     if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) 
 8         return 0;
 9 
10     /* Note that we want call select() even if there are no
11      * file events to process as long as we want to process time
12      * events, in order to sleep until the next time event is ready
13      * to fire. */
14     if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) 
15     {
16         int j;
17         aeTimeEvent *shortest = NULL;
18         struct timeval tv, *tvp;
19 
20         /*处理文件时间事件,先检查是否需要设置延时时间,
21         延时时间的计算方法,如果有定时器事件,就设定定时器事件里面距离触发事件最近的时间?
22         否则设置成NULL,无限期等待。*/
23         if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
24             shortest = aeSearchNearestTimer(eventLoop);
25         if (shortest) 
26         {
27             long now_sec, now_ms;
28 
29             /* Calculate the time missing for the nearest
30              * timer to fire. */
31             aeGetTime(&now_sec, &now_ms);
32             tvp = &tv;
33             tvp->tv_sec = shortest->when_sec - now_sec;
34             if (shortest->when_ms < now_ms) 
35             {
36                 tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000;
37                 tvp->tv_sec --;
38             } 
39             else 
40             {
41                 tvp->tv_usec = (shortest->when_ms - now_ms)*1000;
42             }
43             if (tvp->tv_sec < 0) tvp->tv_sec = 0;
44             if (tvp->tv_usec < 0) tvp->tv_usec = 0;
45         } 
46         else 
47         {
48             /* If we have to check for events but need to return
49              * ASAP because of AE_DONT_WAIT we need to set the timeout
50              * to zero */
51             if (flags & AE_DONT_WAIT) 
52             {
53                 tv.tv_sec = tv.tv_usec = 0;
54                 tvp = &tv;
55             } 
56             else 
57             {
58                 /* Otherwise we can block */
59                 tvp = NULL; /* wait forever */
60             }
61         }
62 
63         /*调用统一的事件监控接口,并处理*/
64         numevents = aeApiPoll(eventLoop, tvp);
65         for (j = 0; j < numevents; j++) 
66         {
67             aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
68             int mask = eventLoop->fired[j].mask;
69             int fd = eventLoop->fired[j].fd;
70             int rfired = 0;
71 
72             /* note the fe->mask & mask & ... code: maybe an already processed
73              * event removed an element that fired and we still didn‘t
74              * processed, so we check if the event is still valid. */
75             if (fe->mask & mask & AE_READABLE) 
76             {
77                 rfired = 1;
78                 fe->rfileProc(eventLoop,fd,fe->clientData,mask);
79             }
80             if (fe->mask & mask & AE_WRITABLE) 
81             {
82                 if (!rfired || fe->wfileProc != fe->rfileProc)
83                     fe->wfileProc(eventLoop,fd,fe->clientData,mask);
84             }
85             processed++;
86         }
87     }
88     /*检查处理定时器事件*/
89     if (flags & AE_TIME_EVENTS)
90         processed += processTimeEvents(eventLoop);
91 
92     return processed; /* return the number of processed file/time events */
93 }
 1 /*事件管理器总函数,没啥可说的*/
 2 void aeMain(aeEventLoop *eventLoop) 
 3 {
 4     eventLoop->stop = 0;
 5     while (!eventLoop->stop) 
 6     {
 7         if (eventLoop->beforesleep != NULL)
 8             eventLoop->beforesleep(eventLoop);
 9         aeProcessEvents(eventLoop, AE_ALL_EVENTS);
10     }
11 }

以上是关于Redis事件管理的主要内容,如果未能解决你的问题,请参考以下文章

Redis事件管理

Redis事件管理

在每个用户的Rails中使用片段缓存

Redis 内存管理与事件处理

如何使用警报管理器将数据从片段传递到广播接收器

Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段