第三篇:核心数据结构之字典(Dict)
1. 引言
字典(Dict)是Redis的核心数据结构之一,用于实现键值存储(Redis数据库的核心)和内部元数据管理(如客户端状态)。Redis的字典基于哈希表实现,支持高效的增删改查操作。本篇将深入剖析其源码实现,包括哈希表结构、冲突解决和渐进式rehash机制。
2. 字典的结构体定义
字典的定义在src/dict.h
和src/dict.c
中。以下是核心结构:
代码片段(dict.h
):
|
|
硬核解析:
dictEntry
:键值对节点,next
指针形成链表解决冲突。dictht
:哈希表,size
是2的幂次,sizemask = size - 1
。dict
:包含两个哈希表ht[0]
和ht[1]
,支持渐进式rehash。
Mermaid结构图:
classDiagram
class dict {
-type: dictType*
-privdata: void*
-ht[2]: dictht
-rehashidx: long
}
class dictht {
-table: dictEntry**
-size: ulong
-sizemask: ulong
-used: ulong
}
class dictEntry {
-key: void*
-v: union
-next: dictEntry*
}
dict o--> "2" dictht
dictht o--> "n" dictEntry
dictEntry o--> "1" dictEntry : "next"
3. 核心操作解析
3.1 添加键值对(dictAdd()
)
代码片段(dict.c
):
|
|
硬核解析:
- 哈希计算:
dictHashKey()
调用自定义哈希函数,默认是MurmurHash2。 - 索引计算:
key_hash & sizemask
,快速定位槽。 - 冲突处理:链地址法,插入到链表头部。
3.2 查找键(dictFind()
)
代码片段(dict.c
):
|
|
硬核解析:
- 检查
ht[0]
和ht[1]
(rehash期间需两表查找)。 - 链表遍历对比键,
dictCompareKeys()
支持自定义比较。
3.3 渐进式rehash
触发条件:
- 负载因子(
used/size
)超过阈值(默认1,或更高若有AOF写入)。 - 通过
_dictExpand()
分配新表ht[1]
。
代码片段(_dictRehashStep()
):
|
|
硬核解析:
- 渐进式迁移:每次操作只迁移一个桶(
rehashidx
)。 - 时间分摊:避免一次性rehash阻塞主线程。
- 完成标志:
rehashidx >= ht[0].size
时,释放ht[0]
,ht[1]
变为ht[0]
。
Mermaid rehash流程:
graph TD
A["dictAdd/dictFind"] --> B["dictIsRehashing()"]
B -->|Yes| C["_dictRehashStep()"]
C --> D{"rehashidx < size?"}
D -->|Yes| E["迁移当前桶"]
E --> F["rehashidx++"]
F --> D
D -->|No| G["rehash完成"]
4. 哈希冲突与扩容缩容
- 冲突解决:链地址法,
next
指针形成链表。 - 扩容:
used/size > 1
时,size
翻倍(_dictExpand()
)。 - 缩容:
used/size < 0.1
时,size
减半(_dictContract()
)。
5. 总结与调试建议
- 收获:理解Redis字典的哈希表实现与rehash优化。
- 调试技巧:用
gdb
打印ht[0].table
(如p d->ht[0].table[0]
),观察链表结构。 - 下一步:探索跳表(Skip List)在ZSET中的应用。