redis的dict是自动rehash的hash表,为了平衡性能,rehash不是一次做完的,而是分散到每次交互操作来做;
typedef struct dictEntry {void *key;
void *val;
struct dictEntry *next;
} dictEntry;
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;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
dict包含两个hash表,当rehash时,逐步将ht[0]中元素挪至ht[1],全部挪完后,ht[0]=ht[1],结束rehash;
int dictRehash(dict *d, int n)
将ht[0]的n个非空桶的元素rehash到ht[1],更新rehashidx;
如果所有元素都已经rehash,则ht[0]=ht[1],reset(ht[1]),设置rehashidx为-1;
触发_dictRehashStep(在没有iterator的时候,挪元素)的操作有:dictAdd、dictReplace、dictGenericDelete、dictDelete、dictDeleteNoFree、dictFind;
dict *dictCreate(dictType *type, void *privDataPtr); // 创建dict
int dictExpand(dict *d, unsigned long size); // 当ht[0].table为NULL时,创建hashtable;其他时候,创建ht[1],设置rehashidx为0,开始rehash;
int dictAdd(dict *d, void *key, void *val);
判断是否需要rehash,触发条件为:元素个数大于或等于桶个数且设置了可以rehash,或者元素个数是桶个数的5倍以上;
从ht[0]中查询是否有key存在,如果在rehash过程中,另需判断key是否在ht[1]中存在,如果存在,则添加失败;
如果在rehash过程中,将元素添加到ht[1],否则,添加到ht[0];
int dictReplace(dict *d, void *key, void *val);
先调用dictAdd,如果成功,直接返回;
失败则表明,key已经存在,调用dictFind获得dictEntry,将dictEntry->val替换掉;
static int dictGenericDelete(dict *d, const void *key, int nofree);
先尝试从ht[0]中删除key元素;
若ht[0]中没有key元素且在rehash过程中,则尝试从ht[1]中删除元素key;
void dictRelease(dict *d); // 释放dict
dictEntry * dictFind(dict *d, const void *key);
先从ht[0]找key,找到直接返回;
若ht[0]中没找到key元素且在rehash过程中,则尝试从ht[1]中找key;
dictIterator *dictGetSafeIterator(dict *d); // 创建迭代器
dictEntry *dictNext(dictIterator *iter); // 迭代元素
与普通hash表迭代器区别在于,如果dict处于rehash过程中,迭代完ht[0]后,会继续迭代ht[1];
在有迭代器迭代dict时,是不允许从ht[0]挪元素到ht[1]的;
dictEntry *dictGetRandomKey(dict *d);
从dict中随机获取一个元素;