Redis5设计与源码分析读后感(四)压缩列表

时间:2020-09-21 09:45:36   收藏:0   阅读:57

一、引言

  上一节我们总结了跳跃表的知识,我们知道了有序数组可以用跳跃表实现,也可以用压缩列表来实现,这一篇文章我们来总结一下压缩列表相关的知识。

二、压缩列表简介

  定义:压缩列表 ziplist 本质上是一个字节数组,每个元素可以是一个字节数组一个整数

  PS:Redis的有序集合散列列表都直接或间接用到了压缩列表。

三、压缩列表的存储结构

  我们通过一张图来直观地分析压缩列表的结构:

技术分享图片

  PS:1字节=8位,二进制里,每位对应2的n次方,1字节最大值为28-1个元素。

  PS:必须遍历整个压缩列表才能获取到元素个数。

四、压缩列表的元素的结构

  还是通过一张图来说明就比较直观一些:

技术分享图片

  PS:假设已知当前元素的首地址p,就可以根据 p-previous_entry_length 推算出前一个元素的首地址。

压缩列表的元素编码

技术分享图片

   简单总结一下:

五、结构体

  意义:由于每次获取前一个元素的内容都需要经过复杂的解码运算,影响效率,所以定义结构体 zlentry 用于表示解码后的压缩列表元素。

  PS:结构体实际上是对每个元素的首部【 previous_entry_length 和 encoding 】结构的细分描述。

结构体的字段

解码步骤

  解码主要用到的是 zipEntry 方法,解码出来的信息储存于 zlentry 结构体:

六、创建压缩列表

  创建压缩列表主要用到的方法为ziplistNew【返回参数为压缩列表的首地址】

  创建一个空的压缩列表需要分配的初始空间为11(4+4+2+1)个字节

七、插入元素

  插入元素主要用到的方法为ziplistInsert【返回参数为压缩列表的首地址】

  步骤:

将元素内容编码

  含义:将元素内容编码就是计算 previous_entry_length 字段、 encoding 字段、 content 字段的内容。

  计算前一个元素的长度又根据插入位置分为三种情况:

技术分享图片

重新分配空间

   首先定义几个变量:

  PS:需要考虑连锁更新的情况~

  详见书本解释~

数据复制

  含义:插入元素以后,插入点之后的元素都要向后进行移动,此时底层实现为复制元素到新的内存地址上。

  几个名词:

  PS:数据移动之后还需要更新entryX+1元素的 previous_entry_length 字段

八、删除元素

  删除元素主要用到的方法为ziplistDelete【返回参数为压缩列表的首地址】

  步骤:

  PS:新增元素是从新分配空间小于指针指向的空间时,可能会出现问题;而删除元素时,内存空间是肯定减小的,但是由于是先复制数据再发分配空间,则多余空间的数据已经复制好了,所以从新分配空间就不会产生这个问题。

九、遍历压缩列表

  向前遍历:

  向后遍历:

十、连锁更新

  连锁更新其实很好理解,就是更新一个元素的同时引发其他元素的同时更新,这种现象就叫连锁更新:

技术分享图片

我们可以看到,当在以下两种情况:

  都会导致连锁更新的发生,为什么呢?

P1位置删除entryX元素

   删除前,entryX的长度是128字节,所以entryX+1的 previous_entry_length 字段只需要1个字节就可以储存。

   但是当删除了entryX元素时,entryX+1的前一个元素变成了entryX-1,而entryX-1的长度为512字节,所以此时entryX+1的 previous_entry_length 字段需要用5个字节来储存

   entryX+1的 previous_entry_length 字段从1个字节变成5个字节以后,entryX+1的长度变成257字节,同时引发entryX+2也需要去改变它的 previous_entry_length 字段长度,从而引发连锁更新...

P2位置插入entryY元素

  与上面类似,就不再过多描述了。

原文:https://www.cnblogs.com/riches/p/13671153.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!