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 }
时间: 2024-12-06 18:38:34

Redis事件管理(一)的相关文章

Redis事件管理(二)

Redis的定时器是自己实现的,不是很复杂.说说具体的实现吧. 定时器的存储维护采用的是普通的单向链表结构,具体节点定义为: 1 /*时间定时器结构体*/ 2 typedef struct aeTimeEvent 3 { 4 long long id; /*定时器的编号*/ 5 long when_sec; /* seconds */ 6 long when_ms; /* milliseconds */ 7 aeTimeProc *timeProc;/*时间到达处理函数*/ 8 aeEventF

Redis 内存管理与事件处理

1 Redis内存管理 Redis内存管理相关文件为zmalloc.c/zmalloc.h,其只是对C中内存管理函数做了简单的封装,屏蔽了底层平台的差异,并增加了内存使用情况统计的功能. void *zmalloc(size_t size) {    // 多申请的一部分内存用于存储当前分配了多少自己的内存     void *ptr = malloc(size+PREFIX_SIZE);      if (!ptr) zmalloc_oom_handler(size); #ifdef HAVE

Redis事件

Redis事件 Redis的ae(Redis用的事件模型库) ae.c Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件: 文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象. 时间事件(time event):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象. 一.文件事件 Redis基于Reactor模式(将消

几款开源的图形化Redis客户端管理软件

您的评价: 收藏该经验 阅读目录 Redis Desktop Manager Redis Client Redis Studio 原文  http://ourjs.com/detail/555975b9329934463f00000f Redis是一个超精简的基于内存的键值对数据库(key-value),一般对并发有一定要求的应用都用其储存session,乃至整个数据库. 参见: node.js与redis结合使用 . 不过它公自带一个最小化的命令行式的数据库管理工具,有时侯使用起来并不方便.不

事件管理器

项目开发过程中经常会用到代理事件,为方便管理,避免代码混乱,需要一个总的事件管理器: using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public class EventManager<T> { private static Dictionary<EventType,List<Action<T>>> eventDic =

redis启动管理脚本

亲测好用的redis启动管理脚本,如果使用需要根据自己安装的redis相关文件进行调整 我是源码安装的redis-3.0.5 安装路径/usr/local/redis 编辑创建脚本文件: vim /etc/init.d/redis #!/bin/sh # # chkconfig:   2345 85 15   # description: this script can manager the redis-server daemon #              Redis is a persi

vue30-单一事件管理组件通信: vuex

------------------------------------------------------ 可以单一事件管理组件通信: vuex var Event=new Vue(); Event.$emit(事件名称, 数据) Event.$on(事件名称,function(data){ //data }.bind(this)); <!DOCTYPE html> <html lang="en"> <head> <meta charset=

MIT 2012分布式课程基础源码解析-事件管理封装

这部分的内容主要包括Epoll/select的封装,在封装好相应函数后,再使用一个类来管理相应事件,实现的文件为pollmgr.{h, cc}. 事件函数封装 可看到pollmgr.h文件下定一个了一个虚基类aio_mgr 1 class aio_mgr { 2 public: 3 virtual void watch_fd(int fd, poll_flag flag) = 0; 4 virtual bool unwatch_fd(int fd, poll_flag flag) = 0; 5

Backbone事件管理——Backbone.Events模块API结构

模块Backbone.Events的事件管理是通过Backbone提供的Events API来实现的,该API在1.0版本之前仅仅提供了几个基本的方法,如on.off.trigger.once分别执行对事件的绑定.解除绑定.执行事件.执行一次事件的操作.从1.0版本以后,又添加了几个实用方法,如listenTo.listenToOnce.stopListening,分别执行添加一个事件的侦察对象.添加一个仅执行一次的事件侦察对象和移除已添加的事件侦察对象,其完整的结构如图3-1所示. Backb