• Redis事件管理(三)


     Redis的事件管理和定时器的管理都是自己来实现的,Redis的事件管理分为两部分,一部分是封装了系统的异步事件API,还有一部分是在这基础上封装了一个通用的事件管理器,根据具体的系统来决定具体使用哪个异步管理API。

    先来说说Redis支持哪些异步的系统API。Redis内部封装了epoll,evport,kqueue,select这四个原始的事件管理器。

    那epoll举个例子解析一下吧。

    1 typedef struct aeApiState 
    2 {
    3     int epfd; //文件描述符
    4     struct epoll_event *events;//epoll实例
    5 } aeApiState;

    这个结构体封装了一个具体的事件实例。

    封装的接口函数:

    1 static int aeApiCreate(aeEventLoop *eventLoop) //创建一个事件管理器
    2 static int aeApiResize(aeEventLoop *eventLoop, int setsize) //重置事件管理器管理事件的个数
    3 static void aeApiFree(aeEventLoop *eventLoop) //删除一个事件管理器
    4 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)//向事件管理器中添加一个事件 
    5 static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) //从时间管理器中删除一个事件
    6 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp)//激活事件管理器,返回已经触发的事件的个数
    7 static char *aeApiName(void) //获取当前使用的是什么事件模型
    1 static int aeApiCreate(aeEventLoop *eventLoop) //创建一个事件管理器
     1 /*创建成功返回0,否则返回-1*/
     2 static int aeApiCreate(aeEventLoop *eventLoop) 
     3 {
     4     aeApiState *state = zmalloc(sizeof(aeApiState));
     5 
     6     if (!state) return -1;
     7     /*直接按size申请内存*/
     8     state->events = zmalloc(sizeof(struct epoll_event) * eventLoop->setsize);
     9     /*事件内存失败时要释放结构体的内存,防止出现内存泄露*/
    10     if (!state->events) 
    11     {
    12         zfree(state);
    13         return -1;
    14     }
    15     /*创建epoll描述符,如果创建失败,记得把上面申请的内存释放掉*/
    16     state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */
    17     if (state->epfd == -1) 
    18     {
    19         zfree(state->events);
    20         zfree(state);
    21         return -1;
    22     }
    23     eventLoop->apidata = state;
    24     return 0;
    25 }
    2 static int aeApiResize(aeEventLoop *eventLoop, int setsize) //重置事件管理器管理事件的个数
    /*重置可接受事件的个数,这个函数不能直接调用,因为没有检查新size和旧size的大小关系,如果小了,直接重置会出问题*/
    static int aeApiResize(aeEventLoop *eventLoop, int setsize) 
    {
        aeApiState *state = eventLoop->apidata;
    
        state->events = zrealloc(state->events, sizeof(struct epoll_event)*setsize);
        return 0;
    }
    4 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)//向事件管理器中添加一个事件
     1 /*向epoll中增加事件,需要注册新的文件描述符和需要监控的事件类型*/
     2 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) 
     3 {
     4     aeApiState *state = eventLoop->apidata;
     5     struct epoll_event ee;
     6     /*因为epoll的维护是用数组维护的,通过下标的方式可以直接访问,省时省力。如果这个节点已经激活了,那新事件添加就好了*/
     7     int op = eventLoop->events[fd].mask == AE_NONE ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
     8 
     9     ee.events = 0;
    10     mask |= eventLoop->events[fd].mask; /* Merge old events */
    11     if (mask & AE_READABLE) ee.events |= EPOLLIN;
    12     if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
    13     ee.data.u64 = 0; /* avoid valgrind warning */
    14     ee.data.fd = fd;
    15     if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;
    16     return 0;
    17 }
    6 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp)//激活事件管理器,返回已经触发的事件的个数
    /*获取事件队列*/
    static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) 
    {
        aeApiState *state = eventLoop->apidata;
        int retval, numevents = 0;
    
        retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
        if (retval > 0) 
        {
            int j;
    
            numevents = retval;
            /*将满足条件的文件描述符和状态保存到fired中,后期逐个处理*/
            for (j = 0; j < numevents; j++) 
            {
                int mask = 0;
                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;
    }
  • 相关阅读:
    Web安全实践
    认证授权的设计与实现
    Elasticsearch 分页查询
    【算法】三色旗
    【转】互联网项目中mysql应该选什么事务隔离级别
    Elasticsearch 聚合
    Elasticsearch 结构化搜索、keyword、Term查询
    Elasticsearch 单字符串多字段查询
    Elasticsearch 复合查询——多字符串多字段查询
    JavaScript 原型与原型链
  • 原文地址:https://www.cnblogs.com/likui360/p/5297729.html
Copyright © 2020-2023  润新知