深入redis内部--字典实现

redis的字典定义和实现在dict.h和dict.c文件中。

1.字典结构

typedef *type; *]; rehashidx; iterators; } dict;

其中涉及到数据结构,如下所示:

 1.1 字典类型,包含了一系列字典所需要用到的函数

typedef (*hashFunction)( *key); *(*keyDup)( *privdata, *key); *(*valDup)( *privdata, *obj); (*keyCompare)( *privdata, *key1, *key2); (*keyDestructor)( *privdata, *key); (*valDestructor)( *privdata, *obj); } dictType;

1.2 哈希表结构,每个字典有两个哈希表。当哈希表扩容时实现散列。

typedef ** size; unsigned sizemask; unsigned used; } dictht;

1.3 dictEntry为字典的条目,其定义如下:

typedef *key; union { * dictEntry *

2. 字典的遍历--字典遍历器

typedef **entry,* fingerprint;

注意:当safe=1时,该遍历器是安全的,即字典可以在遍历的同时执行dictAdd,dictFind,和别的函数。否则遍历器是不安全的,遍历时只能执行dictNext()。

   迭代器提供了遍历字典中所有元素的方法,通过dicGetIterator()获得迭代器后,使用dictNext(dictIterator *)获得下一个元素。遍历的过程,先从ht[0]开始,依次从第一个桶table[0]开始遍历桶中的元素,然后遍历table[1],'***,table[size],若正在扩容,则会继续遍历ht[1]中的桶。遍历桶中元素时,依次访问链表中的每一个元素。

3.宏定义函数

dictFreeVal(d,entry) \ ((d)->type->->type->valDestructor((d)->privdata,(entry)-><span style="color: #0000ff;">#define dictSetVal(d,entry,val) do { \
<span style="color: #0000ff;">if
((d)->type-><span style="color: #000000;">valDup) \
entry
->v.val = (d)->type->valDup((d)-><span style="color: #000000;">privdata,val); \
<span style="color: #0000ff;">else<span style="color: #000000;"> \
entry->v.val =<span style="color: #000000;"> (val); \
} <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#define dictSetSignedIntegerVal(entry,val) \
<span style="color: #0000ff;">do { entry->v.s64 = val; } <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#define dictSetUnsignedIntegerVal(entry,val) \
<span style="color: #0000ff;">do { entry->v.u64 = val; } <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#define dictFreeKey(d,entry) \
<span style="color: #0000ff;">if ((d)->type-><span style="color: #000000;">keyDestructor) \
(d)->type->keyDestructor((d)->privdata,(entry)-><span style="color: #000000;">key)

<span style="color: #0000ff;">#define dictSetKey(d,key) do { \
<span style="color: #0000ff;">if ((d)->type-><span style="color: #000000;">keyDup) \
entry->key = (d)->type->keyDup((d)-><span style="color: #000000;">privdata,key); \
<span style="color: #0000ff;">else<span style="color: #000000;"> \
entry->key =<span style="color: #000000;"> (key); \
} <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#define dictCompareKeys(d,key1,key2) \<span style="color: #000000;">
(((d)->type->keyCompare) ?<span style="color: #000000;"> \
(d)->type->keyCompare((d)-><span style="color: #000000;">privdata,key2) : \
(key1) ==<span style="color: #000000;"> (key2))

<span style="color: #0000ff;">#define dictHashKey(d,key) (d)->type->hashFunction(key)
<span style="color: #0000ff;">#define dictGetKey(he) ((he)->key)
<span style="color: #0000ff;">#define dictGetVal(he) ((he)->v.val)
<span style="color: #0000ff;">#define dictGetSignedIntegerVal(he) ((he)->v.s64)
<span style="color: #0000ff;">#define dictGetUnsignedIntegerVal(he) ((he)->v.u64)
<span style="color: #0000ff;">#define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size)
<span style="color: #0000ff;">#define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used)
<span style="color: #0000ff;">#define dictIsRehashing(ht) ((ht)->rehashidx != -1)

4. 字典提供的api,有字典的创建,增加、删除、修改记录,还有迭代器(前面已经介绍)和自动扩容(下面介绍)。

dict *dictCreate(dictType *type, * dictExpand(dict *d,unsigned dictAdd(dict *d, *key, **dictAddRaw(dict *d, * dictReplace(dict *d, **dictReplaceRaw(dict *d, * dictDelete(dict *d, * dictDeleteNoFree(dict *d, * dictRelease(dict ** dictFind(dict *d, * *dictFetchValue(dict *d, * dictResize(dict **dictGetIterator(dict **dictGetSafeIterator(dict **dictNext(dictIterator * dictReleaseIterator(dictIterator **dictGetRandomKey(dict * dictPrintStats(dict * dictGenHashFunction( *key, dictGenCaseHashFunction( unsigned *buf, dictEmpty(dict * dictEnableResize( dictDisableResize( dictRehash(dict *d, dictRehashMilliseconds(dict *d, dictSetHashFunctionSeed(unsigned dictGetHashFunctionSeed();

5.外部定义变量

<span style="color: #0000ff;">extern<span style="color: #000000;"> dictType dictTypeHeapStringCopyKey;
<span style="color: #0000ff;">extern<span style="color: #000000;"> dictType dictTypeHeapStrings;
<span style="color: #0000ff;">extern dictType dictTypeHeapStringCopyKeyValue;

 6. 自动扩容

    Redis使用标识dict_can_resize来记录字典是否可以扩容,可以使用dictEnableResize()方法和dictDisableResize()来改变此标识。使用dictResize()来扩容,但需要首先判断是否允许扩容及是否正在扩容。若可以扩容,则调用dictExpand()扩容,然后调用dictRehashMilliseconds()启动扩容,并指定扩容过程中记录的copy速度。请看程序:

   6.1 dictResize()

dictResize(dict *</span><span style="color: #0000ff;"&gt;if</span> (!dict_can_resize || dictIsRehashing(d)) <span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; DICT_ERR; minimal </span>= d->ht[<span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;].used; </span><span style="color: #0000ff;"&gt;if</span> (minimal <<span style="color: #000000;"&gt; DICT_HT_INITIAL_SIZE) minimal </span>=<span style="color: #000000;"&gt; DICT_HT_INITIAL_SIZE; </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; dictExpand(d,minimal);

}

   6.2 dictExpand()

dictExpand(dict *d,unsigned realsize =</span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; the size is invalid if it is smaller than the number of * elements already inside the hash table </span><span style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (<span style="color: #000000;"&gt;dictIsRehashing</span>(d) || d->ht[<span style="color: #800080;"&gt;0</span>].used ><span style="color: #000000;"&gt; size) </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; DICT_ERR; </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Allocate the new hash table and initialize all pointers to NULL </span><span style="color: #008000;"&gt;*/</span><span style="color: #000000;"&gt; n.size </span>=<span style="color: #000000;"&gt; realsize; n.sizemask </span>= realsize-<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;; n.table </span>= zcalloc(realsize*<span style="color: #0000ff;"&gt;sizeof</span>(dictEntry*<span style="color: #000000;"&gt;)); n.used </span>= <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; 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 style="color: #008000;"&gt;*/</span> <span style="color: #0000ff;"&gt;if</span> (d->ht[<span style="color: #800080;"&gt;0</span>].table ==<span style="color: #000000;"&gt; NULL) { d</span>->ht[<span style="color: #800080;"&gt;0</span>] =<span style="color: #000000;"&gt; n; </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; DICT_OK; } </span><span style="color: #008000;"&gt;/*</span><span style="color: #008000;"&gt; Prepare a second hash table for incremental rehashing </span><span style="color: #008000;"&gt;*/</span><span style="color: #000000;"&gt; d</span>->ht[<span style="color: #800080;"&gt;1</span>] =<span style="color: #000000;"&gt; n; d</span>->rehashidx = <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;; </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; DICT_OK;

}

6.3 

dictRehashMilliseconds(dict *d, start = rehashes = </span><span style="color: #0000ff;"&gt;while</span>(dictRehash(d,<span style="color: #800080;"&gt;100</span><span style="color: #000000;"&gt;)) { rehashes </span>+= <span style="color: #800080;"&gt;100</span><span style="color: #000000;"&gt;; </span><span style="color: #0000ff;"&gt;if</span> (timeInMilliseconds()-start > ms) <span style="color: #0000ff;"&gt;break</span><span style="color: #000000;"&gt;; } </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; rehashes;

}

相关文章

文章浏览阅读1.3k次。在 Redis 中,键(Keys)是非常重要的概...
文章浏览阅读3.3k次,点赞44次,收藏88次。本篇是对单节点的...
文章浏览阅读8.4k次,点赞8次,收藏18次。Spring Boot 整合R...
文章浏览阅读978次,点赞25次,收藏21次。在Centos上安装Red...
文章浏览阅读1.2k次,点赞21次,收藏22次。Docker-Compose部...
文章浏览阅读2.2k次,点赞59次,收藏38次。合理的JedisPool资...