# 期中测试题答案 | 这些问题你都答对了吗? 你好,我是蒋德钧。这节课,我来给你公布一下期中考试中问答题的答案。 ## 第一题 Redis源码中实现的哈希表在rehash时,会调用dictRehash函数。dictRehash函数的原型如下,它的参数n表示本次rehash要搬移n个哈希桶(bucket)中的数据。假设dictRehash被调用,并且n的传入值为10。但是,在dictRehash查找的10个bucket中,前5个bucket有数据,而后5个bucket没有数据,那么,本次调用dictRehash是否就只搬移了前5个bucket中的数据? ```plain 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实例。这个调用关系如下: ```plain aeCreateEventLoop --> aeApiCreate --> epoll_create ``` 然后,当事件驱动框架初始化完成后,initServer函数就会调用aeCreateFileEvent函数,而aeCreateFileEvent函数会调用aeApiAddEvent函数,进而调用epoll\_ctl将监听套接字加入监听列表。这个调用关系为: ```plain aeCreateFileEvent --> aeApiAddEvent --> epoll_ctl ``` 这样一来,Redis server在完成初始化后,就会调用aeMain函数,进入事件框架的循环流程。在这个流程中,**aeProcessEvents函数**会被循环调用,用于不断处理事件。aeProcessEvents函数会调用aeApiPoll函数,而aeApiPoll函数就会调用epoll\_wait,进而获取就绪的套接字,从而可以处理套接字上的事件了。这个调用关系,你可以参考以下代码: ```plain aeMain --> aeProcessEvents --> aeApiPoll --> epoll_wait ``` 好了,这节课就到这里。期中周转眼就过去了一大半,希望你抓住最后的几天时间,好好地巩固一下所学的内容。我们下节课再见。