最近开始学习redis源码,记录一下
一、涉及的函数
(省略了大量函数)
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就会被调用,处理用户命令