【Redis源码剖析】 - Redis内置数据结构之字典dict

转载自:http://blog.csdn.net/Xiejingfa/article/details/51018337

今天我们来讲讲Redis中的哈希表。哈希表在C++中对应的是map数据结构,但在Redis中称作dict(字典)。Redis只是用了几个简单的结构体和几种常见的哈希算法就实现了一个简单的类似高级语言中的map结构。下面我们来具体分析一下dict的实现。


在学习数据结构的时候,我们接触过一种称作“散列表”的结构,可以根据关键字而直接访问记录。说的具体一点就是通过把key值映射到表中的一个位置来访问,从而加快查找速度。Redis中的dict数据结构和我们之前学过的“散列表”大同小异。总结如下:

1、dict的结构

Redis定义了dictEntry、dictType、dictht和dict四个结构体来实现散列表的功能。它们具体定义如下:

(1)dictEntry结构体

<code class="hljs d has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 保存键值(key - value)对的结构体,类似于STL的pair。*/</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictEntry {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键字key定义</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key;  
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 值value定义,只能存放一个被选中的成员</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">union</span> {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *val;      
        uint64_t u64;   
        int64_t s64;    
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">double</span> d;       
    } v;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 指向下一个键值对节点</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictEntry *next;
} dictEntry;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

从dictEntry的定义我们也可以看出dict通过“拉链法”来解决冲突问题。

(2)、dictType结构体

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 定义了字典操作的公共方法,类似于adlist.h文件中list的定义,将对节点的公共操作方法统一定义。搞不明白为什么要命名为dictType */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictType {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* hash方法,根据关键字计算哈希值 */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*hashFunction)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 复制key */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *(*keyDup)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 复制value */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *(*valDup)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *obj);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 关键字比较方法 */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*keyCompare)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key1, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key2);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 销毁key */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (*keyDestructor)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 销毁value */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (*valDestructor)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *obj);
} dictType;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

(3)、dictht结构体

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 哈希表结构 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictht {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 散列数组。</span>
    dictEntry **table;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 散列数组的长度</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> size;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// sizemask等于size减1</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> sizemask;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 散列数组中已经被使用的节点数量</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> used;
} dictht;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

(4)、dict结构体

<code class="hljs d has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 字典的主操作类,对dictht结构再次包装  */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dict {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 字典类型</span>
    dictType *type;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 私有数据</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 一个字典中有两个哈希表</span>
    dictht ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 数据动态迁移的下标位置</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">long</span> rehashidx; 
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 当前正在使用的迭代器的数量</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> iterators; 
} dict;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

这四个结构体之间的关系如下: 
这里写图片描述

2、散列函数

Redis提供了三种不同的散列函数,分别是:

(1)、使用Thomas Wang’s 32 bit Mix哈希算法,对一个整型进行哈希,该方法在dictIntHashFunction函数中实现。 
(2)、使用MurmurHash2哈希算法对字符串进行哈希,该方法在dictGenHashFunction函数中实现。 
(3)、在dictGenCaseHashFunction函数中提供了一种比较简单的哈希算法,对字符串进行哈希

上面这三种方法的实现具体可以参考下面的代码。至于这几种方法的优劣,这里就不展开讲了(我自己也不是很清楚),大家可以自行google一下。

3、Rehash操作

Rehash是dict一个很重要的操作。在前面我们看到dict结构体中有两个哈希表(定义为dictht ht[2])。通常情况下,dict中的所有数据(键值对)都存放在ht[0],但随着dict中数据量的增加需要进行扩容操作(为什么?数据越多,冲突的元素越多,ht[0]中的链表越长,查找效率越低),此时就需要进行rehash。dict在rehash的时先申请一个更大的空间并用ht[1]指向该空间,然后把ht[0]中的所有数据rehash到ht[1]中,数据迁移完毕后在将ht[1]赋值给ht[0]并清空ht[1]。如果这个rehash过程是一次性完成的倒是很好理解,但从其源码中我们可以看出:dict的rehash操作并不是一次性完成的,而是分成多步。具体来说dict提供了两种不同的策略:一种是每次将ht[0]中的一个bucket,也就是散列数组中对应的一个链表中的所有数据进行rehash到ht[1]中,对应的函数是_dictRehashStep。另一种是每次执行一段固定的时间,时间到了就暂停rehash操作,对应的函数是dictRehashMilliseconds。

_dictRehashStep和dictRehashMilliseconds底层都调用了dictRehash函数来进行rehash操作。实现如下:

<code class="hljs haskell has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">/* 执行n步渐进式的rehash操作,如果还有key需要从旧表迁移到新表则返回<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,否则返回<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> */
<span class="hljs-title" style="box-sizing: border-box;">int</span> dictRehash(dict *d, int n) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dictIsRehashing(d)) return <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

    // n步渐进式的rehash操作就是每次只迁移哈希数组中的n个bucket
    while(n<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">--) {</span>
        dictEntry *de, *nextde;

        /* <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">Check</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> we already rehashed the whole table... */
        // 检查是否对整个哈希表进行了rehash操作
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].used == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
            zfree(d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].table);
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
            _dictReset(&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]);
            d->rehashidx = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
            return <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        }

        /* <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">Note</span> that rehashidx can't overflow <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> we are sure there are more
         * elements because ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].used != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> */
        // rehashidx标记的是当前rehash操作进行到了ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]旧表的那个位置(下标),因此需要判断它是否操作ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]的长度
        assert(d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].size > (unsigned long)d->rehashidx);
        // 跳过ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]中前面为空的位置
        while(d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].table[d->rehashidx] == <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">NULL</span>) d->rehashidx++;
        // 得到对应的链表
        de = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].table[d->rehashidx];
        /* <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">Move</span> all the keys <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> this bucket from the old to the new hash <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">HT</span> */
        // 下面的操作将每个节点(键值对)从ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]迁移到ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>],此过程需要重新计算每个节点key的哈希值
        while(de) {
            unsigned int h;

            nextde = de->next;
            /* <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">Get</span> the index <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> the new hash table */
            h = dictHashKey(d, de->key) & d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].sizemask;
            de->next = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].table[h];
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].table[h] = de;
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].used<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">--;</span>
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].used++;
            de = nextde;
        }
        d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].table[d->rehashidx] = <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">NULL</span>;
        d->rehashidx++;
    }
    return <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li></ul>

dictRehash函数执行N步rehash操作。每步中,首先判断是否已经完成了rehashN操作,判断的标准就是ht[0]的used是否为0。ht[0]的used == 0说明ht[0]中所有的链表都是空的,那么所有的元素都已经移动到ht[1]中。此时,将ht[1]赋值给ht[0],清空ht[1]。将rehashidx赋值为-1表明rehash结束。如果rehash没有结束,那么,查找ht[0]中下一个非空的桶。将这个桶中的所有数据rehash到ht[1]中。

既然rehash操作是分步进行的,那dict就可能存在这样一种状态:既有数据存放在ht[0]中,又有数据存放在ht[1]中。这样在对dict进行访问的时候就要加以区别。对于dictFind、dictDelete函数,需要遍历ht[0]和ht[1]两个表,对于dictAdd函数则需要根据当前dict是否在执行rehash操作来决定将键值对插入ht[0]还是ht[1]中。在下面的源码中,我们可以看到这些函数的具体实现。

dict的注意点大概就是这些,其它的都比较简单就直接贴代码了。大部分代码我都写了注释,如下:

dict.h头文件:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Hash Tables Implementation.
 *
 * This file implements in-memory hash tables with insert/del/replace/find/
 * get-random-element operations. Hash tables will auto-resize if needed
 * tables of power of two in size are used, collisions are handled by
 * chaining. See the source code for more information... :)
 *
 * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Redis nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */</span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <stdint.h></span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifndef __DICT_H</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> __DICT_H</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 成功 or 出错</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> DICT_OK 0</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> DICT_ERR 1</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Unused arguments generate annoying warnings... */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> DICT_NOTUSED(V) ((void) V)</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 保存键值(key - value)对的结构体,类似于STL的pair。Redis采用拉链法处理冲突,
    会把冲突的dictEntry组成一个链表。
*/</span>
typedef <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictEntry {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键字key定义</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key;  
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 值value定义,这里采用了联合体,根据union的特点,联合体只能存放一个被选中的成员</span>
    union {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *val;      <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 自定义类型</span>
        uint64_t u64;   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 无符号整形</span>
        int64_t s64;    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 有符号整形</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> d;       <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 浮点型</span>
    } v;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 指向下一个键值对节点</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictEntry *next;
} dictEntry;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 定义了字典操作的公共方法,类似于adlist.h文件中list的定义,将对节点的公共操作方法统一定义。搞不明白为什么要命名为dictType */</span>
typedef <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictType {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* hash方法,根据关键字计算哈希值 */</span>
    unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*hashFunction)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 复制key */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *(*keyDup)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 复制value */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *(*valDup)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *obj);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 关键字比较方法 */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> (*keyCompare)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key1, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key2);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 销毁key */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (*keyDestructor)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 销毁value */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (*valDestructor)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *obj);
} dictType;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* This is our hash table structure. Every dictionary has two of this as we
 * implement incremental rehashing, for the old to the new table. */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 哈希表结构 */</span>
typedef <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictht {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 散列数组。哈希表内部是基于数组,数组的元素是dictEntry *类型,所以这里是指针数组。</span>
    dictEntry **table;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 散列数组的长度</span>
    unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> size;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// sizemask等于size减1</span>
    unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> sizemask;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 散列数组中已经被使用的节点数量</span>
    unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> used;
} dictht;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 字典的主操作类,对dictht结构再次包装  */</span>
typedef <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dict {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 字典类型</span>
    dictType *type;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 私有数据指针</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 一个字典中有两个哈希表,后面的分析中,我们将ht[0]称作就表,ht[1]称作新表</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*  dict的rehash。通常情况下,所有的数据都是存在放dict的ht[0]中,ht[1]只在rehash的时候使用。
        dict进行rehash操作的时候,将ht[0]中的所有数据rehash到ht[1]中。然后将ht[1]赋值给ht[0],
        并清空ht[1]。rehash操作我们会在后面详细看到。
    */</span>
    dictht ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 数据动态迁移的位置,如果rehashidx == -1说明没有rehash过</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> rehashidx; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* rehashing not in progress if rehashidx == -1 */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 当前正在使用的迭代器的数量</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> iterators; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* number of iterators currently running */</span>
} dict;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* If safe is set to 1 this is a safe iterator, that means, you can call
 * dictAdd, dictFind, and other functions against the dictionary even while
 * iterating. Otherwise it is a non safe iterator, and only dictNext()
 * should be called while iterating. */</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* dict的迭代器定义,该迭代器有安全和不安全之分,这个跟dict的rehash操作有关,我们后面会详细说 */</span>
typedef <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> dictIterator {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 当前使用的字典dict */</span>
    dict *d;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 当前迭代器下标 */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> index;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* table指示字典中散列表下标,safe指明该迭代器是否安全 */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> table, safe;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 键值对节点指针 */</span>
    dictEntry *entry, *nextEntry;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* unsafe iterator fingerprint for misuse detection. */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> fingerprint;
} dictIterator;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 遍历回调函数 */</span>
typedef <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (dictScanFunction)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> dictEntry *de);

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* This is the initial size of every hash table */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 散列数组的初始长度 */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> DICT_HT_INITIAL_SIZE     4</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 下面是节点(键值对)操作的宏定义 */</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* ------------------------------- Macros ------------------------------------*/</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 释放节点value,实际上调用dictType中的valDestructor函数 */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictFreeVal(d, entry) \</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((d)->type->valDestructor) \
        (d)->type->valDestructor((d)->privdata, (entry)->v.val)

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 设置节点value */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictSetVal(d, entry, _val_) do { \</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((d)->type->valDup) \
        entry->v.val = (d)->type->valDup((d)->privdata, _val_); \
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> \
        entry->v.val = (_val_); \
} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 设置节点的值value,类型为signed int */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictSetSignedIntegerVal(entry, _val_) \</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span> { entry->v.s64 = _val_; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 设置节点的值value,类型为unsigned int */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictSetUnsignedIntegerVal(entry, _val_) \</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span> { entry->v.u64 = _val_; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 设置节点的值value,类型为double */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictSetDoubleVal(entry, _val_) \</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span> { entry->v.d = _val_; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 释放节点的键key */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictFreeKey(d, entry) \</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((d)->type->keyDestructor) \
        (d)->type->keyDestructor((d)->privdata, (entry)->key)

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 设置节点的键key */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictSetKey(d, entry, _key_) do { \</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((d)->type->keyDup) \
        entry->key = (d)->type->keyDup((d)->privdata, _key_); \
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> \
        entry->key = (_key_); \
} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断两个key是否相等</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictCompareKeys(d, key1, key2) \</span>
    (((d)->type->keyCompare) ? \
        (d)->type->keyCompare((d)->privdata, key1, key2) : \
        (key1) == (key2))

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取指定key的哈希值*/</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictHashKey(d, key) (d)->type->hashFunction(key)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取节点的key值*/</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictGetKey(he) ((he)->key)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取节点的value值 */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictGetVal(he) ((he)->v.val)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取节点的value值,类型为signed int */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictGetSignedIntegerVal(he) ((he)->v.s64)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取节点的value值,类型为unsigned int */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictGetUnsignedIntegerVal(he) ((he)->v.u64)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取节点的value值,类型为double */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictGetDoubleVal(he) ((he)->v.d)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取字典中哈希表的总长度 */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 获取字典中哈希表中已经被使用的节点数量 */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictSize(d) ((d)->ht[0].used+(d)->ht[1].used)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 判断字典dict是否正在执行rehash操作 */</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> dictIsRehashing(d) ((d)->rehashidx != -1)</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* API */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 下面定义了操作字典的方法 */</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建一个字典dict</span>
dict *dictCreate(dictType *type, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privDataPtr);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 字典容量扩充</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictExpand(dict *d, unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> size);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据key和value往字典中添加一个键值对</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictAdd(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *val);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 往字典中添加一个只有key的dictEntry结构</span>
dictEntry *dictAddRaw(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictReplace(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *val);
dictEntry *dictReplaceRaw(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据key删除字典中的一个键值对</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictDelete(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictDeleteNoFree(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 释放整个字典</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictRelease(dict *d);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据key在字典中查找一个键值对</span>
dictEntry * dictFind(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据key在字典中查找对应的value</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *dictFetchValue(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 重新计算字典大小</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictResize(dict *d);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 获取字典的普通迭代器</span>
dictIterator *dictGetIterator(dict *d);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 获取字典的安全迭代器</span>
dictIterator *dictGetSafeIterator(dict *d);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据迭代器获取下一个键值对</span>
dictEntry *dictNext(dictIterator *iter);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 释放迭代器</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictReleaseIterator(dictIterator *iter);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 随机获取一个键值对</span>
dictEntry *dictGetRandomKey(dict *d);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 打印字典当前状态</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictPrintStats(dict *d);
unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictGenHashFunction(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> len);
unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictGenCaseHashFunction(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *buf, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> len);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 清空字典</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictEmpty(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>(callback)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>*));
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictEnableResize(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictDisableResize(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictRehash(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> n);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictRehashMilliseconds(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> ms);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictSetHashFunctionSeed(unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> initval);
unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictGetHashFunctionSeed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>);
unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> dictScan(dict *d, unsigned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> v, dictScanFunction *fn, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata);

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Hash table types */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 哈希表类型 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> dictType dictTypeHeapStringCopyKey;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> dictType dictTypeHeapStrings;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> dictType dictTypeHeapStringCopyKeyValue;

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">endif</span> /* __DICT_H */</span>
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li><li style="box-sizing: border-box; padding: 0px 5px;">124</li><li style="box-sizing: border-box; padding: 0px 5px;">125</li><li style="box-sizing: border-box; padding: 0px 5px;">126</li><li style="box-sizing: border-box; padding: 0px 5px;">127</li><li style="box-sizing: border-box; padding: 0px 5px;">128</li><li style="box-sizing: border-box; padding: 0px 5px;">129</li><li style="box-sizing: border-box; padding: 0px 5px;">130</li><li style="box-sizing: border-box; padding: 0px 5px;">131</li><li style="box-sizing: border-box; padding: 0px 5px;">132</li><li style="box-sizing: border-box; padding: 0px 5px;">133</li><li style="box-sizing: border-box; padding: 0px 5px;">134</li><li style="box-sizing: border-box; padding: 0px 5px;">135</li><li style="box-sizing: border-box; padding: 0px 5px;">136</li><li style="box-sizing: border-box; padding: 0px 5px;">137</li><li style="box-sizing: border-box; padding: 0px 5px;">138</li><li style="box-sizing: border-box; padding: 0px 5px;">139</li><li style="box-sizing: border-box; padding: 0px 5px;">140</li><li style="box-sizing: border-box; padding: 0px 5px;">141</li><li style="box-sizing: border-box; padding: 0px 5px;">142</li><li style="box-sizing: border-box; padding: 0px 5px;">143</li><li style="box-sizing: border-box; padding: 0px 5px;">144</li><li style="box-sizing: border-box; padding: 0px 5px;">145</li><li style="box-sizing: border-box; padding: 0px 5px;">146</li><li style="box-sizing: border-box; padding: 0px 5px;">147</li><li style="box-sizing: border-box; padding: 0px 5px;">148</li><li style="box-sizing: border-box; padding: 0px 5px;">149</li><li style="box-sizing: border-box; padding: 0px 5px;">150</li><li style="box-sizing: border-box; padding: 0px 5px;">151</li><li style="box-sizing: border-box; padding: 0px 5px;">152</li><li style="box-sizing: border-box; padding: 0px 5px;">153</li><li style="box-sizing: border-box; padding: 0px 5px;">154</li><li style="box-sizing: border-box; padding: 0px 5px;">155</li><li style="box-sizing: border-box; padding: 0px 5px;">156</li><li style="box-sizing: border-box; padding: 0px 5px;">157</li><li style="box-sizing: border-box; padding: 0px 5px;">158</li><li style="box-sizing: border-box; padding: 0px 5px;">159</li><li style="box-sizing: border-box; padding: 0px 5px;">160</li><li style="box-sizing: border-box; padding: 0px 5px;">161</li><li style="box-sizing: border-box; padding: 0px 5px;">162</li><li style="box-sizing: border-box; padding: 0px 5px;">163</li><li style="box-sizing: border-box; padding: 0px 5px;">164</li><li style="box-sizing: border-box; padding: 0px 5px;">165</li><li style="box-sizing: border-box; padding: 0px 5px;">166</li><li style="box-sizing: border-box; padding: 0px 5px;">167</li><li style="box-sizing: border-box; padding: 0px 5px;">168</li><li style="box-sizing: border-box; padding: 0px 5px;">169</li><li style="box-sizing: border-box; padding: 0px 5px;">170</li><li style="box-sizing: border-box; padding: 0px 5px;">171</li><li style="box-sizing: border-box; padding: 0px 5px;">172</li><li style="box-sizing: border-box; padding: 0px 5px;">173</li><li style="box-sizing: border-box; padding: 0px 5px;">174</li><li style="box-sizing: border-box; padding: 0px 5px;">175</li><li style="box-sizing: border-box; padding: 0px 5px;">176</li><li style="box-sizing: border-box; padding: 0px 5px;">177</li><li style="box-sizing: border-box; padding: 0px 5px;">178</li><li style="box-sizing: border-box; padding: 0px 5px;">179</li><li style="box-sizing: border-box; padding: 0px 5px;">180</li><li style="box-sizing: border-box; padding: 0px 5px;">181</li><li style="box-sizing: border-box; padding: 0px 5px;">182</li><li style="box-sizing: border-box; padding: 0px 5px;">183</li><li style="box-sizing: border-box; padding: 0px 5px;">184</li><li style="box-sizing: border-box; padding: 0px 5px;">185</li><li style="box-sizing: border-box; padding: 0px 5px;">186</li><li style="box-sizing: border-box; padding: 0px 5px;">187</li><li style="box-sizing: border-box; padding: 0px 5px;">188</li><li style="box-sizing: border-box; padding: 0px 5px;">189</li><li style="box-sizing: border-box; padding: 0px 5px;">190</li><li style="box-sizing: border-box; padding: 0px 5px;">191</li><li style="box-sizing: border-box; padding: 0px 5px;">192</li><li style="box-sizing: border-box; padding: 0px 5px;">193</li><li style="box-sizing: border-box; padding: 0px 5px;">194</li><li style="box-sizing: border-box; padding: 0px 5px;">195</li><li style="box-sizing: border-box; padding: 0px 5px;">196</li><li style="box-sizing: border-box; padding: 0px 5px;">197</li><li style="box-sizing: border-box; padding: 0px 5px;">198</li><li style="box-sizing: border-box; padding: 0px 5px;">199</li><li style="box-sizing: border-box; padding: 0px 5px;">200</li><li style="box-sizing: border-box; padding: 0px 5px;">201</li><li style="box-sizing: border-box; padding: 0px 5px;">202</li><li style="box-sizing: border-box; padding: 0px 5px;">203</li><li style="box-sizing: border-box; padding: 0px 5px;">204</li><li style="box-sizing: border-box; padding: 0px 5px;">205</li><li style="box-sizing: border-box; padding: 0px 5px;">206</li><li style="box-sizing: border-box; padding: 0px 5px;">207</li><li style="box-sizing: border-box; padding: 0px 5px;">208</li><li style="box-sizing: border-box; padding: 0px 5px;">209</li><li style="box-sizing: border-box; padding: 0px 5px;">210</li><li style="box-sizing: border-box; padding: 0px 5px;">211</li><li style="box-sizing: border-box; padding: 0px 5px;">212</li><li style="box-sizing: border-box; padding: 0px 5px;">213</li><li style="box-sizing: border-box; padding: 0px 5px;">214</li><li style="box-sizing: border-box; padding: 0px 5px;">215</li><li style="box-sizing: border-box; padding: 0px 5px;">216</li><li style="box-sizing: border-box; padding: 0px 5px;">217</li><li style="box-sizing: border-box; padding: 0px 5px;">218</li><li style="box-sizing: border-box; padding: 0px 5px;">219</li><li style="box-sizing: border-box; padding: 0px 5px;">220</li><li style="box-sizing: border-box; padding: 0px 5px;">221</li><li style="box-sizing: border-box; padding: 0px 5px;">222</li><li style="box-sizing: border-box; padding: 0px 5px;">223</li><li style="box-sizing: border-box; padding: 0px 5px;">224</li><li style="box-sizing: border-box; padding: 0px 5px;">225</li><li style="box-sizing: border-box; padding: 0px 5px;">226</li><li style="box-sizing: border-box; padding: 0px 5px;">227</li><li style="box-sizing: border-box; padding: 0px 5px;">228</li><li style="box-sizing: border-box; padding: 0px 5px;">229</li><li style="box-sizing: border-box; padding: 0px 5px;">230</li><li style="box-sizing: border-box; padding: 0px 5px;">231</li><li style="box-sizing: border-box; padding: 0px 5px;">232</li><li style="box-sizing: border-box; padding: 0px 5px;">233</li><li style="box-sizing: border-box; padding: 0px 5px;">234</li><li style="box-sizing: border-box; padding: 0px 5px;">235</li><li style="box-sizing: border-box; padding: 0px 5px;">236</li><li style="box-sizing: border-box; padding: 0px 5px;">237</li><li style="box-sizing: border-box; padding: 0px 5px;">238</li><li style="box-sizing: border-box; padding: 0px 5px;">239</li><li style="box-sizing: border-box; padding: 0px 5px;">240</li><li style="box-sizing: border-box; padding: 0px 5px;">241</li><li style="box-sizing: border-box; padding: 0px 5px;">242</li><li style="box-sizing: border-box; padding: 0px 5px;">243</li><li style="box-sizing: border-box; padding: 0px 5px;">244</li><li style="box-sizing: border-box; padding: 0px 5px;">245</li><li style="box-sizing: border-box; padding: 0px 5px;">246</li><li style="box-sizing: border-box; padding: 0px 5px;">247</li><li style="box-sizing: border-box; padding: 0px 5px;">248</li><li style="box-sizing: border-box; padding: 0px 5px;">249</li><li style="box-sizing: border-box; padding: 0px 5px;">250</li><li style="box-sizing: border-box; padding: 0px 5px;">251</li><li style="box-sizing: border-box; padding: 0px 5px;">252</li><li style="box-sizing: border-box; padding: 0px 5px;">253</li><li style="box-sizing: border-box; padding: 0px 5px;">254</li><li style="box-sizing: border-box; padding: 0px 5px;">255</li><li style="box-sizing: border-box; padding: 0px 5px;">256</li><li style="box-sizing: border-box; padding: 0px 5px;">257</li><li style="box-sizing: border-box; padding: 0px 5px;">258</li><li style="box-sizing: border-box; padding: 0px 5px;">259</li></ul>

dict.c源文件:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Hash Tables Implementation.
 *
 * This file implements in memory hash tables with insert/del/replace/find/
 * get-random-element operations. Hash tables will auto resize if needed
 * tables of power of two in size are used, collisions are handled by
 * chaining. See the source code for more information... :)
 *
 * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Redis nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */</span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "fmacros.h"</span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <stdio.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <stdlib.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <string.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <stdarg.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <limits.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <sys/time.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <ctype.h></span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "dict.h"</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "zmalloc.h"</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "redisassert.h"</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Using dictEnableResize() / dictDisableResize() we make possible to
 * enable/disable resizing of the hash table as needed. This is very important
 * for Redis, as we use copy-on-write and don't want to move too much memory
 * around when there is a child performing saving operations.
 *
 * Note that even when dict_can_resize is set to 0, not all resizes are
 * prevented: a hash table is still allowed to grow if the ratio between
 * the number of elements and the buckets > dict_force_resize_ratio. */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*通过dictEnableResize() / dictDisableResize()方法我们可以启用/禁用ht空间重新分配.  
* 这对于Redis来说很重要, 因为我们用的是写时复制机制而且不想在子进程执行保存操作时移动过多的内存. 
* 
* 需要注意的是,即使dict_can_resize设置为0, 并不意味着所有的resize操作都被禁止: 
* 一个a hash table仍然可以拓展空间,如果bucket与element数量之间的比例  > dict_force_resize_ratio。 
*/</span> 
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dict_can_resize = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dict_force_resize_ratio = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* -------------------------- private prototypes ---------------------------- */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** 下面的方法由static修饰,是私有方法 */</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断字典dict是否需要扩容</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictExpandIfNeeded(dict *ht);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 由于哈希表的容量只取2的整数次幂,该函数对给定数字以2的整数次幂进行上取整</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> _dictNextPower(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> size);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 返回给定新key的对应空闲的索引地址</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictKeyIndex(dict *ht, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 字典的初始化</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictInit(dict *ht, dictType *type, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privDataPtr);

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* -------------------------- hash functions -------------------------------- */</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Thomas Wang's 32 bit Mix Function */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*  Thomas Wang's 32 bit Mix哈希算法,对一个整型进行哈希。这是一种基于移位运算的哈希算法,直接根据
    给定的key值进行移位操作,具有比较高的效率
*/</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictIntHashFunction(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> key)
{
    key += ~(key << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>);
    key ^=  (key >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>);
    key +=  (key << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>);
    key ^=  (key >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>);
    key += ~(key << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">11</span>);
    key ^=  (key >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> key;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 哈希种子,跟产生随机数的种子类似</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> uint32_t dict_hash_function_seed = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5381</span>;

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 设置新的哈希种子</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictSetHashFunctionSeed(uint32_t seed) {
    dict_hash_function_seed = seed;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 获取当前哈希种子的数值</span>
uint32_t dictGetHashFunctionSeed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dict_hash_function_seed;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* MurmurHash2, by Austin Appleby
 * Note - This code makes a few assumptions about how your machine behaves -
 * 1. We can read a 4-byte value from any address without crashing
 * 2. sizeof(int) == 4
 *
 * And it has a few limitations -
 *
 * 1. It will not work incrementally.
 * 2. It will not produce the same results on little-endian and big-endian
 *    machines.
 */</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* MurmurHash2哈希算法,我也不知道是什么东东。网上资料显示MurmurHash2主要对一个字符串进行哈希,其
    基本思想是将给定的key按每四个字符分组,每四个字符当做一个uint32_t整形进行处理。
 */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// MurmurHash2哈希算法的实现,根据key值和指定长度进行哈希</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictGenHashFunction(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> len) {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 'm' and 'r' are mixing constants generated offline.
     They're not really 'magic', they just happen to work well.  */</span>
    uint32_t seed = dict_hash_function_seed;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> uint32_t m = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x5bd1e995</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> r = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Initialize the hash to a 'random' value */</span>
    uint32_t h = seed ^ len;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Mix 4 bytes at a time into the hash */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *data = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *)key;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(len >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>) {
        uint32_t k = *(uint32_t*)data;

        k *= m;
        k ^= k >> r;
        k *= m;

        h *= m;
        h ^= k;

        data += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>;
        len -= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>;
    }

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Handle the last few bytes of the input array  */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">switch</span>(len) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>: h ^= data[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>: h ^= data[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>: h ^= data[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]; h *= m;
    };

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Do a few final mixes of the hash to ensure the last few
     * bytes are well-incorporated. */</span>
    h ^= h >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">13</span>;
    h *= m;
    h ^= h >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>)h;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* And a case insensitive hash function (based on djb hash) */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 一种比较简单的哈希算法,也是对字符串进行哈希的 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictGenCaseHashFunction(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *buf, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> len) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> hash = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>)dict_hash_function_seed;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (len--)
        hash = ((hash << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) + hash) + (tolower(*buf++)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* hash * 33 + c */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> hash;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* ----------------------------- API implementation ------------------------- */</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Reset a hash table already initialized with ht_init().
 * NOTE: This function should only be called by ht_destroy(). */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 私有方法,重置哈希表,参数是dictht哈希表结构。只能在ht_destroy()中使用 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> _dictReset(dictht *ht)
{   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 简单地清空相应变量</span>
    ht->table = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 前面解释过dictht.table其实就是一个指针数组</span>
    ht->size = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    ht->sizemask = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    ht->used = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Create a new hash table */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 创建一个字典dict */</span>
dict *dictCreate(dictType *type,
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privDataPtr)
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 先分配内存</span>
    dict *d = zmalloc(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(*d));

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 接着进行初始化,_dictInit是一个私有方法</span>
    _dictInit(d,type,privDataPtr);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> d;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Initialize the hash table */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 初始化一个字典</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictInit(dict *d, dictType *type,
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privDataPtr)
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 重置两个哈希表,一个字典dict钟有两个哈希表</span>
    _dictReset(&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]);
    _dictReset(&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 下面各个字段的含义见dict结构体的定义</span>
    d->type = type;
    d->privdata = privDataPtr;
    d->rehashidx = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    d->iterators = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Resize the table to the minimal size that contains all the elements,
 * but with the invariant of a USED/BUCKETS ratio near to <= 1 */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 调整哈希表容量,目标是用最小的散列数组来容纳所有的键值对。类似于C++ STL 的vector::shrink_to_fit函数 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictResize(dict *d)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> minimal;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果 dict_can_resize = 0或者正在执行rehash操作,则拒绝resize操作。</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dict_can_resize || dictIsRehashing(d)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_ERR;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 最少的数值就是散列数组中目前存在的键值对数量</span>
    minimal = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (minimal < DICT_HT_INITIAL_SIZE)
        minimal = DICT_HT_INITIAL_SIZE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 防止过小</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用dictExpand进行容量调整</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dictExpand(d, minimal);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Expand or create the hash table */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 字典容量扩充</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictExpand(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> size)
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 新的哈希表</span>
    dictht n; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* the new hash table */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 哈希表的容量被设置为2的整数次幂,这里对给定的数值以2的整数次幂进行上取整</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> realsize = _dictNextPower(size);

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* the size is invalid if it is smaller than the number of
     * elements already inside the hash table */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果字典dict正在rehash或者realsize数值不合法,拒绝expand操作</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d) || d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span> > size)
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_ERR;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Allocate the new hash table and initialize all pointers to NULL */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 按指定长度重新分配一个新的哈希表</span>
    n<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span> = realsize;
    n<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.sizemask</span> = realsize-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    n<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span> = zcalloc(realsize*<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(dictEntry*));
    n<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Is this the first initialization? If so it's not really a rehashing
     * we just set the first hash table so that it can accept keys. */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果旧表为空,则这并不是一次rehashing操作,直接将新的哈希表赋值给旧表指针</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span> == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>) {
        d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = n;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK;
    }

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Prepare a second hash table for incremental rehashing */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 将新创建的哈希表赋值给ht[1],rehashidx设置为0,准备进行渐进式的rehash操作 */</span>
    d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] = n;
    d->rehashidx = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Performs N steps of incremental rehashing. Returns 1 if there are still
 * keys to move from the old to the new hash table, otherwise 0 is returned.
 * Note that a rehashing step consists in moving a bucket (that may have more
 * than one key as we use chaining) from the old to the new hash table. */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 执行n步渐进式的rehash操作,如果还有key需要从旧表迁移到新表则返回1,否则返回0 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictRehash(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> n) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dictIsRehashing(d)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// n步渐进式的rehash操作就是每次只迁移哈希数组中的n歌元素</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(n--) {
        dictEntry *de, *nextde;

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Check if we already rehashed the whole table... */</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 检查是否对整个哈希表进行了rehash操作</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span> == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
            zfree(d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>);
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
            _dictReset(&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]);
            d->rehashidx = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        }

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Note that rehashidx can't overflow as we are sure there are more
         * elements because ht[0].used != 0 */</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// rehashidx标记的是当前rehash操作进行到了ht[0]旧表的那个位置(下标),因此需要判断它是否操作ht[0]的长度</span>
        assert(d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span> > (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>)d->rehashidx);
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 跳过ht[0]中前面为空的位置</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[d->rehashidx] == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>) d->rehashidx++;
        de = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[d->rehashidx];
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Move all the keys in this bucket from the old to the new hash HT */</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 下面的操作将每个节点(键值对)从ht[0]迁移到ht[1],此过程需要重新计算每个节点key的哈希值</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(de) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h;

            nextde = de->next;
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Get the index in the new hash table */</span>
            h = dictHashKey(d, de->key) & d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.sizemask</span>;
            de->next = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[h];
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[h] = de;
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>--;
            d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>++;
            de = nextde;
        }
        d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[d->rehashidx] = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
        d->rehashidx++;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 获取当前的时间戳(一毫秒为单位)</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> timeInMilliseconds(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> timeval tv;

    gettimeofday(&tv,<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>)tv<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.tv_sec</span>)*<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>)+(tv<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.tv_usec</span>/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Rehash for an amount of time between ms milliseconds and ms+1 milliseconds */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 在指定的时间内执行rehash操作 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictRehashMilliseconds(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> ms) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> start = timeInMilliseconds();
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> rehashes = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(dictRehash(d,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>)) {
        rehashes += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (timeInMilliseconds()-start > ms) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> rehashes;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* This function performs just a step of rehashing, and only if there are
 * no safe iterators bound to our hash table. When we have iterators in the
 * middle of a rehashing we can't mess with the two hash tables otherwise
 * some element can be missed or duplicated.
 *
 * This function is called by common lookup or update operations in the
 * dictionary so that the hash table automatically migrates from H1 to H2
 * while it is actively used. */</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 在执行查询或更新操作时,如果符合rehash条件会触发一次rehash操作,每次执行一步 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> _dictRehashStep(dict *d) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->iterators == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) dictRehash(d,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Add an element to the target hash table */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 往字典中添加一个新的键值对 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictAdd(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *val)
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 往字典中添加一个只有key的dictEntry结构</span>
    dictEntry *entry = dictAddRaw(d,key);

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果entry == NULL,说明该key已经存在,添加失败</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!entry) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_ERR;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 设置对应的value</span>
    dictSetVal(d, entry, val);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Low level add. This function adds the entry but instead of setting
 * a value returns the dictEntry structure to the user, that will make
 * sure to fill the value field as he wishes.
 *
 * This function is also directly exposed to user API to be called
 * mainly in order to store non-pointers inside the hash value, example:
 *
 * entry = dictAddRaw(dict,mykey);
 * if (entry != NULL) dictSetSignedIntegerVal(entry,1000);
 *
 * Return values:
 *
 * If key already exists NULL is returned.
 * If key was added, the hash entry is returned to be manipulated by the caller.
 */</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* dictAdd的底层实现方法。往字典中添加一个只有key的dictEntry结构,如果给定的key已经存在,则返回NULL */</span>
dictEntry *dictAddRaw(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> index;
    dictEntry *entry;
    dictht *ht;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 触发rehash操作</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d)) _dictRehashStep(d);

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Get the index of the new element, or -1 if
     * the element already exists. */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果给定key已经存在,则操作失败直接返回NULL</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((index = _dictKeyIndex(d, key)) == -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Allocate the memory and store the new entry */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果字典正在rehash,则插入到新表ht[1],否则插入到旧表ht[0]</span>
    ht = dictIsRehashing(d) ? &d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] : &d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
    entry = zmalloc(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(*entry));
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 使用拉链法处理冲突</span>
    entry->next = ht->table[index];
    ht->table[index] = entry;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 更新键值对数量</span>
    ht->used++;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Set the hash entry fields. */</span>
    dictSetKey(d, entry, key);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> entry;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Add an element, discarding the old if the key already exists.
 * Return 1 if the key was added from scratch, 0 if there was already an
 * element with such key and dictReplace() just performed a value update
 * operation. */</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 添加或替换字典中的键值对,如果返回值为1,表示执行了添加操作,如果返回值是0,表示执行了替换操作 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictReplace(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *val)
{
    dictEntry *entry, auxentry;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Try to add the element. If the key
     * does not exists dictAdd will suceed. */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 现场时添加一个键值对,如果添加成功则直接返回,否则执行替换操作</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictAdd(d, key, val) == DICT_OK)
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* It already exists, get the entry */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据key找到键值对节点</span>
    entry = dictFind(d, key);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Set the new value and free the old one. Note that it is important
     * to do that in this order, as the value may just be exactly the same
     * as the previous one. In this context, think to reference counting,
     * you want to increment (set), and then decrement (free), and not the
     * reverse. */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 设置新值,释放旧值。需要考虑value是同一个的情况</span>
    auxentry = *entry;
    dictSetVal(d, entry, val);
    dictFreeVal(d, &auxentry);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* dictReplaceRaw() is simply a version of dictAddRaw() that always
 * returns the hash entry of the specified key, even if the key already
 * exists and can't be added (in that case the entry of the already
 * existing key is returned.)
 *
 * See dictAddRaw() for more information. */</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 该方法可以看多是dictAddRaw()的扩展方法,它重视返回一个给定值的键值对结构指针,如果不存在这样的键值对则先执行插入操作 */</span>
dictEntry *dictReplaceRaw(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key) {
    dictEntry *entry = dictFind(d,key);

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> entry ? entry : dictAddRaw(d,key);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Search and remove an element */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 查找并删除给定key对应的键值对,nofree决定是否要销毁目标键值对 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictGenericDelete(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> nofree)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h, idx;
    dictEntry *he, *prevHe;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> table;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span> == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_ERR; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* d->ht[0].table is NULL */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d)) _dictRehashStep(d);
    h = dictHashKey(d, key);    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 计算key对应的哈希值,以确定目标节点在散列数组的下标位置</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (table = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; table <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; table++) {
        idx = h & d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.sizemask</span>;
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 找到目标节点所在的链表,下面的操作就成了如何在链表中删除一个指定元素</span>
        he = d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[idx];   
        prevHe = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictCompareKeys(d, key, he->key)) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Unlink the element from the list */</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (prevHe)
                    prevHe->next = he->next;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>
                    d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[idx] = he->next;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!nofree) {
                    dictFreeKey(d, he);
                    dictFreeVal(d, he);
                }
                zfree(he);
                d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>--;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK;
            }
            prevHe = he;
            he = he->next;
        }
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果没有执行rehash操作,全部元素都在ht[0]中,不需要再找ht[1]</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dictIsRehashing(d)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_ERR; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* not found */</span>
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* dictGenericDelete()函数的包装 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictDelete(dict *ht, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dictGenericDelete(ht,key,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* dictGenericDelete()函数的包装 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dictDeleteNoFree(dict *ht, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dictGenericDelete(ht,key,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Destroy an entire dictionary */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 销毁整个字典dict */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictClear(dict *d, dictht *ht, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>(callback)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *)) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> i;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Free all the elements */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 释放全部键值对 */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < ht->size && ht->used > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i++) {
        dictEntry *he, *nextHe;

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 销毁私有数据</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (callback && (i & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">65535</span>) == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) callback(d->privdata);

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 销毁每个槽对应的链表(拉链法)</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((he = ht->table[i]) == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he) {
            nextHe = he->next;
            dictFreeKey(d, he);
            dictFreeVal(d, he);
            zfree(he);
            ht->used--;
            he = nextHe;
        }
    }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Free the table and the allocated cache structure */</span>
    zfree(ht->table);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Re-initialize the table */</span>
    _dictReset(ht);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* never fails */</span>
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Clear & Release the hash table */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 清除并销毁字典dict内部的哈希表 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictRelease(dict *d)
{
    _dictClear(d,&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>],<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);
    _dictClear(d,&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>],<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);
    zfree(d);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 根据给定key查找对应的键值对,没什么难点*/</span>
dictEntry *dictFind(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key)
{
    dictEntry *he;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h, idx, table;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span> == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* We don't have a table at all */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d)) _dictRehashStep(d);
    h = dictHashKey(d, key);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (table = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; table <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; table++) {
        idx = h & d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.sizemask</span>;
        he = d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[idx];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictCompareKeys(d, key, he->key))
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> he;
            he = he->next;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dictIsRehashing(d)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 根据给定key获取对应的value */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *dictFetchValue(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key) {
    dictEntry *he;

    he = dictFind(d,key);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> he ? dictGetVal(he) : <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* A fingerprint is a 64 bit number that represents the state of the dictionary
 * at a given time, it's just a few dict properties xored together.
 * When an unsafe iterator is initialized, we get the dict fingerprint, and check
 * the fingerprint again when the iterator is released.
 * If the two fingerprints are different it means that the user of the iterator
 * performed forbidden operations against the dictionary while iterating. */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*  一个fingerprint为一个64位数值,用来表示某个时刻dict的状态,它由dict的一些属性通过位操作计算得到。
*   当一个非安全迭代器初始后, 会产生一个fingerprint值。 在该迭代器被释放时会重新检查这个fingerprint值。
*   如果前后两个fingerprint值不一致,说明在迭代字典时iterator执行了某些非法操作。
*/</span> 
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> dictFingerprint(dict *d) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> integers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>], hash = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> j;

    integers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>) d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>;
    integers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span>;
    integers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>;
    integers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>) d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>;
    integers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>] = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span>;
    integers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>] = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* We hash N integers by summing every successive integer with the integer
     * hashing of the previous sum. Basically:
     *
     * Result = hash(hash(hash(int1)+int2)+int3) ...
     *
     * This way the same set of integers in a different order will (likely) hash
     * to a different number. */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (j = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; j < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>; j++) {
        hash += integers[j];
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* For the hashing step we use Tomas Wang's 64 bit integer hash. */</span>
        hash = (~hash) + (hash << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">21</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// hash = (hash << 21) - hash - 1;</span>
        hash = hash ^ (hash >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>);
        hash = (hash + (hash << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>)) + (hash << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// hash * 265</span>
        hash = hash ^ (hash >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>);
        hash = (hash + (hash << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)) + (hash << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// hash * 21</span>
        hash = hash ^ (hash >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">28</span>);
        hash = hash + (hash << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">31</span>);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> hash;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 初始化一个普通迭代器 */</span>
dictIterator *dictGetIterator(dict *d)
{
    dictIterator *iter = zmalloc(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(*iter));

    iter->d = d;
    iter->table = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    iter->index = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    iter->safe = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    iter->entry = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
    iter->nextEntry = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> iter;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 初始化一个安全迭代器 */</span>
dictIterator *dictGetSafeIterator(dict *d) {
    dictIterator *i = dictGetIterator(d);

    i->safe = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> i;
}

dictEntry *dictNext(dictIterator *iter)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (iter->entry == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>) {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 首次迭代需要初始化entry属性</span>
            dictht *ht = &iter->d->ht[iter->table];
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (iter->index == -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> && iter->table == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (iter->safe)
                    iter->d->iterators++;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>
                    iter->fingerprint = dictFingerprint(iter->d);
            }
            iter->index++;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (iter->index >= (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>) ht->size) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果正在执行rehash操作,则要处理从旧表ht[0]到ht[1]的情形</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(iter->d) && iter->table == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
                    iter->table++;
                    iter->index = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
                    ht = &iter->d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;
                }
            }
            iter->entry = ht->table[iter->index];
        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
            iter->entry = iter->nextEntry;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (iter->entry) {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* We need to save the 'next' here, the iterator user
             * may delete the entry we are returning. */</span>
            iter->nextEntry = iter->entry->next;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> iter->entry;
        }
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 释放迭代器 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictReleaseIterator(dictIterator *iter)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!(iter->index == -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> && iter->table == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (iter->safe)
            iter->d->iterators--;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>
            assert(iter->fingerprint == dictFingerprint(iter->d));
    }
    zfree(iter);
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Return a random entry from the hash table. Useful to
 * implement randomized algorithms */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 从字典dict中随机返回一个键值对,需要使用随机函数 */</span>
dictEntry *dictGetRandomKey(dict *d)
{
    dictEntry *he, *orighe;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> listlen, listele;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果字典dict没有任何元素,直接返回</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictSize(d) == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 触发一次rehash操作</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d)) _dictRehashStep(d);

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 下面的做法是先随机选取散列数组中的一个槽,这样就得到一个链表(如果该槽中没有元素则重新选取),
        然后在该列表中随机选取一个键值对返回
    */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d)) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果字典正在rehash,则旧表ht[0]和新表ht[1]中都有数据</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span> {
            h = random() % (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span>+d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span>);
            he = (h >= d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span>) ? d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[h - d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span>] :
                                      d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[h];
        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);
    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span> {
            h = random() & d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.sizemask</span>;
            he = d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[h];
        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);
    }

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Now we found a non empty bucket, but it is a linked
     * list and we need to get a random element from the list.
     * The only sane way to do so is counting the elements and
     * select a random index. */</span>
     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 从链表中选取一个键值对 */</span>
    listlen = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    orighe = he;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 统计元素个数</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he) {
        he = he->next;
        listlen++;
    }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 随机选取下标</span>
    listele = random() % listlen;
    he = orighe;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 找到对应元素</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(listele--) he = he->next;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> he;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Function to reverse bits. Algorithm from:
 * http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 位翻转操作 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> rev(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> v) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> s = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span> * <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(v); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// bit size; must be power of 2</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> mask = ~<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> ((s >>= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
        mask ^= (mask << s);
        v = ((v >> s) & mask) | ((v << s) & ~mask);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> v;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* dictScan() is used to iterate over the elements of a dictionary.
 *
 * Iterating works the following way:
 *
 * 1) Initially you call the function using a cursor (v) value of 0.
 * 2) The function performs one step of the iteration, and returns the
 *    new cursor value you must use in the next call.
 * 3) When the returned cursor is 0, the iteration is complete.
 *
 * The function guarantees all elements present in the
 * dictionary get returned between the start and end of the iteration.
 * However it is possible some elements get returned multiple times.
 *
 * For every element returned, the callback argument 'fn' is
 * called with 'privdata' as first argument and the dictionary entry
 * 'de' as second argument.
 *
 * HOW IT WORKS.
 *
 * The iteration algorithm was designed by Pieter Noordhuis.
 * The main idea is to increment a cursor starting from the higher order
 * bits. That is, instead of incrementing the cursor normally, the bits
 * of the cursor are reversed, then the cursor is incremented, and finally
 * the bits are reversed again.
 *
 * This strategy is needed because the hash table may be resized between
 * iteration calls.
 *
 * dict.c hash tables are always power of two in size, and they
 * use chaining, so the position of an element in a given table is given
 * by computing the bitwise AND between Hash(key) and SIZE-1
 * (where SIZE-1 is always the mask that is equivalent to taking the rest
 *  of the division between the Hash of the key and SIZE).
 *
 * For example if the current hash table size is 16, the mask is
 * (in binary) 1111. The position of a key in the hash table will always be
 * the last four bits of the hash output, and so forth.
 *
 * WHAT HAPPENS IF THE TABLE CHANGES IN SIZE?
 *
 * If the hash table grows, elements can go anywhere in one multiple of
 * the old bucket: for example let's say we already iterated with
 * a 4 bit cursor 1100 (the mask is 1111 because hash table size = 16).
 *
 * If the hash table will be resized to 64 elements, then the new mask will
 * be 111111. The new buckets you obtain by substituting in ??1100
 * with either 0 or 1 can be targeted only by keys we already visited
 * when scanning the bucket 1100 in the smaller hash table.
 *
 * By iterating the higher bits first, because of the inverted counter, the
 * cursor does not need to restart if the table size gets bigger. It will
 * continue iterating using cursors without '1100' at the end, and also
 * without any other combination of the final 4 bits already explored.
 *
 * Similarly when the table size shrinks over time, for example going from
 * 16 to 8, if a combination of the lower three bits (the mask for size 8
 * is 111) were already completely explored, it would not be visited again
 * because we are sure we tried, for example, both 0111 and 1111 (all the
 * variations of the higher bit) so we don't need to test it again.
 *
 * WAIT... YOU HAVE *TWO* TABLES DURING REHASHING!
 *
 * Yes, this is true, but we always iterate the smaller table first, then
 * we test all the expansions of the current cursor into the larger
 * table. For example if the current cursor is 101 and we also have a
 * larger table of size 16, we also test (0)101 and (1)101 inside the larger
 * table. This reduces the problem back to having only one table, where
 * the larger one, if it exists, is just an expansion of the smaller one.
 *
 * LIMITATIONS
 *
 * This iterator is completely stateless, and this is a huge advantage,
 * including no additional memory used.
 *
 * The disadvantages resulting from this design are:
 *
 * 1) It is possible we return elements more than once. However this is usually
 *    easy to deal with in the application level.
 * 2) The iterator must return multiple elements per call, as it needs to always
 *    return all the keys chained in a given bucket, and all the expansions, so
 *    we are sure we don't miss keys moving during rehashing.
 * 3) The reverse cursor is somewhat hard to understand at first, but this
 *    comment is supposed to help.
 */</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 遍历字典dict中的每个键值对并执行指定的回调函数 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> dictScan(dict *d,
                       <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> v,
                       dictScanFunction *fn,
                       <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata)
{
    dictht *t0, *t1;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> dictEntry *de;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> m0, m1;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictSize(d) == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dictIsRehashing(d)) {
        t0 = &(d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]);
        m0 = t0->sizemask;

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Emit entries at cursor */</span>
        de = t0->table[v & m0];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (de) {
            fn(privdata, de);
            de = de->next;
        }

    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
        t0 = &d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
        t1 = &d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Make sure t0 is the smaller and t1 is the bigger table */</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (t0->size > t1->size) {
            t0 = &d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
            t1 = &d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
        }

        m0 = t0->sizemask;
        m1 = t1->sizemask;

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Emit entries at cursor */</span>
        de = t0->table[v & m0];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (de) {
            fn(privdata, de);
            de = de->next;
        }

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Iterate over indices in larger table that are the expansion
         * of the index pointed to by the cursor in the smaller table */</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span> {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Emit entries at cursor */</span>
            de = t1->table[v & m1];
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (de) {
                fn(privdata, de);
                de = de->next;
            }

            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Increment bits not covered by the smaller mask */</span>
            v = (((v | m0) + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) & ~m0) | (v & m0);

            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Continue while bits covered by mask difference is non-zero */</span>
        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (v & (m0 ^ m1));
    }

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Set unmasked bits so incrementing the reversed cursor
     * operates on the masked bits of the smaller table */</span>
    v |= ~m0;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Increment the reverse cursor */</span>
    v = rev(v);
    v++;
    v = rev(v);

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> v;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* ------------------------- private functions ------------------------------ */</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Expand the hash table if needed */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断字典dict是否需要扩容</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictExpandIfNeeded(dict *d)
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Incremental rehashing already in progress. Return. */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果正在执行rehash操作,则直接返回</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* If the hash table is empty expand it to the initial size. */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果字典中哈希表的为空,则为其扩展到初始大小</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span> == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dictExpand(d, DICT_HT_INITIAL_SIZE);

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* If we reached the 1:1 ratio, and we are allowed to resize the hash
     * table (global setting) or we should avoid it but the ratio between
     * elements/buckets is over the "safe" threshold, we resize doubling
     * the number of buckets. */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果满足下列条件(已用节点数>=节点总数或节点填充率过高),扩容两倍</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span> >= d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span> &&
        (dict_can_resize ||
         d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>/d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.size</span> > dict_force_resize_ratio))
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dictExpand(d, d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.used</span>*<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> DICT_OK;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Our hash table capability is a power of two */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 由于哈希表的容量只取2的整数次幂,该函数对给定数字以2的整数次幂进行上取整</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> _dictNextPower(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> size)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> i = DICT_HT_INITIAL_SIZE;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 不能超过长整形的最大值</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (size >= LONG_MAX) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> LONG_MAX;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 以2的整数次幂进行上取整</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i >= size)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> i;
        i *= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
    }
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Returns the index of a free slot that can be populated with
 * a hash entry for the given 'key'.
 * If the key already exists, -1 is returned.
 *
 * Note that if we are in the process of rehashing the hash table, the
 * index is always returned in the context of the second (new) hash table. */</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 返回给定key对应的空闲的索引节点,如果该key已经存在,则返回-1 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictKeyIndex(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h, idx, table;
    dictEntry *he;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Expand the hash table if needed */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (_dictExpandIfNeeded(d) == DICT_ERR)
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Compute the key hash value */</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用对应的哈希算法获得给定key的哈希值</span>
    h = dictHashKey(d, key);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (table = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; table <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; table++) {
        idx = h & d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.sizemask</span>;
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Search if this slot does not already contain the given key */</span>
        he = d->ht[table]<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.table</span>[idx];
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 依次比较该slot上的所有键值对的key是否和给定key相等</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictCompareKeys(d, key, he->key))
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
            he = he->next;
        }
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果不是正在执行rehash操作,第二个表为空表,无需继续查找</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dictIsRehashing(d)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> idx;
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 清空字典数据但不释放空间 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictEmpty(dict *d, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>(callback)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>*)) {
    _dictClear(d,&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>],callback);
    _dictClear(d,&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>],callback);
    d->rehashidx = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    d->iterators = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictEnableResize(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>) {
    dict_can_resize = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictDisableResize(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>) {
    dict_can_resize = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#if 0</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* The following is code that we don't use for Redis currently, but that is part
of the library. */</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* ----------------------- Debugging ------------------------*/</span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define DICT_STATS_VECTLEN 50</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> _dictPrintStatsHt(dictht *ht) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> i, slots = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, chainlen, maxchainlen = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> totchainlen = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> clvector[DICT_STATS_VECTLEN];

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ht->used == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
        printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No stats available for empty dictionaries\n"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < DICT_STATS_VECTLEN; i++) clvector[i] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < ht->size; i++) {
        dictEntry *he;

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ht->table[i] == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>) {
            clvector[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]++;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>;
        }
        slots++;
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* For each hash entry on this slot... */</span>
        chainlen = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        he = ht->table[i];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(he) {
            chainlen++;
            he = he->next;
        }
        clvector[(chainlen < DICT_STATS_VECTLEN) ? chainlen : (DICT_STATS_VECTLEN-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)]++;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (chainlen > maxchainlen) maxchainlen = chainlen;
        totchainlen += chainlen;
    }
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Hash table stats:\n"</span>);
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" table size: %ld\n"</span>, ht->size);
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" number of elements: %ld\n"</span>, ht->used);
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" different slots: %ld\n"</span>, slots);
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" max chain length: %ld\n"</span>, maxchainlen);
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" avg chain length (counted): %.02f\n"</span>, (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span>)totchainlen/slots);
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" avg chain length (computed): %.02f\n"</span>, (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span>)ht->used/slots);
    printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" Chain length distribution:\n"</span>);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < DICT_STATS_VECTLEN-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; i++) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (clvector[i] == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>;
        printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"   %s%ld: %ld (%.02f%%)\n"</span>,(i == DICT_STATS_VECTLEN-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)?<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">">= "</span>:<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">""</span>, i, clvector[i], ((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span>)clvector[i]/ht->size)*<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>);
    }
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> dictPrintStats(dict *d) {
    _dictPrintStatsHt(&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dictIsRehashing(d)) {
        printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"-- Rehashing into ht[1]:\n"</span>);
        _dictPrintStatsHt(&d->ht[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]);
    }
}

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* ----------------------- StringCopy Hash Table Type ------------------------*/</span>

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictStringCopyHTHashFunction(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> dictGenHashFunction(key, strlen(key));
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *_dictStringDup(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> len = strlen(key);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *copy = zmalloc(len+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>);
    DICT_NOTUSED(privdata);

    memcpy(copy, key, len);
    copy[len] = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\0'</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> copy;
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> _dictStringCopyHTKeyCompare(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key1,
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key2)
{
    DICT_NOTUSED(privdata);

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> strcmp(key1, key2) == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> _dictStringDestructor(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *privdata, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> *key)
{
    DICT_NOTUSED(privdata);

    zfree(key);
}

dictType dictTypeHeapStringCopyKey = {
    _dictStringCopyHTHashFunction, <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* hash function */</span>
    _dictStringDup,                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key dup */</span>
    <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>,                          <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* val dup */</span>
    _dictStringCopyHTKeyCompare,   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key compare */</span>
    _dictStringDestructor,         <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key destructor */</span>
    <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>                           <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* val destructor */</span>
};

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* This is like StringCopy but does not auto-duplicate the key.
 * It's used for intepreter's shared strings. */</span>
dictType dictTypeHeapStrings = {
    _dictStringCopyHTHashFunction, <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* hash function */</span>
    <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>,                          <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key dup */</span>
    <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>,                          <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* val dup */</span>
    _dictStringCopyHTKeyCompare,   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key compare */</span>
    _dictStringDestructor,         <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key destructor */</span>
    <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>                           <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* val destructor */</span>
};

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* This is like StringCopy but also automatically handle dynamic
 * allocated C strings as values. */</span>
dictType dictTypeHeapStringCopyKeyValue = {
    _dictStringCopyHTHashFunction, <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* hash function */</span>
    _dictStringDup,                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key dup */</span>
    _dictStringDup,                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* val dup */</span>
    _dictStringCopyHTKeyCompare,   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key compare */</span>
    _dictStringDestructor,         <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* key destructor */</span>
    _dictStringDestructor,         <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* val destructor */</span>
};
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif</span></code>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值