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. Spark之命令

    Spark之命令 1.spark运行模式有4种: a.local 多有用测试, b. standalone:spark 集群模式,使用spark自己的调度方式. c. Yarn: 对Mapreduce ...

  2. WPF:依赖属性的应用

    依赖属性与一般属性相比,提供了对资源引用.样式.动画.数据绑定.属性值继承.元数据重载以及WPF设计器的继承支持功能的支持. 下面的这个Demo来自<葵花宝典--WPF自学手册>. 1.M ...

  3. thinkphp中的自动验证

    array(验证字段,验证规则,错误提示,[验证条件,附加规则,验证时间]) 1.验证字段 需要验证的表单字段名称,这个字段不一定是数据库字段,也可以是表单的一些辅助字段,例如确认密码和验证码等等.有 ...

  4. Android--UI之AutoCompleteTextView

    前言 之前讲过EditText,有兴趣的朋友可以看一下.这篇博客主要说明的是自动完成文本框,它实际上也是一个文本编辑框,可以理解为对EditText功能的扩展,它对输入的内容可以进行提示并且自动完成. ...

  5. html5跨域通讯之postMessage的用法

    转自:http://www.cnblogs.com/wshiqtb/p/3171199.html postMessagePortal.html 页面代码 <!DOCTYPE html> & ...

  6. [RouterOS] ROS对接碧海威或PA等流控实现完美流控详细教程(附脚本全免费)

    前言: 经常在群里看到不少朋友争论海蜘蛛 ROS 维盟 爱快 碧海威 流控大师 Woyos等等软路由,哪个好.实际上,网络产品是复杂的,现在的软路由功能上已经远远不是单独的路由了.每种产品都有他本身的 ...

  7. TLS 与 python thread local

    TLS 先说TLS( Thread Local Storage),wiki上是这么解释的: Thread-local storage (TLS) is a computer programming m ...

  8. [转]Aptana Studio 3配置Python开发环境图文教程

    转载URL:http://www.cr173.com/html/49260_1.html 一.安装Aptana Studio 3 安装完运行时建议将相关默认工作目录设定在英文的某个目录下.避免可能出现 ...

  9. Linux的IO性能监控工具iostat详解

    Linux系统出现了性能问题,一般我们可以通过top.iostat.free.vmstat等命令来查看初步定位问题.其中iostat可以提供更丰富的IO性能状态数据. . 基本使用 $iostat - ...

  10. Aufs与Devicemapper的关系

    Aufs与Devicemapper的应用 Aufs是Docker最初采用的文件系统,由于Aufs未能加入到Linux内核,考虑到兼容性问题,加入了Devicemapper的支持.目前,除少数版本如Ub ...