你好,我是蒋德钧。这节课,我来给你公布一下期中考试中问答题的答案。

第一题

Redis源码中实现的哈希表在rehash时,会调用dictRehash函数。dictRehash函数的原型如下,它的参数n表示本次rehash要搬移n个哈希桶(bucket)中的数据。假设dictRehash被调用,并且n的传入值为10。但是,在dictRehash查找的10个bucket中,前5个bucket有数据,而后5个bucket没有数据,那么,本次调用dictRehash是否就只搬移了前5个bucket中的数据?

int dictRehash(dict *d, int n) 

答案分析

当Redis哈希表在做rehash搬移数据时,如果遇到空的bucket,那么Redis会跳过空的bucket,再查找下一个bucket。但是,在dictRehash函数中,是使用了empty_visits变量,来记录跳过的空bucket数量,而empty_visits的值是被初始化成n*10,也就是要搬移的bucket数量的10倍。

因此,如果rehash过程中已经跳过了empty_visits数量的空bucket,那么本次dictRehash的执行就会直接返回了,而不会再查找bucket。这样设计的目的,也是为了避免本次rehash的执行一直无法结束,影响正常的请求处理

所以,在题述场景中,dictRehash函数会在找到50个空bucket时,直接结束执行,即使此时还没有完成10个bucket数据的搬移。而如果在查找的10个bucket后面,紧接着就有5个bucket有数据,那么本次调用dictRehash仍然搬移了10个bucket的数据。

第二题

Redis的事件驱动框架是基于操作系统IO多路复用机制进行了封装,以Linux的epoll机制为例,该机制调用epoll_create函数创建epoll实例,再调用epoll_ctl将监听的套接字加入监听列表,最后调用epoll_wait获取就绪的套接字再进行处理。请简述Redis事件驱动框架中哪些函数和epoll机制各主要函数有对应的调用关系。

答案分析

Redis在initServer函数中,调用了aeCreateEventLoop函数初始化事件框架,其中,aeCreateEventLoop函数会调用aeApiCreate函数,而如果IO多路复用机制使用的是epoll机制,那么aeApiCreate函数就会调用epoll_create函数,创建epoll实例。这个调用关系如下:

aeCreateEventLoop --> aeApiCreate --> epoll_create

然后,当事件驱动框架初始化完成后,initServer函数就会调用aeCreateFileEvent函数,而aeCreateFileEvent函数会调用aeApiAddEvent函数,进而调用epoll_ctl将监听套接字加入监听列表。这个调用关系为:

aeCreateFileEvent --> aeApiAddEvent --> epoll_ctl

这样一来,Redis server在完成初始化后,就会调用aeMain函数,进入事件框架的循环流程。在这个流程中,aeProcessEvents函数会被循环调用,用于不断处理事件。aeProcessEvents函数会调用aeApiPoll函数,而aeApiPoll函数就会调用epoll_wait,进而获取就绪的套接字,从而可以处理套接字上的事件了。这个调用关系,你可以参考以下代码:

aeMain --> aeProcessEvents --> aeApiPoll --> epoll_wait

好了,这节课就到这里。期中周转眼就过去了一大半,希望你抓住最后的几天时间,好好地巩固一下所学的内容。我们下节课再见。

评论