redis的文件事件:即与io相关的事件。

/* File event structure */
typedef struct aeFileEvent {
int mask; /* one of AE_(READABLE|WRITABLE) */
aeFileProc *rfileProc; //读网络数据处理函数
aeFileProc *wfileProc; //写网络数据处理函数
void *clientData;
} aeFileEvent;

所有的文件事件放在aeEventLoop的数组中:

/* 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;
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;
aeBeforeSleepProc *aftersleep;
} aeEventLoop;

重点关注 events数组和fired数组,在(server.c) initServer中创建事件循环,

server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);

在(ae.c) aeCreateEventLoop中,为events数组和fired数组分配内存:

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 = 0;
eventLoop->stop = 0;
eventLoop->maxfd = -1;
eventLoop->beforesleep = NULL;
eventLoop->aftersleep = NULL;
if (aeApiCreate(eventLoop) == -1) goto err;
/* Events with mask == AE_NONE are not set. So let's initialize the
* vector with it. */
for (i = 0; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;
return eventLoop; err:
if (eventLoop) {
zfree(eventLoop->events);
zfree(eventLoop->fired);
zfree(eventLoop);
}
return NULL;
}

在aeCreateFileEvent中为events的具体元素赋值,由创建客户端连接进入aeCreateFileEvent方法的调用栈如下:

// 省略其他代码
client *createClient(int fd) {
client *c = zmalloc(sizeof(client)); /* passing -1 as fd it is possible to create a non connected client.
* This is useful since all the commands needs to be executed
* in the context of a client. When commands are executed in other
* contexts (for instance a Lua script) we need a non connected client. */
if (fd != -) {
anetNonBlock(NULL,fd);
anetEnableTcpNoDelay(NULL,fd);
if (server.tcpkeepalive)
anetKeepAlive(NULL,fd,server.tcpkeepalive);
if (aeCreateFileEvent(server.el,fd,AE_READABLE,
readQueryFromClient, c) == AE_ERR)
{
close(fd);
zfree(c);
return NULL;
}
} ...
return c;
}

把rfileProc和wfileProc的值设为readQueryFromClient函数

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;
}

当客户端发生网络IO时:

调用epoll_wait,获取发生事件的文件描述符,设置在fired元素中:

static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
aeApiState *state = eventLoop->apidata;
int retval, numevents = ; retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
tvp ? (tvp->tv_sec* + tvp->tv_usec/) : -);
if (retval > ) {
int j; numevents = retval;
for (j = ; j < numevents; j++) {
int mask = ;
struct epoll_event *e = state->events+j; if (e->events & EPOLLIN) mask |= AE_READABLE;
if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
if (e->events & EPOLLERR) mask |= AE_WRITABLE;
if (e->events & EPOLLHUP) mask |= AE_WRITABLE;
eventLoop->fired[j].fd = e->data.fd;
eventLoop->fired[j].mask = mask;
}
}
return numevents;
}

在aeProcessEvents方法中,根据fired元素中的fd,处理IO事件。

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++;
}

redis的文件事件的更多相关文章

  1. redis的文件事件处理器

    前言     C10K problem提出了一个问题,如果1w个客户端连接到server上,间歇性的发送消息,有哪些好的方案?     其中的一种方案是,每个线程处理多个客户端,使用异步I/O和就绪通 ...

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

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

  3. Redis线程模型

    Redis 基于 Reactor 模式开发了自己的网络事件处理器: 这个处理器被称为文件事件处理器(file event handler): 文件事件处理器使用 I/O 多路复用(multiplexi ...

  4. redis 笔记03 RDB 持久化、AOF持久化、事件、客户端

    RDB 持久化 1. RDB文件用于保存和还原Redis服务器所有数据库中的所有键值对数据. 2. SAVE命令由服务器进程直接执行保存操作,所以该命令会阻塞服务器. 3. BGSAVE由子进程执行保 ...

  5. Redis与Reactor模式

    Redis与Reactor模式 Jan 9, 2016 近期看了Redis的设计与实现,这本书写的还不错,看完后对Redis的理解有非常大的帮助. 另外,作者整理了一份Redis源代码凝视,大家能够c ...

  6. Redis实现之事件

    事件 Redis服务器是一个事件驱动程序,服务器需要处理以下两类事情: 文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对 ...

  7. redis 命令的调用过程

    参考文献: Redis 是如何处理命令的(客户端) 我是如何通过添加一条命令学习redis源码的 从零开始写redis客户端(deerlet-redis-client)之路--第一个纠结很久的问题,r ...

  8. 跟着大彬读源码 - Redis 4 - 服务器的事件驱动有什么含义?(上)

    众所周知,Redis 服务器是一个事件驱动程序.那么事件驱动对于 Redis 而言有什么含义?源码中又是如何实现事件驱动的呢?今天,我们一起来认识下 Redis 服务器的事件驱动. 对于 Redis ...

  9. 理解Redis的反应堆模式

    1. Redis的网络模型 Redis基于Reactor模式(反应堆模式)开发了自己的网络模型,形成了一个完备的基于IO复用的事件驱动服务器,但是不由得浮现几个问题: 为什么要使用Reactor模式呢 ...

随机推荐

  1. Reversion Count

    字符串基础用法题,包含有大数减法大数除法模板,不难理解,代码如下: #include<stdio.h> #include<string.h> #include<strin ...

  2. Ajax_请求get,post案例

    1. 最原始的ajax请求方式 (1). get请求 <%@ Page Language="C#" AutoEventWireup="true" Code ...

  3. System.out.println 报错: 只能运行在方法体内哦, 类里面只包含属性和方法哦,注意!

    类里面包含属性和方法 所以, System.out.println,只能放在方法体内运行,不能放在类里.方法外哦

  4. Boostrap本地导入js文件

    我一般都是用CDN直接导入的,但是有时候需要自己添加一些功能进入,会用到本地导入.关于导入路径问题,做个笔记. 使用HBuilder,首先右键导入相应的js/cs文件 然后是常规——>文件系统 ...

  5. HeadFIrst Ruby 第六章总结 block return values

    前言 这一章通过抽取一个文件中的确定的单词的项目进行讲解,主要包括了: File 的打开.阅读与关闭 find_all & refuse方法的相关内容 map 方法的相关内容这章的核心是:关于 ...

  6. Node.js 知识(教程)

    JavaScript on the Server JavaScript was originally built for web browsers, but with Node.js we can u ...

  7. 关于OkHttp同步请求的小错误

    今天进行OkHttp的同步请求 写的都是按照官方的去写的 但是返回的东西却不是我想要的 原因是我直接拿到Response后,直接Response.toString,想要拿到返回值 但是这样是错误的,正 ...

  8. hdu-4507 吉哥系列故事——恨7不成妻 数位DP 状态转移分析/极限取模

    http://acm.hdu.edu.cn/showproblem.php?pid=4507 求[L,R]中不满足任意条件的数的平方和mod 1e9+7. 条件: 1.整数中某一位是7:2.整数的每一 ...

  9. scrapy 爬虫框架(一)

    一 . scrapy 的安装 安装scrapy框架时,需要先安装依赖包. #Linux: pip3 install scrapy #Windows: a. pip3 install wheel b. ...

  10. vue, vux调用微信点击图片,上传图片,删除图片,接口,其中选图接口,苹果手机显示有问题,查看不到图片,提交会提示fail not exist,解决如下

    <template> <div v-cloak v-show="show"> <div v-show="mailbox"> ...