第三篇:核心数据结构之字典(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中的应用。
