1. redis事件的定义

/* State of an event based program */
typedef struct aeEventLoop {
int maxfd; /* highest file descriptor currently registered */
int setsize; /* max number of file descriptors tracked */
long long timeEventNextId; /*下一个定时器的id*/
time_t lastTime; /* Used to detect system clock skew */
aeFileEvent *events; /* Registered events注册的文件事件 */
aeFiredEvent *fired; /* Fired events 已注销的文件事件 */
aeTimeEvent *timeEventHead; /*定时器事件链表的首部*/ int stop; void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep; 
} aeEventLoop;

1.1 事件定义


/* File event structure */
typedef struct aeFileEvent {
int mask; /* one of AE_(READABLE|WRITABLE) */
aeFileProc *rfileProc;
aeFileProc *wfileProc;
void *clientData;
} aeFileEvent;


/* Time event structure */
typedef struct aeTimeEvent {
long long id; /* time event identifier. */
long when_sec; /* seconds */
long when_ms; /* milliseconds */
aeTimeProc *timeProc;
aeEventFinalizerProc *finalizerProc;
void *clientData;
struct aeTimeEvent *next;
} aeTimeEvent;


/* A fired event */
typedef struct aeFiredEvent {
int fd;
int mask;
} aeFiredEvent;

 

2.封装事件处理的实现

/* Include the best multiplexing layer supported by this system.
* The following should be ordered by performances, descending. */
#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

3.事件处理的主函数

void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = ;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}

3.1事件处理过程

/* Process every pending time event, then every pending file event
* (that may be registered by time event callbacks just processed).
* Without special flags the function sleeps until some file event
* fires, or when the next time event occurs (if any).
*
* If flags is 0, the function does nothing and returns.
* if flags has AE_ALL_EVENTS set, all the kind of events are processed.
* if flags has AE_FILE_EVENTS set, file events are processed.
* if flags has AE_TIME_EVENTS set, time events are processed.
* if flags has AE_DONT_WAIT set the function returns ASAP until all
* the events that's possible to process without to wait are processed.
*
* The function returns the number of events processed. */
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
int processed = , numevents; /* Nothing to do? return ASAP */
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; 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++;
}
}
/* Check time events */
if (flags & AE_TIME_EVENTS)
processed += processTimeEvents(eventLoop); return processed; /* return the number of processed file/time events */
}
/* Process time events */
static int processTimeEvents(aeEventLoop *eventLoop) {
int processed = ;
aeTimeEvent *te;
long long maxId;
time_t now = time(NULL); /* If the system clock is moved to the future, and then set back to the
* right value, time events may be delayed in a random way. Often this
* means that scheduled operations will not be performed soon enough.
*
* Here we try to detect system clock skews, and force all the time
* events to be processed ASAP when this happens: the idea is that
* processing events earlier is less dangerous than delaying them
* indefinitely, and practice suggests it is. */
if (now < eventLoop->lastTime) {
te = eventLoop->timeEventHead;
while(te) {
te->when_sec = ;
te = te->next;
}
}
eventLoop->lastTime = now; te = eventLoop->timeEventHead;
maxId = eventLoop->timeEventNextId-;
while(te) {
long now_sec, now_ms;
long long id; if (te->id > maxId) {
te = te->next;
continue;
}
aeGetTime(&now_sec, &now_ms);
if (now_sec > te->when_sec ||
(now_sec == te->when_sec && now_ms >= te->when_ms))
{
int retval; id = te->id;
retval = te->timeProc(eventLoop, id, te->clientData);
processed++;
/* After an event is processed our time event list may
* no longer be the same, so we restart from head.
* Still we make sure to don't process events registered
* by event handlers itself in order to don't loop forever.
* To do so we saved the max ID we want to handle.
*
* FUTURE OPTIMIZATIONS:
* Note that this is NOT great algorithmically. Redis uses
* a single time event so it's not a problem but the right
* way to do this is to add the new elements on head, and
* to flag deleted elements in a special way for later
* deletion (putting references to the nodes to delete into
* another linked list). */
if (retval != AE_NOMORE) {
aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
} else {
aeDeleteTimeEvent(eventLoop, id);
}
te = eventLoop->timeEventHead;
} else {
te = te->next;
}
}
return processed;
}

深入redis内部--事件处理机制的更多相关文章

  1. redis的事件处理机制

    redis的事件处理机制 redis是单进程,单线程模型,与nginx的多进程不同,与golang的多协程也不同,"工作的工人"那么少,可那么为什么redis能这么快呢? epol ...

  2. redis底层设计(五)——内部运作机制

    5.1 数据库 5.1.1 数据库的结构: Redis 中的每个数据库,都由一个redis.h/redisDb 结构表示: typedef struct redisDb { // 保存着数据库以整数表 ...

  3. Redis 处理客户端连接的一些内部实现机制

    本文主要介绍了 Redis 处理客户端连接的一些内部实现机制,包括连接处理.超时.缓冲区等一系列内容. 注:本文所述内容基于 Redis2.6 及以上版本. 连接的建立 Redis 通过监听一个 TC ...

  4. iOS 事件处理机制与图像渲染过程(转)

    iOS 事件处理机制与图像渲染过程 iOS RunLoop都干了什么 iOS 为什么必须在主线程中操作UI 事件响应 CALayer CADisplayLink 和 NSTimer iOS 渲染过程 ...

  5. iOS 事件处理机制与图像渲染过程

    Peter在开发公众号功能时触发了一个bug,导致群发错误.对此我们深表歉意,并果断开除了Peter.以下交回给正文时间: iOS 事件处理机制与图像渲染过程 iOS RunLoop都干了什么 iOS ...

  6. 从零开始理解JAVA事件处理机制(2)

    第一节中的示例过于简单<从零开始理解JAVA事件处理机制(1)>,简单到让大家觉得这样的代码简直毫无用处.但是没办法,我们要继续写这毫无用处的代码,然后引出下一阶段真正有益的代码. 一:事 ...

  7. 从零开始理解JAVA事件处理机制(3)

    我们连续写了两小节的教师-学生的例子,必然觉得无聊死了,这样的例子我们就是玩上100遍,还是不知道该怎么写真实的代码.那从本节开始,我们开始往真实代码上面去靠拢. 事件最容易理解的例子是鼠标事件:我们 ...

  8. 关于redis内部的数据结构

    最大感受,无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂.特别是源码,简洁易读,真正做到clean and clear, 这篇文章以unstable分支的源码为基准,先从大体 ...

  9. redis内部数据结构深入浅出

    最大感受,无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂.特别是源码,简洁易读,真正做到clean and clear, 这篇文章以unstable分支的源码为基准,先从大体 ...

随机推荐

  1. jquery实现简单瀑布流

    瀑布流这个概念一直不是很理解,看到别人可以实现,自己弄了很久还是不能实现就很纠结.瀑布流这根刺就一直扎在我心里,一次偶然的机会看到别人实现了瀑布流,我想我是不是也应该再继续把这个未完成的任务画一个圆满 ...

  2. Elasticsearch(1.1.1)基础教程pdf

    基础概念 Elasticsearch有几个核心概念.从一开始理解这些概念会对整个学习过程有莫大的帮助. 接近实时(NRT)        Elasticsearch是一个接近实时的搜索平台.这意味着, ...

  3. ubuntu 跑.net core 2.0

    安装.net core参考地址:http://www.microsoft.com/net/core/preview#linuxubuntu 服务器版本     UBbuntu  16.04 执行命令 ...

  4. 转载:RabbitMQ常用命令

    RabbitMQ常用命令 RabbitMQ常用命令 rabbitmqctl命令http://www.rabbitmq.com/man/rabbitmqctl.1.man.html# 1). 服务器启动 ...

  5. Windows 64位操作系统的ODBC

    我的操作系统是windows server 2008 R2 X64,系统自带两个版本的ODBC管理器,在"运行"中输入下面内容分别调出他们: X64: C:\windows\sys ...

  6. 深入了解java虚拟机(JVM) 第五章 如何判断对象为垃圾对象

    本章开始学习垃圾回收的过程,垃圾回收的过程首先就是要确定对象是否是垃圾对象,如果是垃圾对象,垃圾回收器才会进行回收.垃圾回收主要又两种算法:引用计数算法和可达性分析算法. 一.引用计数算法 引用计数算 ...

  7. 【sonar-block】Use try-with-resources or close this "BufferedInputStream" in a "finally" clause.

    自己的理解: try-with-resources是JDK7的新语法结构,主要功能是自动关闭资源而不需要在finally里面手动close()关闭, 而且最重要的是,try块中的异常不会被close( ...

  8. django中@property装饰器的运用

    python提供的内置装饰器——staticmethod.classmethod和property 在OSQA中,@property的使用频率是非常高的.下面就是它的使用方法: @property 可 ...

  9. MAC系统从零开始

    刚从ubuntu转过来,使用mac多有不习惯的地方,下面记录一些使用中遇到的问题,与解决方法. 1.关于应用程序菜单 在mac中的应用程序菜单,不是在应用程序自身,而是在桌面的桌面的顶部栏上,这个栏会 ...

  10. css modules

    https://juejin.im/post/5aa727fc518825364001159b http://www.ruanyifeng.com/blog/2016/06/css_modules.h ...