《Redis设计与实现》
第二章 简单动态字符串
2.1 SDS的定义
SDS(Simple Dynamic String)
len 、 free 、 buf
len = 5 , free = 5 , buf = Redis\0_____ , buf.length = len + free + 1
2.2 SDS与C字符串的区别
2.2.1 常数复杂度获取字符串长度
2.2.2 杜绝缓冲区溢出
2.2.3 减少修改字符串时带来的内存重分配次数
1. 空间预分配
2. 惰性空间释放
2.2.4 二进制安全
2.2.5 兼容部分C字符串函数
第三章 链表
3.1 链表和链表节点的实现
ListNode
prev
next
value
List
head
tail
len
dup
free
match
3.2 链表和链表节点的API
第四章 字典
4.1 字典的实现
4.1.1 哈希表
dictht
table
size
sizemask
used
4.1.2 哈希表节点
dictEntry
key
v
next
4.1.3 字典
dict
type // 类型特定函数
privdata // 类型特定函数的可选参数
ht[2]
rehashidx // 记录rehash目前的进度
dictType
hashFunction
keyDup
valDup
keyCompare
keyDestructor
valDestructor
4.2 哈希算法
1.
hash = dict -> type -> hashFunction(key);
index = hash & dict -> ht[x].sizemask;
2.
MurmurHash2
4.3 解决键冲突
链地址法 next
头插法
4.4 rehash
扩展
ht[0].used * 2 <= pow(2, n)
收缩
ht[0].used <= pow(2, n)
哈希表的扩展与收缩
扩展
未执行 BGSAVE 或 BGREWRITEAOF load_factor = ht[0].used / ht[0].size >= 1
执行中 BGSAVE 或 BGREWRITEAOF load_factor = ht[0].used / ht[0].size >= 5
收缩
load_factor < 0.1
4.5 渐进式rehash
rehashidx
每次 CRUD 时,移动 rehashidx 索引的 dictEntry
渐进式 rehash 执行期间的哈希表操作
查找
删除
更新
ht[0] 如果没有找到 去 ht[1] 中 找
添加
ht[0] 不做添加操作, 仅对 ht[1] 做添加操作
4.6 字典API
第五章 跳跃表
skiplist
有序数据结构
通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。
平均 O(logN) 、 最坏 O(N)
5.1 跳跃表的实现
zskiplist
header
tail
level
length
zskiplistNode
level
前进指针
跨度
backward
score
obj
5.1.1 跳跃表节点
zskiplistNode
level[] zskiplistLevel
forward // 前进指针
span // 跨度 节点的排位 将沿途访问过的所有层的跨度累计起来,得到的结果就是目标节点在跳跃表中的排位
backward
score
obj
5.1.2 跳跃表
zskiplist
header
tail
length
level
5.2 跳跃表API
第六章 整数集合
intset
只包含整数值元素,并且元素数量不多时
集合键的底层实现
6.1 整数集合的实现
int16_t 、 int32_t 、 int64_t
intset
encoding uint32_t
length uint32_t
contents[] int8_t
INTSET_ENC_INT16
INTSET_ENC_INT32
INTSET_ENC_INT64
6.2 升级
6.3 升级的好处
6.3.1 提升灵活性
6.3.2 节约内存
6.4 降级
6.5 整数集合API
第七章 压缩列表
列表键 : 当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做列表键的底层实现
哈希键 : 当一个哈希键只包含少量键值对,并且每个键值对的键和值要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做哈希键的底层实现。
字节数组 或 整数值
7.1 压缩列表的构成
zlbytes : 记录整个 压缩列表 占用的内存字节数
zltail : 记录压缩列表 表尾节点 距离 压缩列表 的 起始地址 有多少字节
zllen : 记录了 压缩列表 包含的 节点数量 <= UNIT16_MAC(65535)可信
entryX
zlend : 特殊值0xFF
7.2 压缩列表节点的构成
字节数组
len <= pow(2,6) - 1
len <= pow(2,14) - 1
len <= pow(2,32) - 1
整数值
4位 无符号
1字节 有符号
3字节 有符号
int16_t
int32_t
int64_t
extryX
previous_entry_length
encoding
content
7.2.1 previous_entry_length
1 字节 ; 5 字节
7.2.2 encoding
字节数组
一字节 00
两字节 01
五字节 10
整数编码
一字节 11
11 000000
11 010000
11 100000
11 110000
11 111110
11 11xxxx
7.2.3 content
7.3 连锁更新
O(N) * O(N) = O(N * N)
7.4 压缩列表API
第八章 对象
8.1 对象的类型与编码
redisObject
type
encoding
ptr
8.1.1 类型
REDIS_STRING
REDIS_LIST
REDIS_HASH
REDIS_SET
REDIS_ZSET
TYPE
8.1.2 编码和底层实现
编码常量
REDIS_ENCODING_INT
REDIS_ENCODING_EMBSTR
REDIS_ENCODING_RAW
REDIS_ENCODING_HT
REDIS_ENCODING_LINKEDLIST
REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_INTSET
REDIS_ENCODING_SKIPLIST
类型 编码 对象
REDIS_STRING
REDIS_ENCODING_INT
REDIS_ENCODING_EMBSTR
REDIS_ENCODING_RAW
REDIS_LIST
REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_LINKEDLIST
REDIS_HASH
REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_HT
REDIS_SET
REDIS_ENCODING_INTSET
REDIS_ENCODING_HT
REDIS_ZSET
REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_SKIPLIST
8.2 字符串对象
int raw embstr
int long
raw > 32Byte
embstr <= 32Byte
8.2.1 编码的转换
int -> raw
embstr -> raw
8.2.2 字符串命令的实现
8.3 列表对象
quicklist ziplist linkedlist
8.3.1 编码转换
< 64 Byte
< 512 个
8.3.2 列表命令的实现
8.4 哈希对象
ziplist hashtable
ziplist : key1 value1 key2 value2
8.4.1 编码转换
键值对的键和值的字符串长度 都 < 64 Byte
键值对数量 < 512 个
8.4.2 哈希命令的实现
8.5 集合对象
intset hashtable
8.5.1 编码的转换
int
数量 < 512 个
8.5.2 集合命令的实现
8.6 有序集合对象
ziplist skiplist dict
8.6.1 编码的转换
数量 < 128 个
成员的长度 都 < 64 Byte
8.6.2 有序集合命令的实现
8.7 类型检查与命令多态
任何类型的键执行
del expire rename type object
特定类型的键执行
set get append strlen
hdel hset hget hlen
rpush lpop linsert llen
sadd spop sinter scard
zadd zcard zrank zscore
8.7.1 类型检查的实现
8.7.2 多态命令的实现
8.8 内存回收
引用计数
redisObject
refcount
8.9 对象共享
8.10 对象的空转时长
redisObject
lru:22 // 记录对象最后一次被命令程序访问的时间
OBJECT IDLETIME
A B C D E F
10 11 12 13 14 15
EVAL
quicklist
HashMap::indexOf(key)