【时间】2021.11.23
【题目】【《Redis深度历险》读书笔记(3)】源码(5-7)探索 跳跃列表(skiplist)、紧凑列表(listpack)、基数树(Rax)内部结构
本栏目是《Redis深度历险:核心原理和应用实践》的读书笔记。
目录
一、简介
本章主要主要介绍了Redis 跳跃列表(skiplist)、紧凑列表(listpack)、基数树(Rax)内部结构。
- 跳跃列表(skiplist):zset的底层实现,通过空间换时间实现类似有序数组的二分查找,通过逐级“”跳跃”查询,实现O(lg(n))级别的查询时间复杂度。
- 紧凑列表(listpack):压缩列表zipList的改进,entry去掉了prelen字段,增加了lendth字段表示当前entry的长度,解决了“级联更新”问题,Redis的Stream数据结构用到了listpack
- 基数树(Rax,Radix Tree):一棵有序字典树,按照key进行字典序排序,典型应用是英语词典。
二、一些重点图
1、skipList结构
1)一个4层的skipList
struct zslnode {
string value;
double score;
zslnode*[] forwards; // 多层连接指针
zslnode* backward; // 回溯指针
}
struct zsl {
zslnode* header; // 跳跃列表头指针
int maxLevel; // 跳跃列表当前的最高层
map<string, zslnode*> ht; // hash 结构的所有键值对
}
2)查询过程
2、listpack结构
struct listpack<T> {
int32 total_bytes; // 占用的总字节数
int16 size; // 元素个数
T[] entries; // 紧凑排列的元素列表
int8 end; // 同 zlend 一样,恒为 0xFF
}
struct lpentry {
int<var> encoding;
optional byte[] content;
int<var> length;
}
3、基数树Rax的典型结构(英语词典树)
蓝色节点表示压缩结构。
struct raxNode {
int<1> isKey; // 是否没有 key,没有 key 的是根节点
int<1> isNull; // 是否没有对应的 value,无意义的中间节点
int<1> isCompressed; // 是否压缩存储,这个压缩的概念比较特别
int<29> size; // 子节点的数量或者是压缩字符串的长度 (isCompressed)
byte[] data; // 路由键、子节点指针、value 都在这里
}
1)压缩结构
struct data {
optional struct { // 取决于 header 的 size 字段是否为零
byte[] childKey; // 路由键
raxNode* childNode; // 子节点指针
} child;
optional string value; // 取决于 header 的 isNull 字段
}
2)非压缩结构
struct data {
byte[] childKeys; // 路由键字符列表
raxNode*[] childNodes; // 多个子节点指针
optional string value; // 取决于 header 的 isNull 字段
}