前言:压缩列表是列表键、哈希键、有序集合的底层实现之一。
当一个列表键只包含少量列表项,并且每个项要么是小整数或者短字符串的时候,redis使用压缩列表来实现列表键。
当一个哈希键只包含少量键值对,并且每个键值对要么是小整数值,要么是短字符串,redis使用压缩列表实现哈希键。
一、实现
压缩列表是redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序性数据型数据结构。一个压缩列表可以包含任意多个节点,每个节点可以保存一个字节数组或者一个整数值。
1.1、压缩列表
1.2、压缩列表节点
1、pre_entry_length 记录了前一个节点的长度,通过这个值,可以进行指针计算,从而跳转到上一个节点。只要用指针减去当前节点pre_entry_length 值,就可以得出前一个节点的指针。压缩列表从节点尾部想头部遍历就是利用这一点。
2、encoding 决定了 content 部分所保存的数据的类型以及长度。
3、content负责保存节点的值,节点值可以是一个字节数组或者整数。
二、连锁更新
添加和删除 ziplist 节点有可能会引起连锁更新,因此,添加和删除操作的最坏复杂度为 O(N^2) ,不过,因为连锁更新的出现概率并不高,所以一般可以将添加和删除操作的复杂度视为 O(N)。
为什么会连锁更新?
主要是因为pre_entry_length记录了前一个节点的长度,
如果前一个节点长度小于等于254字节,pre_entry_length将会是1个字节长度。
如果前一个节点长度大于254字节,pre_entry_length将会是5个字节长度。
如果有一种情况:压缩列表中有多个连续250-253字节的节点。由于都是这么长,所以这些节点的pre_entry_length都是一个字节,但是突然插入了一个新的节点,他的长度超过了254个字节,那么所有的节点的pre_entry_length都要变成5个字节,一个一个连锁反应,都要改变。
当然,删除节点也会引起这样的变化。