redis 事件处理

redis 代码解读

redis 5.0.4

ae.c里面定义了四种mask
None 没有事件
read  cli读取
write  cli 写,连接, 断开
barrier

对于文件事件进行了一个封装
typedef struct aeFileEvent {
    // 文件时间类型:AE_NONE,AE_READABLE,AE_WRITABLE
    int mask; /* one of AE_(READABLE|WRITABLE) */
    // 可读处理函数
    aeFileProc *rfileProc;
    // 可写处理函数
    aeFileProc *wfileProc;
    // 客户端传入的数据
    void *clientData;
} aeFileEvent;  //文件事件


触发事件的封装
/* A fired event */
typedef struct aeFiredEvent {
    // 就绪事件的文件描述符
    int fd;
    // 就绪事件类型:AE_NONE,AE_READABLE,AE_WRITABLE
    int mask;
} aeFiredEvent; //就绪事件

aeEventLoop是对文件事件和时间事件的同一抽象


在config.h 当中定义了HAVE_EPOLL这些属性

redis当中的epoll使用

cat /proc/sys/fs/file-max  可以查看一个进程可以打开的最大fd数

typedef struct aeApiState {
    int epfd;    //epoll的FD
    struct epoll_event *events;      //用于保存EventLoop.size * event的大小
} aeApiState;

最后把他保存到eventLoop当中的API当中


=========================epoll核心的三个函数==============================
//创建一个epoll的fd
int epoll_create(int size);

struct epoll_event {
    uint32_t     events;      /* Epoll events */
    epoll_data_t data;        /* User data variable */
};

typedef union epoll_data {
    void        *ptr;
    int          fd;
    uint32_t     u32;
    uint64_t     u64;
} epoll_data_t;

//第一个参数是epollfd,
第二个是动作(add,mod,del等),
第三个是真正的文件句柄
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

EPOLLERR   文件描述符发生错误
EPOLLHUP  文件描述符被挂断

//第一个参数是epollfd,
第二个是传入传出参数,
第三个同时最大的事件数
第四个是超时,-1是阻塞,0是立即返回,大于0是指定的秒数
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
=====================================================================

实际redis需要把epoll事件与自身的AE_READABLE,AE_WRITABLE组合起来
static int aeApiCreate(aeEventLoop *eventLoop)      
启动的时候有一个setSize

***aeApiCreate是由include导入的符号,导入的是谁就跑哪个
就是说C的include可以实现类似于java的多态功能

 

***其实可以看到,aeEventLoop中的events,fired和ae_epoll里面的events的个数都是set_size的个数

因此events本身就是用fd作为参数来做索引的

但是在eaApiPoll的pol里面看到,epoll的实现里面,每次epoll_wait都是将有事件的events放到最前面,并且fired里面也是按照0-retval的顺序排的

retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,

tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);

并且在aeProcessEvents里面用aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];

找到真正地event

 

 

//这个event是真正的redis封装过的event
eventLoop里面有个events
//这个event是epoll的event
aeApiState里面也有一个events
用于保存进来的事件

aeCreateFileEvent   是把相应的事件加入到订阅的事件当中,在redis中有很多处这种调用,比如在client接入的时候
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
        aeFileProc *proc, void *clientData)
当中会调用aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)


readQueryFromClient   这个函数是从client读取数据的函数

server.c里面有三个createFileEvent,createClient这个是当client连接的时候的函数指针

the 0th trigger, the fd is 7
creating client 8
eventLoop add event fd:8, mask:1
the 0th trigger, the fd is 8

the 0th trigger, the fd is 7   ///创建fd的时候有个fd号是7,很奇怪这个是什么
creating client 9
eventLoop add event fd:9, mask:1
the 0th trigger, the fd is 9

就是死循环一直调这个函数
aeProcessEvents


Redis服务器在没有被事件触发时,就会阻塞等待,因为没有设置AE_DONT_WAIT标识。但是他不会一直的死等待,等待文件事件的到来,因为他还要处理时间时间,因此,在调用aeApiPoll进行监听之前,先从时间事件表中获取一个最近到达的时间时间,根据要等待的时间构建一个struct timeval tv, *tvp结构的变量,这个变量保存着服务器阻塞等待文件事件的最长时间,一旦时间到达而没有触发文件事件,aeApiPoll函数就会停止阻塞,进而调用processTimeEvents处理时间事件,因为Redis服务器设定一个对自身资源和状态进行检查的周期性检查的时间事件,而该函数就是timeProc所指向的回调函数


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值