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/*处理事件时是否设置延迟时间*/

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

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

事件管理器的定义,在结构体中维护了两个数组,一个存放设置的文件描述符和设置,一个存放经过检测,满足条件的文件描述符和对应的触发状态,在处理的时候直接处理

fired中的数据就好。

typedef struct aeEventLoop
{
int maxfd; /*事件管理器能管理的文件描述符的最大值*/
int setsize; /*管理器能管理的文件描述符的个数*/
long long timeEventNextId; /*定时器用的*/
time_t lastTime; /*定时器最后一次处理时间,定时器中用的,防止修改了系统时间,影响了定时器的判断。*/
aeFileEvent *events; /*原始事件数组,这里面存放的是开始的文件事件,保存文件描述符,需要监控的事件等信息*/
aeFiredEvent *fired; /*触发事件数组,这里面放的是经过系统判断,有对应事件发生的文件描述符的存放数组,和上面一样,都采用数组维护*/
aeTimeEvent *timeEventHead;/*定时器链表*/
int stop;/*该事件管理器是否有效*/
void *apidata; /*因为事件管理器支持很多模型,每个模型都有自己的特殊数据格式,这个变量就是用来存储模型自己的数据,拿epoll举个例子,这个地方会存储aeApiState节点的信息*/
aeBeforeSleepProc *beforesleep;
} aeEventLoop;

具体的接口函数:

 /*创建一个事件管理器,需要初始化文件事件,触发事件,定时器事件等,stop值默认为0,最大文件描述符值为-1,并将所有的文件描述符的监控事件类型设置为NULL。 */
1 aeEventLoop *aeCreateEventLoop(int setsize)
{
aeEventLoop *eventLoop;
int i; if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL)
goto err;
eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);/*给文件事件申请空间*/
eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
if (eventLoop->events == NULL || eventLoop->fired == NULL)
goto err;
eventLoop->setsize = setsize;/*设置可处理的事件个数*/
eventLoop->lastTime = time(NULL);
eventLoop->timeEventHead = NULL;/*定时器链表初始化*/
eventLoop->timeEventNextId = ;
eventLoop->stop = ;/*设置停用表示为无效*/
eventLoop->maxfd = -;/*设置最大文件描述符的初始化*/
eventLoop->beforesleep = NULL;
if (aeApiCreate(eventLoop) == -)
goto err;
/* Events with mask == AE_NONE are not set. So let's initialize the
* vector with it. */
for (i = ; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;/*AE_NONE代表这个事件没有启用*/
return eventLoop; err:
if (eventLoop) {
zfree(eventLoop->events);
zfree(eventLoop->fired);
zfree(eventLoop);
}
return NULL;
}
/*返回管理器能管理的事件的个数*/
int aeGetSetSize(aeEventLoop *eventLoop)
{
return eventLoop->setsize;
}
 /*重置管理器能管理的事件个数*/
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize)
{
int i;
/*如果新大小等于现有的大小则直接返回成*/
if (setsize == eventLoop->setsize)
return AE_OK;
/*如果重置的大小小于当前管理器中最大的文件描述符大小,则不能进行重置,否则会丢失已经注册的事件。*/
if (eventLoop->maxfd >= setsize)
return AE_ERR;
/*调用已经封装好的重置大小函数*/
if (aeApiResize(eventLoop,setsize) == -)
return AE_ERR;
/*重置记录内存块大小*/
eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize);
eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize);
eventLoop->setsize = setsize; /*将新增部分的事件标记置为无效*/
for (i = eventLoop->maxfd+; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;
return AE_OK;
}
 /*删除事件控制器*/
void aeDeleteEventLoop(aeEventLoop *eventLoop)
{
/*调用封装好的删除事件函数*/
aeApiFree(eventLoop);
/*逐个释放内存*/
zfree(eventLoop->events);
zfree(eventLoop->fired);
zfree(eventLoop);
}
/*增加一个文件事件,参数为事件控制器,文件描述符,事件掩码,处理函数,函数参数,对一个描述符添加多个事件的时候要挨个添加*/
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) == -)
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;
}
 /*删除文件事件中指定文件描述符的指定事件*/
void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
{
/*检查文件描述符是否超限*/
if (fd >= eventLoop->setsize) return;
/*检查该位置是否启用了*/
aeFileEvent *fe = &eventLoop->events[fd];
if (fe->mask == AE_NONE) return; /*先把事件从处理模型中去掉*/
aeApiDelEvent(eventLoop, fd, mask);
fe->mask = fe->mask & (~mask);/*去掉读写掩码*/
/*检查是否需要更新管理器中的最大文件描述符的值*/
if (fd == eventLoop->maxfd && fe->mask == AE_NONE)
{
/* Update the max fd */
int j;
/*从最大位置反向找启用的位置,更新最大文件描述符*/
for (j = eventLoop->maxfd-; j >= ; j--)
if (eventLoop->events[j].mask != AE_NONE) break;
eventLoop->maxfd = j;
}
}
/*获取某个文件描述符的注册事件*/
int aeGetFileEvents(aeEventLoop *eventLoop, int fd)
{
if (fd >= eventLoop->setsize) return ;
aeFileEvent *fe = &eventLoop->events[fd]; return fe->mask;
}
 /*处理控制器中的所有时间,算是最核心的函数了,参数2为要处理的事件类型*/
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
int processed = , numevents; /*参数2设置的是不处理任何事件就直接返回*/
if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS))
return ; /* Note that we want call select() even if there are no
* file events to process as long as we want to process time
* events, in order to sleep until the next time event is ready
* to fire. */
if (eventLoop->maxfd != - || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT)))
{
int j;
aeTimeEvent *shortest = NULL;
struct timeval tv, *tvp; /*处理文件时间事件,先检查是否需要设置延时时间,
延时时间的计算方法,如果有定时器事件,就设定定时器事件里面距离触发事件最近的时间?
否则设置成NULL,无限期等待。*/
if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
shortest = aeSearchNearestTimer(eventLoop);
if (shortest)
{
long now_sec, now_ms; /* Calculate the time missing for the nearest
* timer to fire. */
aeGetTime(&now_sec, &now_ms);
tvp = &tv;
tvp->tv_sec = shortest->when_sec - now_sec;
if (shortest->when_ms < now_ms)
{
tvp->tv_usec = ((shortest->when_ms+) - now_ms)*;
tvp->tv_sec --;
}
else
{
tvp->tv_usec = (shortest->when_ms - now_ms)*;
}
if (tvp->tv_sec < ) tvp->tv_sec = ;
if (tvp->tv_usec < ) tvp->tv_usec = ;
}
else
{
/* If we have to check for events but need to return
* ASAP because of AE_DONT_WAIT we need to set the timeout
* to zero */
if (flags & AE_DONT_WAIT)
{
tv.tv_sec = tv.tv_usec = ;
tvp = &tv;
}
else
{
/* Otherwise we can block */
tvp = NULL; /* wait forever */
}
} /*调用统一的事件监控接口,并处理*/
numevents = aeApiPoll(eventLoop, tvp);
for (j = ; j < numevents; j++)
{
aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
int mask = eventLoop->fired[j].mask;
int fd = eventLoop->fired[j].fd;
int rfired = ; /* note the fe->mask & mask & ... code: maybe an already processed
* event removed an element that fired and we still didn't
* processed, so we check if the event is still valid. */
if (fe->mask & mask & AE_READABLE)
{
rfired = ;
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
}
if (fe->mask & mask & AE_WRITABLE)
{
if (!rfired || fe->wfileProc != fe->rfileProc)
fe->wfileProc(eventLoop,fd,fe->clientData,mask);
}
processed++;
}
}
/*检查处理定时器事件*/
if (flags & AE_TIME_EVENTS)
processed += processTimeEvents(eventLoop); return processed; /* return the number of processed file/time events */
}
 /*事件管理器总函数,没啥可说的*/
void aeMain(aeEventLoop *eventLoop)
{
eventLoop->stop = ;
while (!eventLoop->stop)
{
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}

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

  1. Redis事件管理(二)

    Redis的定时器是自己实现的,不是很复杂.说说具体的实现吧. 定时器的存储维护采用的是普通的单向链表结构,具体节点定义为: /*时间定时器结构体*/ typedef struct aeTimeEve ...

  2. Redis事件管理(三)

    Redis的事件管理和定时器的管理都是自己来实现的,Redis的事件管理分为两部分,一部分是封装了系统的异步事件API,还有一部分是在这基础上封装了一个通用的事件管理器,根据具体的系统来决定具体使用哪 ...

  3. redis的管理工具

    phpredisadmin工具 rdbtools管理工具 saltstack管理redis 通过codis完成redis管理 一:phpredisadmin工具:类似于mysqladmin管理mysq ...

  4. Redis 内存管理与事件处理

    1 Redis内存管理 Redis内存管理相关文件为zmalloc.c/zmalloc.h,其只是对C中内存管理函数做了简单的封装,屏蔽了底层平台的差异,并增加了内存使用情况统计的功能. void * ...

  5. Redis事件

    Redis事件 Redis的ae(Redis用的事件模型库) ae.c Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件: 文件事件(file event):Redis服务器通过套接字与 ...

  6. 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理

    服务器文档下载zip格式   刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...

  7. JavaScript 事件管理

    在设计JavaScript xxsdk的时候考虑到能让调用者参与到工作流程中来,开始用了回调函数.如下: this.foo = function(args,callbackFn) { //do som ...

  8. jquery技巧之让任何组件都支持类似DOM的事件管理

    本文介绍一个jquery的小技巧,能让任意组件对象都能支持类似DOM的事件管理,也就是说除了派发事件,添加或删除事件监听器,还能支持事件冒泡,阻止事件默认行为等等.在jquery的帮助下,使用这个方法 ...

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

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/98.html?1455870209 Redis是一个超精简的基于内存的键值 ...

随机推荐

  1. 【PHP面向对象(OOP)编程入门教程】21.多态的应用

    多态是除封装和继承之外的另一个面象对象的三大特性之一,我个人看来PHP中虽然可以实现多态,但和c++还有Java这些面向对象的语言相比,多 态性并不是那么突出,因为PHP本身就是一种弱类型的语言,不存 ...

  2. C#GDI+编程基础(二)

    pen类:绘制指定宽度和样式的直线.使用DashStyle属性绘制几种虚线,可以使用各种填充样式(包括纯色和纹理)来填充Pen绘制的直线,填充模式取决于画笔或用作填充对象的纹理. 创建画笔: //用指 ...

  3. go outside @ CULTS LYRICS

    I really want to go out I really want to go outside and stop to see your day You really want to hole ...

  4. linux 下开放端口问题

    Linux安装Tomcat后本地可以正常访问,可是这时Tomcat还不能被外界访问需要在Linux默认防护墙上打开8080端口 打开 /etc/sysconfig/iptables   [root@l ...

  5. 1.xrange和range不要混了,2.range(len(xx))不如用enumerate

    range()是列表, xrange()是迭代 >>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i i ...

  6. (转)android图片压缩总结

    原文地址:http://blog.csdn.net/cherry609195946/article/details/9264409 一.图片的存在形式 1.文件形式(即以二进制形式存在于硬盘上)2.流 ...

  7. 大数据热点问题TOP K

    1单节点上的topK (1)批量数据 数据结构:HashMap, PriorityQueue 步骤:(1)数据预处理:遍历整个数据集,hash表记录词频 (2)构建最小堆:最小堆只存k个数据. 时间复 ...

  8. 音频DAC剖析---解开HI-FI音质的秘密

    选自:http://mp3.zol.com.cn/54/547689.html 无论我们是买MP3.MP4也好,实际上我们的数码播放器最经常使用的就是音乐播放功能,所以数码播放器的音质,一直是消费者的 ...

  9. yuv转bmp

    #ifdef _INTERFACE_H #error _INTERFACE_H has be exsisted #else #define _INTERFACE_H #include "st ...

  10. Linux--多网卡的7种Bond模式

    网卡bond是通过把多张网卡绑定为一个逻辑网卡,实现本地网卡的冗余,带宽扩容和负载均衡.在应用部署中是一种常用的技术,我们公司基本所有的项目相关服务器都做了bond,这里总结整理,以便待查. bond ...