数据结构
ziplist字段说明:
名称 | 说明 | 长度 |
zlbytes | 记录当前ziplist结构的所有字节数,包含zlbytes的4个字节 | 4字节 |
zltail | 记录当前最尾的一个节点距离起始的位置 | 4字节 |
zllen | 记录当前的ziplist的entry个数 | 2字节 |
entry | ziplist中每一项数据,也是一个对象 | 由具体的编码决定大小 |
zlend | 记录当前ziplist的结束,固定值为255 | 1字节 |
entry字段说明:
名称 | 说明 | 长度 |
previous_entry_length | 前一项的字节长度 | |
encoding | 当前项的编码方式 | |
content | 实际存储的内容 |
previsous_entry_length: 如果当前的值小于254,则会以一个字节来存储数值(范围是0-253),相反,如果是大于等于254,则会以5个字节来存储,第一个字节固定为 0xFE (因为255是结束符),其余4个字段来存储具体数值。
encoding:取决于content字段的内容
string类型:以00/01/10开头
int 类型:以11 开头,再往下区分
当为 1111xxxx格式时(只代表0-12的数值),因为0000与1111是不能再使用了(实际是1-13),所以最终的数值要以xxxx-1作为实际的值
如 11111010 -> 对应存储的是整数 5
示例
zlbytes的值为15(以小端形式存储数据)
zltail 的值是12,表示最后一个索引是12
zlen 是2 ,entry的个数为2
entry1 第一个字节是0,因为是每一个元素,第二个字节是11110101,则代表的是0-12的整数,值为0101-1=2
entry2 第一个字节是00000010,记录的是前一个元素的长度2,encoding部分,为11111010 ,也是代表0-12的整数,值为1010-1=5
这时,如果插入新的数据 "hello world",则会产生以下新的数据
[02] [0b] [48 65 6c 6c 6f 20 57 6f 72 6c 64]
连锁更新
从ziplist的结构中,可以知道,当添加或是删除节点时,会因为要重新计算previous_entry_length的值,可能导致发生连锁更新的情况。
如果 entry1的previous_entry_length 只有1个字节,当新插入的节点的长度大于254时,因为entry1的previous_entry_length无法存储该数值,就需要将entry1的previous_entry_length长度更新为5个字节。
假设当前的entry1大小,再加上扩容后的4个字节,超过254时,则entry2的长度也要进行更新,则会一直更新下去,删除操作也是相同的问题。
对于每次的新增与删除,都需要进行空间分配,连锁更新的最坏的情况是O(N2),但一般只有当一个ziplist有连续的多个长度在250-253字节的节点时,才会出现这种情况。