字典是redis中的一種資料結構實現,用來儲存索引值對。
字典中的每個鍵都是獨一無二的,程式可以根據鍵來找到與之關聯的值。
redis的資料庫的底層實現是字典,對於資料庫的增刪改查操作也都是通過對字典進行操作來實現的。
字典還是hash鍵的底層實現之一,如果一個hash鍵包含的索引值對比較多或字串長度比較長的時候,redis就會使用字典作為hash鍵的底層實現。
---------------------------------------------------
redis的字典底層實現為hash表、
hash表由dict.h/dictht結構定義:
typedef struts dictht{ //雜湊表數組 dictEntry **table; //雜湊表數組 unsigned long size; //雜湊表大小掩碼,用於計算索引值 //總是等於size-1 unsigned long sizemask; //該hash表已有節點的數量 unsigned long used;}dictth;
table屬性是一個數組,每個元素指向一個 hash表節點的指標。
hash表節點的由dict.h/dictEntry結構定義
<pre name="code" class="cpp">typedef struts dictEntry{ //鍵 void *key; //值 union{ void *val; uint64_tu64; int64_ts64; } //指向下個hash表節點,形成鏈表 strut dictEntry *next;}dictEntry;
索引值對的值可以是指標,uint64_t整數,或者是int64_t整數
。
next屬性的作用是:如果多個索引值對的hash值相同,它們會成為一個單向鏈表,來解決衝突。
redis中的字典由 dict.h/dict結構來定義
typedef struts dict{<pre name="code" class="cpp"><pre name="code" class="cpp"> //類型特定函數 dictType *type; //私人資料 void *private; //hash表 dictth ht[2] //rehash索引 //當rehash不再進行的時候,值為-1 int trehashidx;}dict;
type屬性和private屬性針對不同類型的索引值對,用來建立多態字典。
dictType結構儲存了一些用於操作索引值對的函數,redis會為用途不同的字典設定不同的函數。
private儲存了傳給函數的 參數。
ht屬性儲存了兩個hash表,通常情況下只使用一個hash表,另一個hash表用作複製。
該圖展示了一個普通狀態下的字典:
--------------------------------------------------------------------------------------
當一個索引值對需要儲存到字典中的時候,
1 .程式會使用hash演算法根據 索引值算出該鍵的hashcode,
2. 根據key算出的hashcode與sizemask屬性算出該索引值對的索引。
3. 根據索引將該索引值對放在hash表數組的指定索引上。
3.1 如果在該索引位置已經存在了索引值對,則會形成單向鏈表,而且會把新加入的索引值對放在該鏈表的表頭。
3.2如果沒有,則直接加入。
rehashc操作
在不斷加入新資料的過程中,為了減小hash表的負載因子,程式會通過rehash操作對hash表的大小進行拓展或伸縮。
該操作就用到了字典中的 h【0】 和 h【1】。
負載因子=ht【0】.used / ht【0】.size
當負載因子小於0.1的時候程式會執行收縮操作。
擴充:ht[1] >= ht[0].used*2 的 2^n
收縮 : ht[1] = ht[0].used 的 2^n
rehash操作的時候,rehash動作是分多次,漸進式的完成的。避免了集中式rehash帶來的龐大計算量。
在進行漸進式rehash操作期間,在字典中添加新值的時候 會儲存在h[1]中,h[0]中的索引值對只會減少,不會增加。