Redis设计与实现(六)压缩列表
压缩列表是列表键和哈希键的底层实现之一,当一个列表键只包含少量的列表项,而且每个列表项都是小整数值或者长度比较小的字符串。那么就会使用压缩列表来进行列表键的底层实现。很明显在C的天下里面,int都要分位数,开发的人肯定是个极致思想的老铁。变态的压缩思想都来了,很多时候我们也在尽可能的去调整代码的深度,调前退出循环什么的,为什么Java里面好像不咋说压缩这回事。这个和java的设计有关系。很简单的说就是C站在了巨人的裤腰带上,java站在了巨人的肩膀上。所以导致java看不及下面的空间。
压缩列表是为了压缩内存而产生的东西。是由一系列特殊编码的连续内存组成的顺序型数据结构。一个列表包含多个节点。每个节点可以保存一个字节数组或者一个整型。
在设计的时候也是在数组的头上放点标识位.
zlbytes:是int32位的数据,用来计算整个压缩列表中占有的内存字节数,对压缩列表进行内存重分配。
zltail:也是int32位的数据,记录压缩列表尾节点距离压缩列表的起始地址有多少字节。这样就可以直接找到尾部。
zllen:是16位的数据,记录了压缩列表中真实的数据,这边有个bug,就是它是16位的,那最大值只有65536,如果超过了这个,依然会显示65536.
entry不限制大小,是一个存放数据的地方。
zlend标识尾巴0xff
看到这边我就在思考,怎么进行压缩的,你大小不知道,寻址的方法都变得复杂了,本身int就是纯净的数据,数组只是纯净数据的集合,浪费的最多是空间(int 64 放了一个16的数据)。你现在破坏了整体的规范性,寻址公式可能有不能用了 (y = 10x+30).
别着急往下看看。
entry肯定也是一种类(java的叫法)。字节数组有以下三种,长度小于等于63的,小于16838的,小于32个2-1的,三种模式,整数可以有以下六种长度,4位长 0-12之间的,1字节长度的有符号数,4字节长度的有符号,int16的整数,32,64.
每一个节点都是由previous_entry_length,encoding,content组成。
previous_entry_length表示:前一个数据的长度,以字节为单位,为1字节和5字节。
这为什么是后存前一个节点的原因我也不明白,偏爱从后往前遍历吗。这其实蛮有意思的,唯一我感觉能解释的就是zltail这个存了尾巴的偏移量。所有这样会方便一点。
encoding:记录了节点的content属性所保存数据的类型和长度
现在应该能感受出为什么叫压缩列表了,其实我个人真正意义上愿意叫他是个混合列表。什么都能存入,另外一个特点就是,大量的哨兵位来打破了固化设计。
压缩列表有个问题就是:连锁更新,什么是连锁更新,就是一个256插入新的压缩列表,导致后面的253的数据都要更新,进行扩容。像火车一样,每个后面的车厢都需要进行更新了。
这样的话会进行很操蛋的事情。