有趣的Redis:压缩列表是如何是如何实现的?

有趣的Redis:压缩列表是如何是如何实现的?_第1张图片

压缩列表的数据结构

zset和hash容器对象在元素个数较少的时候,采用压缩列表(ziplist)来存储。压缩列表是一块连续的内存空间。结构如下
在这里插入图片描述

属性 类型 长度 用途
zlbytes uint32_t 4字节 整个压缩列表占用字节数
zltail uint32_t 4字节 最后一个元素距离压缩列表起始位置的偏移量,用于快速定位最后一个元素
zllen uint16_t 2字节 压缩列表的节点数量,值小于UINT16_MAX(65535)时,这个属性值就是压缩列表包含节点的数量,值等于UINT16_MAX,节点的数量需要遍历整个压缩列表才能计算得出
entry 不定 不定 元素内容,可以是字节数组,也可以是整数
zlend uint8_t 1字节 压缩列表结束标志,值恒为0xFF(十进制255)

下图是压缩列表的示意图
有趣的Redis:压缩列表是如何是如何实现的?_第2张图片
zlbytes的值为0x50(十进制80),表示压缩列表的总长度为80字节
zltail的值为0x3c(十进制60),entry3元素距离列表起始位置的偏移量为60,起始位置的指针加上60就能算出表尾节点entry3的地址
zllen的值为0x3(十进制3),表示压缩列表包含3个节点

那么每个元素的组成又是怎样的呢?
每个元素的数据结构如下图所示
有趣的Redis:压缩列表是如何是如何实现的?_第3张图片

previous_entry_length

previous_entry_length以字节为单位,记录了压缩列表中前一个节点的长度,这样主要为了方便倒着遍历。通过zltail属性直接定位压缩列表的最后一个节点,然后通过previous_entry_length定位前一个节点。

  1. 如果前一个节点的长度小与254字节,那么previous_entry_length属性的长度为1字节(1个字节可以表示的最大长度为28-1=255,但是255被设置为压缩列表的结束标志了,所以为254)
  2. 如果前一个节点的长度大于等于254字节,那么previous_entry_length属性的长度为5字节。属性的第一字节会被设置成0xFE(十进制为254),而之后的四个字节则用于保存前一字节的长度

encoding

encoding存储了元素内容的类型编码信息,ziplist通过这个字段来决定后面的content的形式
Redis通过encoding字段的前缀来识别存储的格式

字节数组编码

编码 编码长度 content属性保存的值
00xxxxxx 1字节 长度小于等于63的字节数组(26-1)
01xxxxxx xxxxxxxx 2字节 长度小于16383的字节数组(214-1)
10xxxxxx aaaaaaaa bbbbbbbb cccccccc dddddddd 5字节 长度小于238-1的字节数组

整数编码

编码 编码长度 content属性保存的值
11000000 1字节 int16_t类型的数
11010000 1字节 int32_t类型的数
11100000 1字节 int64_t类型的数
11110000 1字节 int24类型的数
11111110 1字节 int8类型的数
1111xxxx 1字节 0-12之间的数字,没有content

可以看到编码为 1111xxxx时,没有content
因为编码本身的xxxx四个位已经保存了一个介于0-12之间的值,所以它无需content属性。xxxx的范围只能是(0001-1101),也就是1~13,因为0000,1110,1111都被占用了。读取value后会减1,即能0-12之间的值

content

保存节点的值,节点值可以是字节数组或者整数,值的类型和长度由encoding决定

级连更新

参考博客

你可能感兴趣的:(Redis)