昨晚看了下redis的populateCommandTable.大致原理我是明白的,
不过我觉得代码写的有点绕,有些细节的控制看得会让人晕头转向。
我自己想了下,如果让我根据其原理来自己写的话,我的思路会是如下:
考虑到有两个哈希表ht[0],ht[1],刚开始ht[0]没有成员,ht[1]没有成员。
1)ht[0]为空,申请缓冲区,size=4.同时加入第一个命令。
2)ht[0]还可以放一个,放入第2个命令。
3)ht[0]不满,放入第3个命令。
4)ht[0]不满,放入第4个命令,
此时ht[0].used==ht[0].size.立刻设置ht[0].rehash=0;
表示ht[0]需要rehash了。
5)需要放入第5个命令,由于ht[0].rehash=0.表明ht[0]不可以放入命令了,
那么此时需要放入ht[1]中,此时ht[1]肯定是NULL,为ht[1]申请缓冲区,大小为2*ht[0].size.
对ht[0]执行单步一个桶的rehash到ht[1]中,同时加入第5个命令到ht[1]中。
6)后续加入命令时,每次先对ht[0]执行单步一个桶的rehash到ht[1]中,同时加入当前命令到ht[1]中。
7)对ht[1]执行完 ht[0]的单步rehash和加入新命令到ht[1]中后,一旦发现ht[0].used=0.
立即将ht[1]赋值给ht[0],释放ht[1]的缓冲区,标记ht[0].rehash=-1.
此处后来补充:
同时根据更新后的ht[0]的used和size情况决定ht[0].rehash是否需要再次rehash.
从数学角度来分析,每次rehash结束后,ht[1]赋值给ht[0]后,更新后的ht[0]里最多有多少个节点?
稍微分析一下,就知道此时ht[0].used<=ht[0].size.
什么情况下ht[0]. used=ht[0].size?
就是之前每次rehash, 只从ht[0]取出一个节点出来到ht[1]中,这也意味着老的ht[0]的每个桶里有且只有一个节点。
~~~~~~~~~~~
然后rehash结束后,再加入命令,就跟刚开始加入节点一样了。
通过上面的方法来改造,对细节更容易让人理解,对ht[0],ht[1]的关系看代码更容易清楚,
特别是2个哈希表的节点数量的关系。
反正如果让我写,我就这么写。
说了这么多,为啥要费尽功夫做rehash,还不是为了减少每个桶下面的节点数量,减少查找时间。
典型的以空间换时间的做法。
---强子哥哥 QQ 837500869