list结构为链表提供了表头指针head、表尾指针tail,以及链表长度计数器len,而dup、free和match成员则是用于实现多态链表所需的类型特定函数:
dup函数用于复制链表结点所保存的值;
free函数用于释放链表结点所保存的值;
match函数用于对比链表结点所保存的值和另一个输入值是否相等;
Redis的链表实现的特性总结如下:
双端:链表节点带有prev 和next 指针,获取某个节点的前置节点和后置节点的时间复杂度都是O(1)。
无环:表头节点的 prev 指针和表尾节点的next 都指向NULL,对链表的访问时以NULL来做判断是否截止。
带表头指针和表尾指针:因为链表带有head指针和tail 指针,程序获取链表头结点和尾节点的时间复杂度为O(1)。
带链表长度计数器:链表中存有记录链表长度的属性 len。
多态:链表节点使用 void* 指针来保存节点值,并且可以通过list 结构的dup 、 free、 match三个属性为节点值设置类型特定函数,所以链表可以用来保存各种不同类型的值。
字典字典由哈希表组成,而哈希表又由哈希结点组成。
哈希表结点
和链表一样,Redis也自己实现了哈希表结点结构和哈希表结构,如下:
哈希表结点:
typeof struct dictEntry{ //键 void *key; //值 union{ void *val; uint64_tu64; int64_ts64; } struct dictEntry *next; }
每个dictEntry结构都保存着一个键值对,分别对应属性key和value,同时,next属性是指向另外一个哈希表结点的指针,作用就是将多个哈希值相同的哈希结点连接起来,以此来解决键冲突的问题。
哈希表Redis在dictEntry的基础之上封装实现了哈希表,如下:
typedef struct dictht { //哈希表数组 dictEntry **table; //哈希表大小 unsigned long size; //哈希表大小掩码,用于计算索引值 unsigned long sizemask; //该哈希表已有节点的数量 unsigned long used; }
其中需要提到的是sizemark,这个属性和哈希值一起决定一个键应该被放到table数组中的哪个索引上面。
字典Redis在哈希表的基础上封装了dictht实现字典,如下:
typedef struct dict { // 类型特定函数 dictType *type; // 私有数据 void *privedata; // 哈希表 dictht ht[2]; // rehash 索引 int rehashidx; }
type属性和privdata属性是针对不同类型的键值对,为创建多态字典而设置的。ht属性是一个包含两个项的数组,数组中的每个项都是一个dictht哈希表,一般情况下,字典只使用ht[0]哈希表,ht[1]哈希表只会在对ht[0]哈希表进行rehash时使用,而rehashidx则决定了rehash的进度,如果没有进行rehash,其值则为-1。
哈希算法