目录
listpack 结构
listpack 节点结构
quicklist 虽然通过控制 quicklistNode 结构里的压缩列表的大小或者元素个数,来减少连锁更新带来的性能影响,但是并没有完全解决连锁更新的问题。
于是,Redis 在 5.0 新设计一个数据结构叫 listpack,目的是替代压缩列表,它最大特点是 listpack 中每个节点不再包含前一个节点的长度,而是记录当前节点的长度。
Listpack源码https://github.com/redis/redis/blob/unstable/src/listpack.clistpack 结构
listpack 头包含两个属性,分别记录了 listpack 总字节数和元素数量,然后 listpack 末尾也有个结尾标识。图中的 listpack entry 就是 listpack 的节点了,相对于ZipList没有记录,距离尾节点的偏移量,Listpack节省了这部分内存空间。
unsigned char *lpNew(size_t capacity) {
unsigned char *lp = lp_malloc(capacity > LP_HDR_SIZE+1 ? capacity : LP_HDR_SIZE+1);
if (lp == NULL) return NULL;
lpSetTotalBytes(lp,LP_HDR_SIZE+1);
lpSetNumElements(lp,0);
lp[LP_HDR_SIZE] = LP_EOF;
return lp;
}
listpack 节点结构
listpack entry主要包含三个方面内容:
- encoding,定义该元素的编码类型,会对不同长度的整数和字符串进行编码;
- data,实际存放的数据;
- len,encoding+data的总长度;
可以看到,listpack 没有压缩列表中记录前一个节点长度的字段了,listpack 只记录当前节点的长度,当我们向 listpack 加入一个新元素的时候,不会影响其他节点的长度字段的变化,从而避免了压缩列表的连锁更新问题。
listpackEntry中的改进 :
不同于ziplist,listpackEntry中的len记录的是当前entry的长度,而非上一个entry的长度。listpackEntry中可存储的为字符串或整型。
- 当存储的为字符串,那么lsentry的sval不为空,slen记录大小。
- 当存储的为整型,那么lval记录整型,sval字段为空