Redis源碼分析---字典dict

本文主要分析redis中的dict結構(對應文件dict.h/dict.c)。

一般的dict結構可以利用紅黑數實現,STL中的map便是。redis中的dict結構是用哈希表來實現的,鍵的衝突通過鏈表來解決。


首先看一些基本結構。

hash表節點結構體,除了kv,還有一個next指針,指向下一個節點(衝突的鍵是通過鏈表來解決的)

/*
  * 哈希表節點
  */
 typedef struct dictEntry {
        
     // 鍵
     void *key;
     // 值
     union {
         void *val;
         uint64_t u64;
         int64_t s64;
     } v;
 
     // 指向下個哈希表節點,形成鏈表
     struct dictEntry *next;
 
 } dictEntry;


字典特定類型函數結構體。每個特定的字典都需要包含一個這個結構體,可以看到該結構體中的成員都是一些函數指針,例如計算key hash值,key複製函數,value複製函數等。這樣做的好處是,抽象。

/*
  * 字典類型特定函數
  */
 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表結構體。table是hash表數組,一個二維數組,table[i]表示分配到第i個桶的所有hash表節點鏈接起來的鏈表;size表示hash表table的大小;sizemask=size-1是hash表掩碼,用於計算索引值(節點索引值計算方式:計算key的hash_value,然後index=hash_value &sizemask);used表示hash表已有節點數量。

redis中定義的dict都包含兩個這樣的hash表,用以實現漸進式rehash。

/*
  * 哈希表
  *
  * 每個字典都使用兩個哈希表,從而實現漸進式 rehash 。
  */
 typedef struct dictht {
 
     // 哈希表數組
     dictEntry **table;
 
     // 哈希表大小
     unsigned long size;
 
     // 哈希表大小掩碼,用於計算索引值
     // 總是等於 size - 1
     unsigned long sizemask;
 
     // 該哈希表已有節點的數量
     unsigned long used;
 
 } dictht;

最後來看看dict結構

type是類型的特定函數集合;ht[2]表示兩個hash表;privdata是私有數據;rehashidx是rehash索引;privdata;iterators;

/*
  * 字典
  */
 typedef struct dict {
 
     // 類型特定函數
     dictType *type;
 
     // 私有數據
     void *privdata;
 
     // 哈希表
     dictht ht[2];
     
     // rehash 索引
     // 當 rehash 不在進行時,值爲 -1
     int rehashidx; /* rehashing not in progress if rehashidx == -1 */
     
     // 目前正在運行的安全迭代器的數量
     int iterators; /* number of iterators currently running */
     
 } dict;



接着看看dict提供的API,主要包括dict的創建、釋放,以及插入、刪除、查找、替換等操作。

dict創建釋放:

 dict *dictCreate(dictType *type, void *privDataPtr);
 void dictRelease(dict *d);


dict的增刪查改:

 int dictAdd(dict *d, void *key, void *val);
 dictEntry *dictAddRaw(dict *d, void *key);
 int dictReplace(dict *d, void *key, void *val);
 dictEntry *dictReplaceRaw(dict *d, void *key);
 int dictDelete(dict *d, const void *key);
 int dictDeleteNoFree(dict *d, const void *key);
 dictEntry * dictFind(dict *d, const void *key);
 void *dictFetchValue(dict *d, const void *key);
 dictEntry *dictGetRandomKey(dict *d);


dict的hash表擴大以及rehash
 int dictExpand(dict *d, unsigned long size); 
 int dictRehash(dict *d, int n);
 int dictRehashMilliseconds(dict *d, int ms);

dict迭代器相關
 dictIterator *dictGetIterator(dict *d);
 dictIterator *dictGetSafeIterator(dict *d);
 dictEntry *dictNext(dictIterator *iter);
 void dictReleaseIterator(dictIterator *iter);






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章