字典就是我们熟悉的map,键值对(key-value pair)的抽象数据结构。Redis数据库就是使用字典来作为底层实现的。
先介绍下数据结构:
1.哈希表
typeof struct dictht {
//哈希表数组
dictEntry **table;
//哈希表大小
unsigned long size;
//哈希表大小掩码,用于计算索引
//总是等于size-1
unsigned long sizemask;
//已有节点数量
unsigned long used;
} dictht;
这种数据结构很好理解,和Java里面HashMap实现差不多。哈希表里面每个节点都是一个entry对象。
2.哈希表节点
typeof struct dictEntry {
//键
void *key;
//值
union {
void *val;
unit64_t u64;
int64_t s64;
} v;
//指向下个哈希表节点,形成链表
struct dictEntry *next;
} dictEntry;
key属性存着键值对中的键,v属性存值。键可以是一个指针,也可以是一个unit64_t整数,或是一个int^4_t整数。C语言没了解过,这种奇怪的整数也不知道什么意思,姑且理解为Java里面的hashCode吧。
next属性指向链表中的下一个节点,这点和Java一样,当多个对象哈希值相同时,就造成hash冲突,多个对象的索引值都落在同一索引下标上,该节点的数据结构为链表,需要遍历该链表才能找到对应元素。
3.字典数据结构
typeof struct dict {
//类型特定函数
dictType *type;
//私有数据
void *privdata;
//哈希表
dictht ht[2];
//rehash索引
//当rehash不再进行时,值为-1
int rehashidx;
} dict;
type属性和privdata属性针对不同类型的键值对,为创建多态字典设置的。
type属性是一个指向dictType结构的指针,每个dictType保存了一簇用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同的类型特定函数。
privdata属性保存了需要传给那些类型特定函数的可选参数。
typeof 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;
ht属性是一个包含2个索引的数组,每个位置都是一个dictht哈希表,一般使用ht[0],ht[1]用于存放对ht[0]哈希表进行rehash的结果。
rehashidx记录目前rehash进度,当前没有执行rehash,值为-1。