zoukankan      html  css  js  c++  java
  • 【redis源码】(七)Dict.c

    无疑,作为key-value的nosql存储工具,redis中最核心的数据结构便是dict本身了。 哈希表作为查找效率 O(1)的数据结构,本身也存在着一些局限性,如hash算法的选择,怎样做到元素在桶内的均匀分布,及当哈希表内元素数量增多时,如果处理随着增加的碰撞,碰撞如果较深,会严重影响哈希表的效率

    redis中的dict便是hash实现的一个很好的范例,dict的实现中最巧妙地细节便是采用了类似双buffer的hash扩容方式,及缓慢的哈希表转移算法。

    1. 哈希表扩容方式【双buffer的hash表结构】

    1 typedef struct dict {
    2     dictType *type;
    3     void *privdata;
    4     dictht ht[2];
    5     int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    6     int iterators; /* number of iterators currently running */
    7 } dict;

    如代码所示,在哈希表resizing的过程中,ht[0]和ht[1]两个哈希表同时工作,直到ht[0]中的元素完全转移到ht[1]中来

    2. 哈希表转移过程是平滑缓慢的

    哈希表的转移并不是一步到位的,这里作者应该是考虑到,在哈希表很大的情况下,如果一次性的对哈希表进行转移操作,会引起性能抖动,所以以两种转移触发条件来对哈希表进行转移

    a. 在每次哈希表进行查询或者更新操作时,转移一个元素

    1 static void _dictRehashStep(dict *d) {
    2     if (d->iterators == 0) dictRehash(d,1);
    3 }

    b. 会有定时操作,每次执行指定长度时间的转移操作,粒度是每次100个元素【具体由谁来触发,还需要进一步看代码】

     1 int dictRehashMilliseconds(dict *d, int ms) {
     2     long long start = timeInMilliseconds();
     3     int rehashes = 0;
     4 
     5     while(dictRehash(d,100)) {
     6         rehashes += 100;
     7         if (timeInMilliseconds()-start > ms) break;
     8     }
     9     return rehashes;
    10 }

    好了,开始贴代码

    dict.h

      1 #ifndef __DICT_H
      2 #define __DICT_H
      3 
      4 #define DICT_OK 0
      5 #define DICT_ERR 1
      6 
      7 /* Unused arguments generate annoying warnings... */
      8 #define DICT_NOTUSED(V) ((void) V)
      9 
     10 typedef struct dictEntry {
     11     void *key;
     12     void *val;
     13     struct dictEntry *next;
     14 } dictEntry;
     15 
     16 typedef struct dictType {
     17     unsigned int (*hashFunction)(const void *key);
     18     void *(*keyDup)(void *privdata, const void *key);
     19     void *(*valDup)(void *privdata, const void *obj);
     20     int (*keyCompare)(void *privdata, const void *key1, const void *key2);
     21     void (*keyDestructor)(void *privdata, void *key);
     22     void (*valDestructor)(void *privdata, void *obj);
     23 } dictType;
     24 
     25 /* This is our hash table structure. Every dictionary has two of this as we
     26  * implement incremental rehashing, for the old to the new table. */
     27 typedef struct dictht {
     28     dictEntry **table;
     29     unsigned long size;
     30     unsigned long sizemask;
     31     unsigned long used;
     32 } dictht;
     33 
     34 typedef struct dict {
     35     dictType *type;
     36     void *privdata;
     37     dictht ht[2];
     38     int rehashidx; /* rehashing not in progress if rehashidx == -1 */
     39     int iterators; /* number of iterators currently running */
     40 } dict;
     41 
     42 /* If safe is set to 1 this is a safe iteartor, that means, you can call
     43  * dictAdd, dictFind, and other functions against the dictionary even while
     44  * iterating. Otherwise it is a non safe iterator, and only dictNext()
     45  * should be called while iterating. */
     46 typedef struct dictIterator {
     47     dict *d;
     48     int table, index, safe;
     49     dictEntry *entry, *nextEntry;
     50 } dictIterator;
     51 
     52 /* This is the initial size of every hash table */
     53 #define DICT_HT_INITIAL_SIZE     4
     54 
     55 /* ------------------------------- Macros ------------------------------------*/
     56 #define dictFreeEntryVal(d, entry) \
     57     if ((d)->type->valDestructor) \
     58         (d)->type->valDestructor((d)->privdata, (entry)->val)
     59 
     60 #define dictSetHashVal(d, entry, _val_) do { \
     61     if ((d)->type->valDup) \
     62         entry->val = (d)->type->valDup((d)->privdata, _val_); \
     63     else \
     64         entry->val = (_val_); \
     65 } while(0)
     66 
     67 #define dictFreeEntryKey(d, entry) \
     68     if ((d)->type->keyDestructor) \
     69         (d)->type->keyDestructor((d)->privdata, (entry)->key)
     70 
     71 #define dictSetHashKey(d, entry, _key_) do { \
     72     if ((d)->type->keyDup) \
     73         entry->key = (d)->type->keyDup((d)->privdata, _key_); \
     74     else \
     75         entry->key = (_key_); \
     76 } while(0)
     77 
     78 #define dictCompareHashKeys(d, key1, key2) \
     79     (((d)->type->keyCompare) ? \
     80         (d)->type->keyCompare((d)->privdata, key1, key2) : \
     81         (key1) == (key2))
     82 
     83 #define dictHashKey(d, key) (d)->type->hashFunction(key)
     84 
     85 #define dictGetEntryKey(he) ((he)->key)
     86 #define dictGetEntryVal(he) ((he)->val)
     87 #define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size)
     88 #define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used)
     89 #define dictIsRehashing(ht) ((ht)->rehashidx != -1)
     90 
     91 /* API */
     92 dict *dictCreate(dictType *type, void *privDataPtr);
     93 int dictExpand(dict *d, unsigned long size);
     94 int dictAdd(dict *d, void *key, void *val);
     95 int dictReplace(dict *d, void *key, void *val);
     96 int dictDelete(dict *d, const void *key);
     97 int dictDeleteNoFree(dict *d, const void *key);
     98 void dictRelease(dict *d);
     99 dictEntry * dictFind(dict *d, const void *key);
    100 void *dictFetchValue(dict *d, const void *key);
    101 int dictResize(dict *d);
    102 dictIterator *dictGetIterator(dict *d);
    103 dictIterator *dictGetSafeIterator(dict *d);
    104 dictEntry *dictNext(dictIterator *iter);
    105 void dictReleaseIterator(dictIterator *iter);
    106 dictEntry *dictGetRandomKey(dict *d);
    107 void dictPrintStats(dict *d);
    108 unsigned int dictGenHashFunction(const unsigned char *buf, int len);
    109 unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);
    110 void dictEmpty(dict *d);
    111 void dictEnableResize(void);
    112 void dictDisableResize(void);
    113 int dictRehash(dict *d, int n);
    114 int dictRehashMilliseconds(dict *d, int ms);
    115 
    116 /* Hash table types */
    117 extern dictType dictTypeHeapStringCopyKey;
    118 extern dictType dictTypeHeapStrings;
    119 extern dictType dictTypeHeapStringCopyKeyValue;
    120 
    121 #endif /* __DICT_H */

    dict.c

      1 #include "fmacros.h"
      2 
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <stdarg.h>
      7 #include <assert.h>
      8 #include <limits.h>
      9 #include <sys/time.h>
     10 #include <ctype.h>
     11 
     12 #include "dict.h"
     13 #include "zmalloc.h"
     14 
     15 /* Using dictEnableResize() / dictDisableResize() we make possible to
     16  * enable/disable resizing of the hash table as needed. This is very important
     17  * for Redis, as we use copy-on-write and don't want to move too much memory
     18  * around when there is a child performing saving operations.
     19  *
     20  * Note that even when dict_can_resize is set to 0, not all resizes are
     21  * prevented: an hash table is still allowed to grow if the ratio between
     22  * the number of elements and the buckets > dict_force_resize_ratio. */
     23 static int dict_can_resize = 1;
     24 static unsigned int dict_force_resize_ratio = 5;
     25 
     26 /* -------------------------- private prototypes ---------------------------- */
     27 
     28 //扩展dict中桶的数量
     29 static int _dictExpandIfNeeded(dict *ht);
     30 //得到扩展后的dict应有的桶的数量,这个数量是2的幂次
     31 static unsigned long _dictNextPower(unsigned long size);
     32 //如果插入key,返回其在哈希表ht中应存方的hashentry的index,如果
     33 //ht正在resizing,则返回在ht[1]中的index
     34 static int _dictKeyIndex(dict *ht, const void *key);
     35 //初始化dict,初始化一个哈希表
     36 static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
     37 
     38 /* -------------------------- hash functions -------------------------------- */
     39 //一系列哈希函数
     40 /* Thomas Wang's 32 bit Mix Function */
     41 unsigned int dictIntHashFunction(unsigned int key)
     42 {
     43     key += ~(key << 15);
     44     key ^=  (key >> 10);
     45     key +=  (key << 3);
     46     key ^=  (key >> 6);
     47     key += ~(key << 11);
     48     key ^=  (key >> 16);
     49     return key;
     50 }
     51 
     52 /* Identity hash function for integer keys */
     53 unsigned int dictIdentityHashFunction(unsigned int key)
     54 {
     55     return key;
     56 }
     57 
     58 /* Generic hash function (a popular one from Bernstein).
     59  * I tested a few and this was the best. */
     60 unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
     61     unsigned int hash = 5381;
     62 
     63     while (len--)
     64         hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
     65     return hash;
     66 }
     67 
     68 /* And a case insensitive version */
     69 unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len) {
     70     unsigned int hash = 5381;
     71 
     72     while (len--)
     73         hash = ((hash << 5) + hash) + (tolower(*buf++)); /* hash * 33 + c */
     74     return hash;
     75 }
     76 
     77 /* ----------------------------- API implementation ------------------------- */
     78 //重置一个dictht结构
     79 /* Reset an hashtable already initialized with ht_init().
     80  * NOTE: This function should only called by ht_destroy(). */
     81 static void _dictReset(dictht *ht)
     82 {
     83     ht->table = NULL;
     84     ht->size = 0;
     85     ht->sizemask = 0;
     86     ht->used = 0;
     87 }
     88 //初始化一个新的哈希表结构,并且调用_dictInit对其进行初始化
     89 /* Create a new hash table */
     90 dict *dictCreate(dictType *type,
     91         void *privDataPtr)
     92 {
     93     dict *d = zmalloc(sizeof(*d));
     94 
     95     _dictInit(d,type,privDataPtr);
     96     return d;
     97 }
     98 
     99 //初始化哈希表
    100 /* Initialize the hash table */
    101 int _dictInit(dict *d, dictType *type,
    102         void *privDataPtr)
    103 {
    104     _dictReset(&d->ht[0]);
    105     _dictReset(&d->ht[1]);
    106     d->type = type;
    107     d->privdata = privDataPtr;
    108     d->rehashidx = -1;
    109     d->iterators = 0;
    110     return DICT_OK;
    111 }
    112 
    113 //resize哈希表d,如果entry数量小于默认初始值,将其置为初始值
    114 //否则将其置为与保存的元素数量相同
    115 /* Resize the table to the minimal size that contains all the elements,
    116  * but with the invariant of a USER/BUCKETS ratio near to <= 1 */
    117 int dictResize(dict *d)
    118 {
    119     int minimal;
    120 
    121     if (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR;
    122     minimal = d->ht[0].used;
    123     if (minimal < DICT_HT_INITIAL_SIZE)
    124         minimal = DICT_HT_INITIAL_SIZE;
    125     return dictExpand(d, minimal);
    126 }
    127 
    128 
    129 //根据size,得到下一个hash的size,应该是2的幂次
    130 //如果size的大小小于目前元素的数量,或者dict正在resize,则终止expanding
    131 //如果确定可以resize,申请一个newsize大小的dicthashtable,并为其初始化
    132 /* Expand or create the hashtable */
    133 int dictExpand(dict *d, unsigned long size)
    134 {
    135     dictht n; /* the new hashtable */
    136     unsigned long realsize = _dictNextPower(size);
    137 
    138     /* the size is invalid if it is smaller than the number of
    139      * elements already inside the hashtable */
    140     if (dictIsRehashing(d) || d->ht[0].used > size)
    141         return DICT_ERR;
    142 
    143     /* Allocate the new hashtable and initialize all pointers to NULL */
    144     n.size = realsize;
    145     n.sizemask = realsize-1;
    146     n.table = zcalloc(realsize*sizeof(dictEntry*));
    147     n.used = 0;
    148 
    149     /* Is this the first initialization? If so it's not really a rehashing
    150      * we just set the first hash table so that it can accept keys. */
    151     if (d->ht[0].table == NULL) {
    152         d->ht[0] = n;
    153         return DICT_OK;
    154     }
    155 
    156     /* Prepare a second hash table for incremental rehashing */
    157     d->ht[1] = n;
    158     d->rehashidx = 0;
    159     return DICT_OK;
    160 }
    161 
    162 
    163 
    164 //rehashing 操作需要n步来执行,一次rehash一个元素,这样一点点的rehash
    165 //可以避免性能波动
    166 /* Performs N steps of incremental rehashing. Returns 1 if there are still
    167  * keys to move from the old to the new hash table, otherwise 0 is returned.
    168  * Note that a rehashing step consists in moving a bucket (that may have more
    169  * thank one key as we use chaining) from the old to the new hash table. */
    170 int dictRehash(dict *d, int n) {
    171     if (!dictIsRehashing(d)) return 0;
    172 
    173     while(n--) {
    174         dictEntry *de, *nextde;
    175 
    176         /* Check if we already rehashed the whole table... */
    177         if (d->ht[0].used == 0) {
    178             zfree(d->ht[0].table);
    179             d->ht[0] = d->ht[1];
    180             _dictReset(&d->ht[1]);
    181             d->rehashidx = -1;
    182             return 0;
    183         }
    184 
    185         /* Note that rehashidx can't overflow as we are sure there are more
    186          * elements because ht[0].used != 0 */
    187         while(d->ht[0].table[d->rehashidx] == NULL) d->rehashidx++;
    188         de = d->ht[0].table[d->rehashidx];
    189         /* Move all the keys in this bucket from the old to the new hash HT */
    190         while(de) {
    191             unsigned int h;
    192 
    193             nextde = de->next;
    194             /* Get the index in the new hash table */
    195             h = dictHashKey(d, de->key) & d->ht[1].sizemask;
    196             de->next = d->ht[1].table[h];
    197             d->ht[1].table[h] = de;
    198             d->ht[0].used--;
    199             d->ht[1].used++;
    200             de = nextde;
    201         }
    202         d->ht[0].table[d->rehashidx] = NULL;
    203         d->rehashidx++;
    204     }
    205     return 1;
    206 }
    207 
    208 //得到以毫秒为单位的当前时间
    209 long long timeInMilliseconds(void) {
    210     struct timeval tv;
    211 
    212     gettimeofday(&tv,NULL);
    213     return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
    214 }
    215 //每次执行一定时间的rehashing操作,这次rehasing的时间不超过ms毫秒
    216 /* Rehash for an amount of time between ms milliseconds and ms+1 milliseconds */
    217 int dictRehashMilliseconds(dict *d, int ms) {
    218     long long start = timeInMilliseconds();
    219     int rehashes = 0;
    220 
    221     while(dictRehash(d,100)) {
    222         rehashes += 100;
    223         if (timeInMilliseconds()-start > ms) break;
    224     }
    225     return rehashes;
    226 }
    227 
    228 
    229 //这个函数执行一次rehashing,即移动一个元素。
    230 //这个函数在任何一次查询或者更新操作时会被调用
    231 //将rehashing的性能消耗分布在每一步
    232 /* This function performs just a step of rehashing, and only if there are
    233  * no safe iterators bound to our hash table. When we have iterators in the
    234  * middle of a rehashing we can't mess with the two hash tables otherwise
    235  * some element can be missed or duplicated.
    236  *
    237  * This function is called by common lookup or update operations in the
    238  * dictionary so that the hash table automatically migrates from H1 to H2
    239  * while it is actively used. */
    240 static void _dictRehashStep(dict *d) {
    241     if (d->iterators == 0) dictRehash(d,1);
    242 }
    243 
    244 //在d中增加一个键值对
    245 /* Add an element to the target hash table */
    246 int dictAdd(dict *d, void *key, void *val)
    247 {
    248     int index;
    249     dictEntry *entry;
    250     dictht *ht;
    251 
    252     if (dictIsRehashing(d)) _dictRehashStep(d);
    253 
    254     /* Get the index of the new element, or -1 if
    255      * the element already exists. */
    256     if ((index = _dictKeyIndex(d, key)) == -1)
    257         return DICT_ERR;
    258 
    259     /* Allocates the memory and stores key */
    260     ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
    261     entry = zmalloc(sizeof(*entry));
    262     entry->next = ht->table[index];
    263     ht->table[index] = entry;
    264     ht->used++;
    265 
    266     /* Set the hash entry fields. */
    267     dictSetHashKey(d, entry, key);
    268     dictSetHashVal(d, entry, val);
    269     return DICT_OK;
    270 }
    271 
    272 //增加一个元素,如果存在,替换
    273 /* Add an element, discarding the old if the key already exists.
    274  * Return 1 if the key was added from scratch, 0 if there was already an
    275  * element with such key and dictReplace() just performed a value update
    276  * operation. */
    277 int dictReplace(dict *d, void *key, void *val)
    278 {
    279     dictEntry *entry, auxentry;
    280 
    281     /* Try to add the element. If the key
    282      * does not exists dictAdd will suceed. */
    283     if (dictAdd(d, key, val) == DICT_OK)
    284         return 1;
    285     /* It already exists, get the entry */
    286     entry = dictFind(d, key);
    287     /* Free the old value and set the new one */
    288     /* Set the new value and free the old one. Note that it is important
    289      * to do that in this order, as the value may just be exactly the same
    290      * as the previous one. In this context, think to reference counting,
    291      * you want to increment (set), and then decrement (free), and not the
    292      * reverse. */
    293     auxentry = *entry;
    294     dictSetHashVal(d, entry, val);
    295     dictFreeEntryVal(d, &auxentry);
    296     return 0;
    297 }
    298 
    299 //删除一个元素
    300 /* Search and remove an element */
    301 static int dictGenericDelete(dict *d, const void *key, int nofree)
    302 {
    303     unsigned int h, idx;
    304     dictEntry *he, *prevHe;
    305     int table;
    306 
    307     if (d->ht[0].size == 0) return DICT_ERR; /* d->ht[0].table is NULL */
    308     if (dictIsRehashing(d)) _dictRehashStep(d);
    309     h = dictHashKey(d, key);
    310 
    311     for (table = 0; table <= 1; table++) {
    312         idx = h & d->ht[table].sizemask;
    313         he = d->ht[table].table[idx];
    314         prevHe = NULL;
    315         while(he) {
    316             if (dictCompareHashKeys(d, key, he->key)) {
    317                 /* Unlink the element from the list */
    318                 if (prevHe)
    319                     prevHe->next = he->next;
    320                 else
    321                     d->ht[table].table[idx] = he->next;
    322                 if (!nofree) {
    323                     dictFreeEntryKey(d, he);
    324                     dictFreeEntryVal(d, he);
    325                 }
    326                 zfree(he);
    327                 d->ht[table].used--;
    328                 return DICT_OK;
    329             }
    330             prevHe = he;
    331             he = he->next;
    332         }
    333         if (!dictIsRehashing(d)) break;
    334     }
    335     return DICT_ERR; /* not found */
    336 }
    337 
    338 //删除ht中的一个元素
    339 int dictDelete(dict *ht, const void *key) {
    340     return dictGenericDelete(ht,key,0);
    341 }
    342 
    343 //删除一个袁术,不释放old键值对的空间
    344 int dictDeleteNoFree(dict *ht, const void *key) {
    345     return dictGenericDelete(ht,key,1);
    346 }
    347 
    348 //释放d中的dictht ht及其中所有的keyvalue对
    349 /* Destroy an entire dictionary */
    350 int _dictClear(dict *d, dictht *ht)
    351 {
    352     unsigned long i;
    353 
    354     /* Free all the elements */
    355     for (i = 0; i < ht->size && ht->used > 0; i++) {
    356         dictEntry *he, *nextHe;
    357 
    358         if ((he = ht->table[i]) == NULL) continue;
    359         while(he) {
    360             nextHe = he->next;
    361             dictFreeEntryKey(d, he);
    362             dictFreeEntryVal(d, he);
    363             zfree(he);
    364             ht->used--;
    365             he = nextHe;
    366         }
    367     }
    368     /* Free the table and the allocated cache structure */
    369     zfree(ht->table);
    370     /* Re-initialize the table */
    371     _dictReset(ht);
    372     return DICT_OK; /* never fails */
    373 }
    374 
    375 //释放整个哈希表
    376 /* Clear & Release the hash table */
    377 void dictRelease(dict *d)
    378 {
    379     _dictClear(d,&d->ht[0]);
    380     _dictClear(d,&d->ht[1]);
    381     zfree(d);
    382 }
    383 
    384 //找到key所在的entry
    385 dictEntry *dictFind(dict *d, const void *key)
    386 {
    387     dictEntry *he;
    388     unsigned int h, idx, table;
    389 
    390     if (d->ht[0].size == 0) return NULL; /* We don't have a table at all */
    391     if (dictIsRehashing(d)) _dictRehashStep(d);
    392     h = dictHashKey(d, key);
    393     for (table = 0; table <= 1; table++) {
    394         idx = h & d->ht[table].sizemask;
    395         he = d->ht[table].table[idx];
    396         while(he) {
    397             if (dictCompareHashKeys(d, key, he->key))
    398                 return he;
    399             he = he->next;
    400         }
    401         if (!dictIsRehashing(d)) return NULL;
    402     }
    403     return NULL;
    404 }
    405 
    406 //拿到key的value,如果不存在,返回NULL
    407 void *dictFetchValue(dict *d, const void *key) {
    408     dictEntry *he;
    409 
    410     he = dictFind(d,key);
    411     return he ? dictGetEntryVal(he) : NULL;
    412 }
    413 
    414 //拿到dict的iterator
    415 dictIterator *dictGetIterator(dict *d)
    416 {
    417     dictIterator *iter = zmalloc(sizeof(*iter));
    418 
    419     iter->d = d;
    420     iter->table = 0;
    421     iter->index = -1;
    422     iter->safe = 0;
    423     iter->entry = NULL;
    424     iter->nextEntry = NULL;
    425     return iter;
    426 }
    427 
    428 //得到safe的iterator
    429 //如果iterator是safe的,则可以进行修改操作,否则,只能执行dictNext
    430 dictIterator *dictGetSafeIterator(dict *d) {
    431     dictIterator *i = dictGetIterator(d);
    432 
    433     i->safe = 1;
    434     return i;
    435 }
    436 
    437 //得到iter的下一个元素
    438 dictEntry *dictNext(dictIterator *iter)
    439 {
    440     while (1) {
    441         if (iter->entry == NULL) {
    442             dictht *ht = &iter->d->ht[iter->table];
    443             if (iter->safe && iter->index == -1 && iter->table == 0)
    444                 iter->d->iterators++;
    445             iter->index++;
    446             if (iter->index >= (signed) ht->size) {
    447                 if (dictIsRehashing(iter->d) && iter->table == 0) {
    448                     iter->table++;
    449                     iter->index = 0;
    450                     ht = &iter->d->ht[1];
    451                 } else {
    452                     break;
    453                 }
    454             }
    455             iter->entry = ht->table[iter->index];
    456         } else {
    457             iter->entry = iter->nextEntry;
    458         }
    459         if (iter->entry) {
    460             /* We need to save the 'next' here, the iterator user
    461              * may delete the entry we are returning. */
    462             iter->nextEntry = iter->entry->next;
    463             return iter->entry;
    464         }
    465     }
    466     return NULL;
    467 }
    468 
    469 //释放哈希表的iterator
    470 void dictReleaseIterator(dictIterator *iter)
    471 {
    472     if (iter->safe && !(iter->index == -1 && iter->table == 0))
    473         iter->d->iterators--;
    474     zfree(iter);
    475 }
    476 
    477 /* Return a random entry from the hash table. Useful to
    478  * implement randomized algorithms */
    479  //得到一个随机key
    480 dictEntry *dictGetRandomKey(dict *d)
    481 {
    482     dictEntry *he, *orighe;
    483     unsigned int h;
    484     int listlen, listele;
    485 
    486     if (dictSize(d) == 0) return NULL;
    487     if (dictIsRehashing(d)) _dictRehashStep(d);
    488     if (dictIsRehashing(d)) {
    489         do {
    490             h = random() % (d->ht[0].size+d->ht[1].size);
    491             he = (h >= d->ht[0].size) ? d->ht[1].table[h - d->ht[0].size] :
    492                                       d->ht[0].table[h];
    493         } while(he == NULL);
    494     } else {
    495         do {
    496             h = random() & d->ht[0].sizemask;
    497             he = d->ht[0].table[h];
    498         } while(he == NULL);
    499     }
    500 
    501     /* Now we found a non empty bucket, but it is a linked
    502      * list and we need to get a random element from the list.
    503      * The only sane way to do so is counting the elements and
    504      * select a random index. */
    505     listlen = 0;
    506     orighe = he;
    507     while(he) {
    508         he = he->next;
    509         listlen++;
    510     }
    511     listele = random() % listlen;
    512     he = orighe;
    513     while(listele--) he = he->next;
    514     return he;
    515 }
    516 
    517 /* ------------------------- private functions ------------------------------ */
    518 
    519 /* Expand the hash table if needed */
    520 //如果哈希表需要resize,则执行dictexpand
    521 static int _dictExpandIfNeeded(dict *d)
    522 {
    523     /* Incremental rehashing already in progress. Return. */
    524     if (dictIsRehashing(d)) return DICT_OK;
    525 
    526     /* If the hash table is empty expand it to the intial size. */
    527     if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);
    528 
    529     /* If we reached the 1:1 ratio, and we are allowed to resize the hash
    530      * table (global setting) or we should avoid it but the ratio between
    531      * elements/buckets is over the "safe" threshold, we resize doubling
    532      * the number of buckets. */
    533     if (d->ht[0].used >= d->ht[0].size &&
    534         (dict_can_resize ||
    535          d->ht[0].used/d->ht[0].size > dict_force_resize_ratio))
    536     {
    537         return dictExpand(d, ((d->ht[0].size > d->ht[0].used) ?
    538                                     d->ht[0].size : d->ht[0].used)*2);
    539     }
    540     return DICT_OK;
    541 }
    542 
    543 //根据size,得到比size大的最小的一个2的幂次数作为新哈希表的size值
    544 /* Our hash table capability is a power of two */
    545 static unsigned long _dictNextPower(unsigned long size)
    546 {
    547     unsigned long i = DICT_HT_INITIAL_SIZE;
    548 
    549     if (size >= LONG_MAX) return LONG_MAX;
    550     while(1) {
    551         if (i >= size)
    552             return i;
    553         i *= 2;
    554     }
    555 }
    556 
    557 
    558 //返回key在d中所在的index值,如果已经存在,则返回-1,否则返回所在entry的index值
    559 /* Returns the index of a free slot that can be populated with
    560  * an hash entry for the given 'key'.
    561  * If the key already exists, -1 is returned.
    562  *
    563  * Note that if we are in the process of rehashing the hash table, the
    564  * index is always returned in the context of the second (new) hash table. */
    565 static int _dictKeyIndex(dict *d, const void *key)
    566 {
    567     unsigned int h, idx, table;
    568     dictEntry *he;
    569 
    570     /* Expand the hashtable if needed */
    571     if (_dictExpandIfNeeded(d) == DICT_ERR)
    572         return -1;
    573     /* Compute the key hash value */
    574     h = dictHashKey(d, key);
    575     for (table = 0; table <= 1; table++) {
    576         idx = h & d->ht[table].sizemask;
    577         /* Search if this slot does not already contain the given key */
    578         he = d->ht[table].table[idx];
    579         while(he) {
    580             if (dictCompareHashKeys(d, key, he->key))
    581                 return -1;
    582             he = he->next;
    583         }
    584         if (!dictIsRehashing(d)) break;
    585     }
    586     return idx;
    587 }
    588 
    589 //清空哈希表d
    590 void dictEmpty(dict *d) {
    591     _dictClear(d,&d->ht[0]);
    592     _dictClear(d,&d->ht[1]);
    593     d->rehashidx = -1;
    594     d->iterators = 0;
    595 }
    596 
    597 #define DICT_STATS_VECTLEN 50
    598 static void _dictPrintStatsHt(dictht *ht) {
    599     unsigned long i, slots = 0, chainlen, maxchainlen = 0;
    600     unsigned long totchainlen = 0;
    601     unsigned long clvector[DICT_STATS_VECTLEN];
    602 
    603     if (ht->used == 0) {
    604         printf("No stats available for empty dictionaries\n");
    605         return;
    606     }
    607 
    608     for (i = 0; i < DICT_STATS_VECTLEN; i++) clvector[i] = 0;
    609     for (i = 0; i < ht->size; i++) {
    610         dictEntry *he;
    611 
    612         if (ht->table[i] == NULL) {
    613             clvector[0]++;
    614             continue;
    615         }
    616         slots++;
    617         /* For each hash entry on this slot... */
    618         chainlen = 0;
    619         he = ht->table[i];
    620         while(he) {
    621             chainlen++;
    622             he = he->next;
    623         }
    624         clvector[(chainlen < DICT_STATS_VECTLEN) ? chainlen : (DICT_STATS_VECTLEN-1)]++;
    625         if (chainlen > maxchainlen) maxchainlen = chainlen;
    626         totchainlen += chainlen;
    627     }
    628     printf("Hash table stats:\n");
    629     printf(" table size: %ld\n", ht->size);
    630     printf(" number of elements: %ld\n", ht->used);
    631     printf(" different slots: %ld\n", slots);
    632     printf(" max chain length: %ld\n", maxchainlen);
    633     printf(" avg chain length (counted): %.02f\n", (float)totchainlen/slots);
    634     printf(" avg chain length (computed): %.02f\n", (float)ht->used/slots);
    635     printf(" Chain length distribution:\n");
    636     for (i = 0; i < DICT_STATS_VECTLEN-1; i++) {
    637         if (clvector[i] == 0) continue;
    638         printf("   %s%ld: %ld (%.02f%%)\n",(i == DICT_STATS_VECTLEN-1)?">= ":"", i, clvector[i], ((float)clvector[i]/ht->size)*100);
    639     }
    640 }
    641 
    642 void dictPrintStats(dict *d) {
    643     _dictPrintStatsHt(&d->ht[0]);
    644     if (dictIsRehashing(d)) {
    645         printf("-- Rehashing into ht[1]:\n");
    646         _dictPrintStatsHt(&d->ht[1]);
    647     }
    648 }
    649 
    650 //打开rehashing的开关,允许条件满足时执行hashExpanding
    651 void dictEnableResize(void) {
    652     dict_can_resize = 1;
    653 }
    654 
    655 void dictDisableResize(void) {
    656     dict_can_resize = 0;
    657 }
    658 
    659 #if 0
    660 
    661 /* The following are just example hash table types implementations.
    662  * Not useful for Redis so they are commented out.
    663  */
    664 
    665 /* ----------------------- StringCopy Hash Table Type ------------------------*/
    666 
    667 static unsigned int _dictStringCopyHTHashFunction(const void *key)
    668 {
    669     return dictGenHashFunction(key, strlen(key));
    670 }
    671 
    672 static void *_dictStringDup(void *privdata, const void *key)
    673 {
    674     int len = strlen(key);
    675     char *copy = zmalloc(len+1);
    676     DICT_NOTUSED(privdata);
    677 
    678     memcpy(copy, key, len);
    679     copy[len] = '\0';
    680     return copy;
    681 }
    682 
    683 static int _dictStringCopyHTKeyCompare(void *privdata, const void *key1,
    684         const void *key2)
    685 {
    686     DICT_NOTUSED(privdata);
    687 
    688     return strcmp(key1, key2) == 0;
    689 }
    690 
    691 static void _dictStringDestructor(void *privdata, void *key)
    692 {
    693     DICT_NOTUSED(privdata);
    694 
    695     zfree(key);
    696 }
    697 
    698 dictType dictTypeHeapStringCopyKey = {
    699     _dictStringCopyHTHashFunction, /* hash function */
    700     _dictStringDup,                /* key dup */
    701     NULL,                          /* val dup */
    702     _dictStringCopyHTKeyCompare,   /* key compare */
    703     _dictStringDestructor,         /* key destructor */
    704     NULL                           /* val destructor */
    705 };
    706 
    707 /* This is like StringCopy but does not auto-duplicate the key.
    708  * It's used for intepreter's shared strings. */
    709 dictType dictTypeHeapStrings = {
    710     _dictStringCopyHTHashFunction, /* hash function */
    711     NULL,                          /* key dup */
    712     NULL,                          /* val dup */
    713     _dictStringCopyHTKeyCompare,   /* key compare */
    714     _dictStringDestructor,         /* key destructor */
    715     NULL                           /* val destructor */
    716 };
    717 
    718 /* This is like StringCopy but also automatically handle dynamic
    719  * allocated C strings as values. */
    720 dictType dictTypeHeapStringCopyKeyValue = {
    721     _dictStringCopyHTHashFunction, /* hash function */
    722     _dictStringDup,                /* key dup */
    723     _dictStringDup,                /* val dup */
    724     _dictStringCopyHTKeyCompare,   /* key compare */
    725     _dictStringDestructor,         /* key destructor */
    726     _dictStringDestructor,         /* val destructor */
    727 };
    728 #endif
    喜欢一起简单,实用的东西,拒绝复杂花哨,我不是GEEK.
  • 相关阅读:
    Java实现各种内部排序算法
    Java实现堆排序(大根堆)
    Java对象的序列化和反序列化
    Java实现链式存储的二叉查找树(递归方法)
    337. House Robber III(包含I和II)
    318. Maximum Product of Word Lengths
    114. Flatten Binary Tree to Linked List
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    96. Unique Binary Search Trees(I 和 II)
  • 原文地址:https://www.cnblogs.com/igloo1986/p/2669230.html
Copyright © 2011-2022 走看看