视频剪辑软件 HTML框架 vim复制 razor random UIkit vue过滤器 jmeter性能测试视频 erp系统源码 大数据驾驶舱 ps字体旋转角度 查看rabbitmq版本 hbase端口 mysql分区表优劣分析 java不定长数组 python界面 java注释 java获取年份 java接口文档 java的运行环境 java文件重命名 java日期类 java集合类 java怎么学 java异常 linux密码 ie模拟器 xp画图工具 adobe清理工具 din字体 jdk9下载 c4d挤压 unity3d中文版 mix2s拆机 c语言从入门到精通 相册制作软件 android下载文件 appsync补丁 寂静城 studio3t
当前位置: 首页 > 学习教程  > 编程语言

Redis 设计与实现 5:压缩列表 ziplist

2020/12/28 19:48:39 文章标签:

压缩列表是 ZSET、HASH和 LIST 类型的其中一种编码的底层实现,是由一系列特殊编码的连续内存块组成的顺序型数据结构,其目的是节省内存。 ziplist 的结构 外层结构 下图展示了压缩列表的组成: ziplist 的结构 各个字段的含义如下&#xff1…

压缩列表是 ZSET、HASH和 LIST 类型的其中一种编码的底层实现,是由一系列特殊编码的连续内存块组成的顺序型数据结构,其目的是节省内存。

ziplist 的结构
外层结构
下图展示了压缩列表的组成:
ziplist 的结构

各个字段的含义如下:

zlbytes:是一个无符号 4 字节整数,保存着 ziplist 使用的内存数量。
通过 zlbytes,程序可以直接对 ziplist 的内存大小进行调整,无须为了计算 ziplist 的内存大小而遍历整个列表。
zltail:压缩列表 最后一个 entry 距离起始地址的偏移量,占 4 个字节。
这个偏移量使得对表尾的 pop 操作可以在无须遍历整个列表的情况下进行。
zllen:压缩列表的节点 entry 数目,占 2 个字节。
当压缩列表的元素数目超过 2^16 - 2 的时候,zllen 会设置为216-1,当程序查询到值为216-1,就需要遍历整个压缩列表才能获取到元素数目。所以 zllen 并不能替代 zltail。
entryX:压缩列表存储数据的节点,可以为字节数组或者整数。
zlend:压缩列表的结尾,占一个字节,恒为 0xFF。
实现的代码 ziplist.c 中,ziplist 定义成了宏属性。

// 相当于 zlbytes,ziplist 使用的内存字节数
#define ZIPLIST_BYTES(zl) (((uint32_t)(zl)))
// 相当于 zltail,最后一个 entry 距离 ziplist 起始位置的偏移量
#define ZIPLIST_TAIL_OFFSET(zl) (((uint32_t)((zl)+sizeof(uint32_t))))
// 相当于 zllen,entry 的数量
#define ZIPLIST_LENGTH(zl) (((uint16_t)((zl)+sizeof(uint32_t)*2)))
// zlbytes + zltail + zllen 的长度,也就是 4 + 4 + 2 = 10
#define ZIPLIST_HEADER_SIZE (sizeof(uint32_t)*2+sizeof(uint16_t))
// zlend 的长度,1 字节
#define ZIPLIST_END_SIZE (sizeof(uint8_t))
// 指向第一个 entry 起始位置的指针
#define ZIPLIST_ENTRY_HEAD(zl) ((zl)+ZIPLIST_HEADER_SIZE)
// 指向最后一个 entry 起始位置的指针
#define ZIPLIST_ENTRY_TAIL(zl) ((zl)+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)))
// 相当于 zlend,指向 ziplist 最后一个字节
#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
以下是重建新的空 ziplist 的代码实现,在 ziplist.c 中:

unsigned char *ziplistNew(void) {
// ziplist 头加上结尾标志字节数,就是 ziplist 使用内存的字节数了
unsigned int bytes = ZIPLIST_HEADER_SIZE+ZIPLIST_END_SIZE;
unsigned char *zl = zmalloc(bytes);
ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);
// 因为没有 entry 列表,所以尾部偏移量是 ZIPLIST_HEADER_SIZE
ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);
// entry 节点数量是 0
ZIPLIST_LENGTH(zl) = 0;
// 设置尾标识。
// #define ZIP_END 255
zl[bytes-1] = ZIP_END;
return zl;
}
entry 节点的结构
布局
节点的结构一般是:

prevlen:前一个 entry 的大小,用于反向遍历。
encoding:编码,由于 ziplist 就是用来节省空间的,所以 ziplist 有多种编码,用来表示不同长度的字符串或整数。
data:用于存储 entry 真实的数据;
prevlen
节点的 prevlen 属性以字节为单位,记录了压缩列表中前一个节点的长度。编码长度可以是 1 字节或者 5 字节。

当前面节点长度小于 254 的时候,长度为 1 个字节。
当前面节点长度大于 254 的时候,1 个字节不够存了。前面第一个字节就设置为 254,后面 4 个字节才是真正的前面节点的长度。
下图展示了 1 字节 和 5 字节 prevlen 的示意图(来源)
不同长度的 prevlen 示意图

prevlen 属性主要的作用是反向遍历。通过 ziplist 的 zltail,我们可以得到最后一个节点的位置,接着可以获取到前一个节点的长度 len,指针向前移动 len,就是指向倒数第二个节点的位置了。以此类推,可以一直往前遍历。

encoding
encoding 记录了节点的 data 属性所保存数据的类型和长度。类型主要有两种:字符串和整数。

类型 1. 字符串
如果 encoding 以 00、01 或者 10 开头,就表示数据类型是字符串。

#define ZIP_STR_06B (0 << 6)
#define ZIP_STR_14B (1 << 6)
#define ZIP_STR_32B (2 << 6)
字符串有三种编码:

长度 < 2^6 时,以 00 开头,后 6 位表示 data 的长度,。
2^6 <= 长度 < 2^14 时,以 01 开头,后续 6 位 + 下一个字节的 8 位 = 14 位表示 data 的长度。
2^14 <= 长度 < 2^32 字节时,以 10 开头,后续 6 位不用,从下一字节起连续 32 位表示 data 的长度。
下图为字符串三种长度结构的示意图(来源):
ziplist 字符串编码示意图
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/889
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/885
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/890
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/886
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/891
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/887
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/892
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/888
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/893
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/889
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/894
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/890
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/895
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/891
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/896
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/892
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/897
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/893
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/898
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/894
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/899
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/895
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/900
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/896
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/901
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/897
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/902
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/898
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/903
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/899
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/904
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/905
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/900
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/906
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/901
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/907
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/902
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/908
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/903
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/909
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/904
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/910
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/905
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/911
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/906
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/912
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/913
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/907
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/914
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/908
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/915
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/909
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/916
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/917
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/910
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/918
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/911
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/919
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/912
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/920
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/913
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/921
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/914
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/922
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/915
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/923
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/916
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/924
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/917
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/925
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/918
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/926
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/919
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/927
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/920
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/928
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/929
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/921
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/930
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/922
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/923
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/931
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/924
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/932
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/925
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/933
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/926
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/934
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/927
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/935
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/936
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/928
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/937
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/929
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/938
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/930
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/931
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/939
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/932
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/940
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/933
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/941
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/934
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/942
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/935
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/943
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/936
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/937
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/944
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/945
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/938
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/946
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/939
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/947
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/940
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/941
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/948
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/942
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/949
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/950
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/943
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/951
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/944
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/952
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/945
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/946
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/953
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/947
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/954
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/955
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/948
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/956
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/949
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/957
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/950
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/958
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/951
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/959
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/960
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/952
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/953
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/961
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/962
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/954
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/963
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/955
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/964
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/956
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/965
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/966
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/957
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/967
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/958
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/968
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/959
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/969
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/960
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/961
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/970
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/971
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/962
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/972
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/963
https://ggithub.com/fdxr69x2/lfwjghixlp/discussions/973
https://ggithub.com/a9r036f3/kptbymhxiy/discussions/964
https://ggithub.com/91sipp68/jgvawurmpd/discussions/398
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/391
https://ggithub.com/91sipp68/jgvawurmpd/discussions/399
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/392
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/393
https://ggithub.com/91sipp68/jgvawurmpd/discussions/400
https://ggithub.com/91sipp68/jgvawurmpd/discussions/401
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/394
https://ggithub.com/91sipp68/jgvawurmpd/discussions/402
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/395
https://ggithub.com/91sipp68/jgvawurmpd/discussions/403
https://ggithub.com/91sipp68/jgvawurmpd/discussions/404
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/396
https://ggithub.com/91sipp68/jgvawurmpd/discussions/405
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/397
https://ggithub.com/91sipp68/jgvawurmpd/discussions/406
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/398
https://ggithub.com/91sipp68/jgvawurmpd/discussions/407
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/399
https://ggithub.com/91sipp68/jgvawurmpd/discussions/408
https://ggithub.com/91sipp68/jgvawurmpd/discussions/409
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/400
https://ggithub.com/91sipp68/jgvawurmpd/discussions/410
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/401
https://ggithub.com/91sipp68/jgvawurmpd/discussions/411
https://ggithub.com/91sipp68/jgvawurmpd/discussions/412
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/402
https://ggithub.com/91sipp68/jgvawurmpd/discussions/413
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/403
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/404
https://ggithub.com/91sipp68/jgvawurmpd/discussions/414
https://ggithub.com/91sipp68/jgvawurmpd/discussions/415
https://ggithub.com/91sipp68/jgvawurmpd/discussions/416
https://ggithub.com/91sipp68/jgvawurmpd/discussions/417
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/405
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/406
https://ggithub.com/91sipp68/jgvawurmpd/discussions/418
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/407
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/408
https://ggithub.com/91sipp68/jgvawurmpd/discussions/419
https://ggithub.com/91sipp68/jgvawurmpd/discussions/420
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/409
https://ggithub.com/91sipp68/jgvawurmpd/discussions/421
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/410
https://ggithub.com/91sipp68/jgvawurmpd/discussions/422
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/411
https://ggithub.com/91sipp68/jgvawurmpd/discussions/423
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/413
https://ggithub.com/91sipp68/jgvawurmpd/discussions/424
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/414
https://ggithub.com/91sipp68/jgvawurmpd/discussions/425
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/415
https://ggithub.com/91sipp68/jgvawurmpd/discussions/426
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/416
https://ggithub.com/91sipp68/jgvawurmpd/discussions/427
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/417
https://ggithub.com/91sipp68/jgvawurmpd/discussions/428
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/418
https://ggithub.com/91sipp68/jgvawurmpd/discussions/429
https://ggithub.com/l32nyw20/pmtfvfmhdz/discussions/419
https://ggithub.com/91sipp68/jgvawurmpd/discussions/430
类型 2. 整数
如果 encoding 以 11 开头,就表示数据类型是整数。

#define ZIP_INT_16B (0xc0 | 0<<4)
#define ZIP_INT_32B (0xc0 | 1<<4)
#define ZIP_INT_64B (0xc0 | 2<<4)
#define ZIP_INT_24B (0xc0 | 3<<4)
#define ZIP_INT_8B 0xfe

#define ZIP_INT_IMM_MIN 0xf1 /* 11110001 /
#define ZIP_INT_IMM_MAX 0xfd /
11111101 */
整数一共有 6 种编码,说起来麻烦,看图吧(来源)。
ziplist 整数编码示意图
看了上图的最后一个类型,可能有小伙伴就有疑问:为啥没有 11111111 ?
答:因为 11111111 表示 zlend (十进制的 255,十六进制的 oxff)

data
data 表示真实存的数据,可以是字符串或者整数,从编码可以得知类型和长度。知道长度,就知道 data 的起始位置了。

比较特殊的是,整数 1 ~ 13 (0001 ~ 1101),因为比较短,刚好可以塞在 encoding 字段里面,所以就没有 data。

连锁更新
通过上面的分析,我们知道:

前个节点的长度小于 254 的时候,用 1 个字节保存 prevlen
前个字节的长度大于等于 254 的时候,用 5 个字节保存 prevlen
现在我们来考虑一种情况:假设一个压缩列表中,有多个长度 250 ~ 253 的节点,假设是 entry1 ~ entryN。
因为都是小于 254,所以都是用 1 个字节保存 prevlen。
如果此时,在压缩列表最前面,插入一个 254 长度的节点,此时它的长度需要 5 个字节。
也就是说 entry1.prevlen 会从 1 个字节变为 5 个字节,因为 prevlen 变长,entry1 的长度超过 254 了。
这下就糟糕了,entry2.prevlen 也会因为 entry1 而变长,entry2 长度也会超过 254 了。
然后接着 entry3 也会连锁更新。。。直到节点不超过 254, 噩梦终止。。。

这种由于一个节点的增删,后续节点变长而导致的连续重新分配内存的现象,就是连锁更新。最坏情况下,会导致整个压缩列表的所有节点都重新分配内存。

每次分配空间的最坏时间复杂度是 O(n),所以连锁更新的最坏时间复杂度高达 O(n2) !

虽然说,连锁更新的时间复杂度高,但是它造成大的性能影响的概率很低,原因如下:

压缩列表中需要需要有连续多个长度刚好为 250 ~ 253 的节点,才有可能发生连锁更新。实际上,这种情况并不多见。
即使有连续多个长度刚好为 250 ~ 253 的节点,连续的个数也不多,不会对性能造成很大影响
因此,压缩列表插入操作,平均复杂度还是 O(n).

总结:
压缩列表是一种为节约内存而开发的顺序型数据结构,是 ZSET、HASH 和 LIST 的底层实现之一。
压缩列表有 3 种字符串类型编码、6 种整数类型编码
压缩列表的增删,可能会引发连锁更新操作,但这种操作出现的几率并不高。


本文链接: http://www.dtmao.cc/news_show_550395.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?