开始学习redis的源码了,记录一下过程。首先下载了redis的第一个发布版本0.091版本:
https://download.redis.io/rel...
在redis.c文件里找到了redis服务启动的入口,即main函数。粗略看一眼启动过程:
首先是main函数:
int main(int argc, char **argv) {
...
aeMain(server.el);
...
}
进入aeMain函数,它在ae.c文件中:
void aeMain(aeEventLoop *eventLoop){
eventLoop->stop = 0;
while (!eventLoop->stop)
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
进入aeProcessEvents函数:
int aeProcessEvents(aeEventLoop *eventLoop, int flags){
...
retval = select(maxfd+1, &rfds, &wfds, &efds, tvp);
...
fe->fileProc(eventLoop, fe->fd, fe->clientData, mask);
...
retval = te->timeProc(eventLoop, id, te->clientData);
...
}
截取了上面三段代码,大概能看出redis的启动逻辑和事件处理模型了,它通过select来阻塞等待关心的事件到来,然后处理事件,处理完后又阻塞等待下一个事件的发生,如此往复。
所以简单的看,不停的往事件集合中添加事件和移除事件,就能让redis运作起来。
回过头看main函数,发现redis服务程序启动的时候就添加了一个事件:
int main(int argc, char **argv) {
...
if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,
acceptHandler, NULL, NULL) == AE_ERR) oom("creating file event");
...
}
其中server.fd
在服务初始化的时候赋值了,就是一个server socket,这里是监听它是否可读,当可读的时候调用acceptHandler
来处理server socket可读事件。
看看acceptHandler函数:
static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
...
cfd = anetAccept(server.neterr, fd, cip, &cport);
...
if (createClient(cfd) == NULL) {
...
}
...
}
在接受了客户端的请求后,调用了createClient函数:
static redisClient *createClient(int fd) {
...
if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
readQueryFromClient, c, NULL) == AE_ERR) {
...
}
...
}
可以看到这里又添加了一个事件,与客户端连接的socket有数据可读时,调用readQueryFromClient函数:
static void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
...
processCommand(c);
...
}
这个函数就是执行客户端传过来的各种指令,到这里,差不多把redis的源码大体上过了一遍了,下面看一个addReply函数,很容易可以看出,它是通过添加和处理socket可写事件,来返回信息给客户端。
static void addReply(redisClient *c, robj *obj) {
if (listLength(c->reply) == 0 &&
aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
sendReplyToClient, c, NULL) == AE_ERR) return;
if (!listAddNodeTail(c->reply,obj)) oom("listAddNodeTail");
incrRefCount(obj);
}
今天的源码先分析到这里,之后再看redis是具体如何处理各个指令的,0.091版本的redis支持49条指令,比最新版本少很多,很适合用来入门。