redis的文件事件
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的文件事件的更多相关文章
- redis的文件事件处理器
前言 C10K problem提出了一个问题,如果1w个客户端连接到server上,间歇性的发送消息,有哪些好的方案? 其中的一种方案是,每个线程处理多个客户端,使用异步I/O和就绪通 ...
- Redis 内存管理与事件处理
1 Redis内存管理 Redis内存管理相关文件为zmalloc.c/zmalloc.h,其只是对C中内存管理函数做了简单的封装,屏蔽了底层平台的差异,并增加了内存使用情况统计的功能. void * ...
- Redis线程模型
Redis 基于 Reactor 模式开发了自己的网络事件处理器: 这个处理器被称为文件事件处理器(file event handler): 文件事件处理器使用 I/O 多路复用(multiplexi ...
- redis 笔记03 RDB 持久化、AOF持久化、事件、客户端
RDB 持久化 1. RDB文件用于保存和还原Redis服务器所有数据库中的所有键值对数据. 2. SAVE命令由服务器进程直接执行保存操作,所以该命令会阻塞服务器. 3. BGSAVE由子进程执行保 ...
- Redis与Reactor模式
Redis与Reactor模式 Jan 9, 2016 近期看了Redis的设计与实现,这本书写的还不错,看完后对Redis的理解有非常大的帮助. 另外,作者整理了一份Redis源代码凝视,大家能够c ...
- Redis实现之事件
事件 Redis服务器是一个事件驱动程序,服务器需要处理以下两类事情: 文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对 ...
- redis 命令的调用过程
参考文献: Redis 是如何处理命令的(客户端) 我是如何通过添加一条命令学习redis源码的 从零开始写redis客户端(deerlet-redis-client)之路--第一个纠结很久的问题,r ...
- 跟着大彬读源码 - Redis 4 - 服务器的事件驱动有什么含义?(上)
众所周知,Redis 服务器是一个事件驱动程序.那么事件驱动对于 Redis 而言有什么含义?源码中又是如何实现事件驱动的呢?今天,我们一起来认识下 Redis 服务器的事件驱动. 对于 Redis ...
- 理解Redis的反应堆模式
1. Redis的网络模型 Redis基于Reactor模式(反应堆模式)开发了自己的网络模型,形成了一个完备的基于IO复用的事件驱动服务器,但是不由得浮现几个问题: 为什么要使用Reactor模式呢 ...
随机推荐
- python线程 有问题?
- oracle 与其他数据库如mysql的区别
想明白一个问题:(1)oracle是以数据库为中心,一个数据库就是一个域(可以看作是一个文件夹的概念),一个数据库可以有多个用户,创建用户是在登陆数据库之后进行的,但是有表空间的概念(2)而mysql ...
- HttpDns原理
什么是 DNS DNS(Domain Name System,域名系统),DNS 服务用于在网络请求时,将域名转为 IP 地址.能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的 IP 数 ...
- 【Python】【IO】
# [[IO]] # [文件读写] '''读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的.读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现 ...
- 一行css解决图片统一大小后的拉伸问题(被冷漠的object-fit)
一.先来个实战 1. 测试案例 需求: 要求表情库里所有表情包大小都固定 实际效果: 由于图片原始大小都不一样,强行设定大小值会导致拉伸,如果不设定大小则参差不齐.例如: //html <bod ...
- 实现一个键对应多个值的字典(multidict)
一个字典就是一个键对应一个单值的映射.如果你想要一个键映射多个值,那么你就需要将这多个值放到另外的容器中, 比如列表或者集合里面.比如,你可以像下面这样构造这样的字典: d = { , , ], , ...
- centos7 下载安装tomcat9
需要Java环境 https://www.cnblogs.com/sea-stream/p/10404360.html 官网下载安装包 wget http://archive.apache.org/d ...
- 【C#】采用OleDB读取Excel文件转DataTable
using System; using System.Data; using System.Data.OleDb; using System.IO; using System.Linq; using ...
- ABP捕捉异常错误代码
在服务层或者CORE层 随便哪里都可以 创建一个捕捉异常的文件夹 里面写一个LonsidException类 继承后面的接口 然后重写继承的方法 这样在ABP项目运行阶段 无论在哪里出现异 ...
- [JS]计算字符串中出现最多的字符和其出现次数
这是一道面试题 此处是利用Obj来解决的,当然不只此一种方法. //思路:遍历数组,拿到一个字符,并将之以 "字符":出现次数 的key:value形式存到对象中. //如果此字符 ...