redis dict.h源码分析

来源:互联网 发布:java 云平台 编辑:程序博客网 时间:2024/05/21 03:28
/* Hash Tables Implementation. * * This file implements in memory hash tables with insert/del/replace/find/ * get-random-element operations. Hash tables will auto resize if needed * tables of power of two in size are used, collisions are handled by * chaining. */#ifndef __DICT_H#define __DICT_H#define DICT_OK 0#define DICT_ERR 1/* Unused arguments generate annoying warnings... */#define DICT_NOTUSED(V) ((void) V)/* * dict 是主要是由 struct dictht 的 哈唏表构成的, 之所以定义成长度为2的( dictht ht[2] ) 哈唏表数组, * 是因为 redis 采用渐进的 rehash,即当需要 rehash 时,每次像 hset,hget 等操作前,先执行N 步 rehash. * 这样就把原来一次性的 rehash过程拆散到进行, 防止一次性 rehash 期间 redis 服务能力大幅下降. 这种渐进的 rehash * 需要一个额外的 struct dictht 结构来保存.struct dictht 主要是由一个 struct dictEntry 指针数组组成的, hash 表的冲突是通过链表法来解决的.在Redis中,hash表被称为字典(dictionary),采用了典型的链式解决冲突方法,即:当有多个key/value的key的映射值(每对key/value保存之前,会先通过类似HASH(key) MOD N的方法计算一个值,以便确定其对应的hash table的位置)相同时,会将这些value以单链表的形式保存;同时为了控制哈希表所占内存大小,redis采用了双哈希表(ht[2])结构,并逐步扩大哈希表容量(桶的大小)的策略,即:刚开始,哈希表ht[0]的桶大小为4,哈希表ht[1]的桶大小为0,待冲突严重(redis有一定的判断条件)后,ht[1]中桶的大小增为ht[0]的两倍,并逐步(注意这个词:”逐步”)将哈希表ht[0]中元素迁移(称为“再次Hash”)到ht[1],待ht[0]中所有元素全部迁移到ht[1]后,再将ht[1]交给ht[0](这里仅仅是C语言地址交换),之后重复上面的过程。 */typedef struct dictEntry {    void *key;    void *val;    struct dictEntry *next;//chaining to avoid hash conflict} dictEntry;//每种hash table的类型,里面既有成员函数,又有成员变量,完全是模拟的C++类,注意,//每个函数带有的privdata均为预留参数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;/* This is our hash table structure. Every dictionary has two of this as we * implement incremental rehashing, for the old to the new table. */typedef struct dictht {    dictEntry **table;//hash 表中的数据,以key/value形式,通过单链表保存    //a pointer to dictEntry*, not an array of dictEntry*.    //dictEntry can perform chaining work    unsigned long size;//桶个数    unsigned long sizemask; //size - 1,    //hashresult & sizemask = hashresult % sizemask, result is 0 ~ size - 1    unsigned long used; //实际保存的元素数entry num} dictht;/* * lazy rehashing:在每次对dict进行操作的时候执行一个slot的rehash * active rehashing:每100ms里面使用1ms时间进行rehash。 */typedef struct dict {    dictType *type;    void *privdata;    dictht ht[2];    int rehashidx; /* rehashidx是下一个需要rehash的项在ht[0]中的索引    rehashing not in progress if rehashidx == -1 */    int iterators; /* number of iterators currently running记录当前dict中的迭代器数,主要是为了避免在有迭代器时rehash,在有迭代器时rehash可能会造成值的丢失或重复,*/} dict;/* If safe is set to 1 this is a safe iteartor, that means, you can call * dictAdd, dictFind, and other functions against the dictionary even while * iterating. Otherwise it is a non safe iterator, and only dictNext() * should be called while iterating. */typedef struct dictIterator {    dict *d;    int table;//所在的table    int index;//在两个table中的index,可能大于d.table[0]的size    int safe;    dictEntry *entry, *nextEntry;} dictIterator;/* This is the initial size of every hash table */#define DICT_HT_INITIAL_SIZE     4/* ------------------------------- Macros ------------------------------------*/#define dictFreeEntryVal(d, entry) \    if ((d)->type->valDestructor) \        (d)->type->valDestructor((d)->privdata, (entry)->val)#define dictSetHashVal(d, entry, _val_) do { \    if ((d)->type->valDup) \        entry->val = (d)->type->valDup((d)->privdata, _val_); \    else \        entry->val = (_val_); \} while(0)#define dictFreeEntryKey(d, entry) \    if ((d)->type->keyDestructor) \        (d)->type->keyDestructor((d)->privdata, (entry)->key)#define dictSetHashKey(d, entry, _key_) do { \    if ((d)->type->keyDup) \        entry->key = (d)->type->keyDup((d)->privdata, _key_); \    else \        entry->key = (_key_); \} while(0)#define dictCompareHashKeys(d, key1, key2) \    (((d)->type->keyCompare) ? \        (d)->type->keyCompare((d)->privdata, key1, key2) : \        (key1) == (key2))#define dictHashKey(d, key) (d)->type->hashFunction(key)#define dictGetEntryKey(he) ((he)->key)#define dictGetEntryVal(he) ((he)->val)#define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size)#define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used)#define dictIsRehashing(ht) ((ht)->rehashidx != -1)/* API */dict *dictCreate(dictType *type, void *privDataPtr);int dictExpand(dict *d, unsigned long size);int dictAdd(dict *d, void *key, void *val);int dictReplace(dict *d, void *key, void *val);int dictDelete(dict *d, const void *key);int dictDeleteNoFree(dict *d, const void *key);void dictRelease(dict *d);dictEntry * dictFind(dict *d, const void *key);void *dictFetchValue(dict *d, const void *key);int dictResize(dict *d);dictIterator *dictGetIterator(dict *d);dictIterator *dictGetSafeIterator(dict *d);dictEntry *dictNext(dictIterator *iter);void dictReleaseIterator(dictIterator *iter);dictEntry *dictGetRandomKey(dict *d);void dictPrintStats(dict *d);unsigned int dictGenHashFunction(const unsigned char *buf, int len);unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);void dictEmpty(dict *d);void dictEnableResize(void);void dictDisableResize(void);int dictRehash(dict *d, int n);int dictRehashMilliseconds(dict *d, int ms);/* Hash table types */extern dictType dictTypeHeapStringCopyKey;extern dictType dictTypeHeapStrings;extern dictType dictTypeHeapStringCopyKeyValue;#endif /* __DICT_H */