Redis 早期版本存储 list 列表数据结构使用的是压缩列表 ziplist 和普通的双向链表 linkedlist,也就是元素少时用 ziplist,元素多时用 linkedlist。
而快速链表则是ziplist+linkedlist同时使用
快速列表
typedef struct quicklist {
quicklistNode *head; // 头指针
quicklistNode *tail; // 尾指针
unsigned long count; //所有压缩列表的节点数量之和。
unsigned long len; //快速列表节点数量。
int fill : QL_FILL_BITS; // 32 位机器上占 14 bit,64 位机器上占 16 bit,存放 list-max-ziplist-size 参数的值,用于设置压缩列表节点的大小。 /* fill factor for individual nodes */
unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
unsigned int bookmark_count: QL_BM_BITS;
quicklistBookmark bookmarks[];
} quicklist;
32 位机器上占 14 bit,64 位机器上占 16 bit,存放 list-compress-depth 参数的值,用于设置压缩深度。快速列表默认的压缩深度为 0,即不压缩。为了支持快速的 push/pop 操作,快速列表的首尾两个节点不压缩,此时压缩深度就是 1。如果压缩深度为 2,就表示快速列表的首尾第一个及第二个节点都不压缩。
- bookmark_count:占 4 bit,
- bookmarks 数组的长度。bookmarks:这是一个可选字段,快速列表重新分配内存时使用,不使用时不占用空间。
快速列表节点
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl;
unsigned int sz; /* ziplist size in bytes */
unsigned int count : 16; /* count of items in ziplist */
unsigned int encoding : 2; /* RAW==1 or LZF==2 */
unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */
unsigned int recompress : 1; /* was this node previous compressed? */
unsigned int attempted_compress : 1; /* node can't compress; too small */
unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;
- z1:数据指针,如果当前节点的数据没有压缩,它指向一个 ziplist 结构,否则,它指向一个 quicklistLZF 结构。
- sz:表示 zl 指向的数据总大小,注意,如果数据被压缩了,其表示压缩前的数据大小。
- count:占 16 bit,表示当前的快速列表节点中数据项个数。
- encoding:表示 当前节点的数据是否被压缩,目前只有两种取值:1 表示没有压缩;2 表示被压缩了,且用的是 LZF 压缩算法。
- container:略
- recompress:当我们使用类似 lindex 这样的命令查看了某一项本来压缩的数据时,需要把数据暂时解压,这时就设置 recompress=1 做一个标记,等有机会再把数据重新压缩。
quicklist 内部默认单个 ziplist 长度为 8k 字节
quicklist 默认的压缩深度是 0,也就是不压缩。压缩的实际深度由配置参数list-compress-depth决定。为了支持快速的 push/pop 操作,quicklist 的首尾两个 ziplist 不压缩,此时深度就是 1。如果深度为 2,就表示 quicklist 的首尾第一个 ziplist 以及首尾第二个 ziplist 都不压缩。
文章末尾请带上以下文字及链接:本文正在参与「掘金小册免费学啦!」活动, 点击查看活动详情