字典
作用: 數據庫和hash鍵
字典的結構
typedef struct dict {
// 類型特定函數
//type以及privdata爲了創建多態字典存在
dictType *type;
// 私有數據
void *privdata;
// 哈希表 ht[1]主要用於rehash
dictht ht[2];
// rehash 索引
// 當 rehash 不在進行時,值爲 -1
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
} dict;
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;
字典的底層實現是hash表
typedef struct dictht {
// 哈希表數組
dictEntry **table;
// 哈希表大小
unsigned long size;
// 哈希表大小掩碼,用於計算索引值
// 總是等於 size - 1
unsigned long sizemask;
// 該哈希表已有節點的數量
unsigned long used;
} dictht;
示意圖:
哈希表節點結構:
typedef struct dictEntry {
// 鍵
void *key;
// 值
union {
void *val;
uint64_t u64;
int64_t s64;
} v;
// 指向下個哈希表節點,形成鏈表 採用鏈地址法解決衝突
struct dictEntry *next;
} dictEntry;
字典示例圖:
字典索引值計算以及衝突解決方法
索引值計算: 如果index爲0 , 那麼存放在dictEntry*[0] 下
1).計算key的hash : hash = dict->type->hashFunction(key) 此處使用的hash算法爲(MurmurHash)
2).以key的hash計算索引 : index = hash & dict->ht[x].sizemask
衝突解決以及插入效率:
1).衝突解決:鏈地址法解決衝突
2).插入效率: 對於index相同的key,value按頭插法插入鏈
rehash
1.什麼時候會進行rehash?
負載因子 = ht[0].used / ht[0].size
1).當沒有進行持久化操作(bgsave和bgrewriteaof)時,負載因子大於等於1時會進行
2).當有在進行持久化操作(bgsave和bgrewriteaof)時,負載因子大於等於5會進行(目的:爲了避免在子進程存在期間進行rehash操作(寫時複製))
3).當負載因子小於0.1時,也會進行rehash操作
2.rehash操作:
1).ht[1]空間分配:
擴展: ht[1].size >= ht[0].used*2 的2^n冪 如ht[0].used= 4 ,那麼ht[1]= 8剛好2^3
收縮:ht[1].size >= ht[0].used 的2^n冪
2).漸進式rehash
1)).爲ht[1]分配空間
2)).將rehashindex值設爲0,表示rehash開始
3)).每次對字典的執行操做時,除了執行指定操作外,還會將rehashindex索引上指定的所有鍵值對rehash到ht[1]上,每次完成rehashindex加1
4)).字典完全rehash到ht[1]後,重設rehashindex爲-1,ht[1]變爲ht[0]
在漸進rehash階段會在ht[0]和ht[1]上進行刪除,更新,查找等操作(先ht[0]後ht[1]),所有的添加字典的操作都在ht[1]進行;