redis学习笔记->事件处理流程

最近开始学习redis源码,记录一下

一、涉及的函数

redis学习笔记->事件处理流程_第1张图片

(省略了大量函数)

redis的main函数在redis.c文件里,在main函数里,initServerConfig()函数设置全局变量server的每项默认值,之后main函数在检查程序参数,根据参数读取相关配置修改server配置,server定义如下:

struct redisServer server;

接下来,initServer()函数会做服务器初始化工作,包括创建相关数据结构,打开监听端口,设置事件循环等等

最后aeMain()会启动事件循环,服务器开始处理事件,服务器退出后,调用aeDeleteEventLoop()摧毁事件循环。

二、相关初始化工作

在initServer()函数内:

初始化相关数据结构

server.clients = listCreate();
server.clients_to_close = listCreate();
server.slaves = listCreate();

//创建事件循环,接下里服务器处理事件将会围绕这个循环,即EventLoop,同时调用aeApiCreate()创建IO多路复用的实例,例如epoll实例
server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);

接下来,程序打开监听端口,用于等待客户端的命令

    if (server.port != 0 &&
        listenToPort(server.port,server.ipfd,&server.ipfd_count) == REDIS_ERR)
        exit(1);
然后,会为serverCron()函数创建时间事件,为监听端口上的套接字创建文件事件,函数为acceptTcpHandler()

if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
        redisPanic("Can't create the serverCron time event.");
        exit(1);
    }

    /* Create an event handler for accepting new connections in TCP and Unix
     * domain sockets. */
    for (j = 0; j < server.ipfd_count; j++) {
        if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
            acceptTcpHandler,NULL) == AE_ERR)
            {
                redisPanic(
                    "Unrecoverable error creating server.ipfd file event.");
            }
    }


在aeCreateTimeEvent()函数内,创建好的时间事件结构体aeTimeEvent *te会被放入事件循环server.el中的时间事件链表表头上,并设置事件处理函数te->timeProc = proc。
在aeCreateFileEvent()函数内,设置该文件事件的mask,并注册到IO多路复用的监听中。并设置事件处理函数fe->rfileProc = proc;fe->wfileProc = proc;


三、开始处理事件

aeMain代码如下:

void aeMain(aeEventLoop *eventLoop) {

    eventLoop->stop = 0;

    while (!eventLoop->stop) {

        // 如果有需要在事件处理前执行的函数,那么运行它
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);

        // 开始处理事件
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

在aeProcessEvents()函数里

先检查最近的时间事件,检查事件到达时间,计算出IO多路复用实例(如epoll)一次等待的时间。

如果时间事件已经到达,则设置epoll等待时间为0,立刻返回,如果不是立刻到达,则计算出时间差,时间差为epoll_wait的等待时间

然后程序已经到达的文件事件,并调用他们事件处理函数。

处理完文件事件后,处理时间事件。


四、处理用户命令流程

监听套接字接到一个新用户连接时,调用acceptTcpHandler为客户端创建redisClient。并添加到服务器的客户端链表中,同时为这个连接添加事件到事件循环。

redisClient *createClient(int fd) {
aeCreateFileEvent(server.el,fd,AE_READABLE,
            readQueryFromClient, c)
listAddNodeTail(server.clients,c);
}
当用户传命令到服务器时,readQueryFromClient就会被调用,处理用户命令


你可能感兴趣的:(redis)