Redis数据结构-字典

157 阅读2分钟

定义

哈希表
typedef struct dictht {
    dictEntry **table;			// 哈希表数组
    unsigned long size;			// 哈希表大小
    unsigned long sizemask;		// 哈希表大小掩码,用于计算索引值,总是等于size - 1
    unsigned long used;			// 哈希表已有节点的数量
}dictht;
哈希表节点
typedef struct dictEntry {
    void *key;				// 键
    union {						
        void *val;
        uint64_t u64;
        int64_t s64;
        struct dictEntry *next;
    }v;					// 值
    struct dictEntry *next;		// 指向下个哈希表节点,形成链表
}dictEntry;
字典
typedef struct dict {
    dictType *type;			// 类型特定函数
    void *private;			// 私有数据
    dictht ht[2];			// 哈希表
    int trehashidx;			// rehash索引,当rehash不在进行时,值为-1
}dict;
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 *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
}dictType;
普通状态下的字典图示

rehash

操作步骤
  • 为ht[1]哈希表分配空间,哈希表的空间大小取决于要执行的操作,以及ht[0].used

扩展操作:ht[1]的大小为第一个大于等于

ht[0].used*2的2^n

收缩操作:ht[1]的大小为第一个大于等于

ht[0].used的2^n
  • ht[0]中所有的键值对都迁移到ht[1]:重新计算键的哈希值和索引值
  • 当ht[0]中所有键值对都迁移到了ht[1]之后,释放ht[0],将ht[1]设置为ht[1],ht[1]新创建空白哈希表

渐进式rehash

操作步骤
  • 为ht[1]分配空间,让字典同时拥有ht[0]和ht[1]两个hash表
  • 在字典中维持一个索引计数器变量rehashidx = 0,表示rehash工作开始
  • 在rehash进行期间,每次对字典执行添加、删除、查找、更新操作时,程序既执行指定操作,也会将ht[0]中索引值为rehashidx的键值对rehash到ht[1],当rehash工作完成,rehashidx++
  • 随着字典操作的不断执行,最终在某个时间点上,ht[0]所有键值对都会rehash到ht[1],此时rehashidx置为-1,表示rehash操作已完成

参考

《Redis设计与实现》