字典,又稱爲符號表(symbol table)、關聯數組(associative array)或映射(map),是一種保存鍵值對的數據結構。Redis中數據庫就是用字典做爲底層實現。算法
dict.h/dictht源碼:數據庫
typedef struct dictht { //哈希表數組 dictEntry **table; //哈希表大小 unsigned long size; //哈希表大小掩碼,用於計算索引值,老是等於size - 1 unsigned long sizemask; //已有的節點數 unsigned long used; } dictht;
dict.h/dict源代碼:數組
typedef struct dict { //類型特定函數 dictType *type; //私有數據 void *privdata; //哈希表 dictht ht[2]; //rehash索引,當沒有進行rehash時爲-1,大於-1時表示準備處理dictEntry數組下標的值 int rehashidx; //目前正在運行的安全迭代器的數量 int iterators; } dict;
dict.h/dictEntry源代碼:安全
typedef struct dictEntry { void *key; union { void *val; unit64_t u64; int64_t s64; } v; //指向下個哈希表節點 struct dictEntry *next; } dictEntry;
dict.h/dictType源代碼:服務器
typedef struct dictType { // 計算哈希值的函數 unsigned int (*hashFunction)(const void *key); // 複製鍵的函數 void *(*keyDup)(void *privdata, const void *key); // 複製值的函數 void *(*valDup)(void *privdata, const void *obj); // 對比鍵的函數 int (*keyCompare)(void *privdata, const void *key1, const void *key2); // 銷燬鍵的函數 void (*keyDestructor)(void *privdata, void *key); // 銷燬值的函數 void (*valDestructor)(void *privdata, void *obj); } dictType;
一個字典結構以下:數據結構
字典實現和Java的HashMap相似,都是由一個Entry數組,數組中放Entry鏈表方式實現,當添加一個元素時,先根據元素key算出應該放入數組的下標值,添加Entry到鏈表最後。函數
index算法:優化
#計算key的哈希值spa
hash = dict ->type->hashFunction(key);操作系統
#使用哈希表的sizemask屬性和哈希值,計算出索引值,x多是0或1根據是否在rehash中肯定
index = hash & dict ->ht[x].sizemask;
字典會在兩種狀況下觸發rehash擴充哈希表數組長度:
哈希表收縮條件
#負載因子 = 哈希以保存節點數 / 哈希表數組長度
load_factor = ht[0].used / ht[0].size
之因此當服務器在執行BGSAVE和BGREWRITEAOF時提升了負載因子儘可能在這個時候進行rehash是由於這個兩個操做時Reids須要建立當前服務器進程的子進程,而大多數操做系統都會採用寫時複製(copy-on-write)技術來優化子進程效率,若是在這期間進行rehash寫操做作會須要額外複製到子進程,致使內存使用加大。
字典的rehash過程:
在rehash沒有完成期間,字典全部的delete、find、update都會先在ht[0]操做若是沒有找到再去ht[1]進行,instert操做會直接在ht[1]進行,這樣保證了ht[0]的鍵值對數量只減不增。