1.绪论
前面讲过的ziplist在查找元素的时候是o(n)的复杂度,如果ziplist长度太长,会导致查找元素很缓慢,而ziplist是拥有内存连续的优势,为了保留ziplist内存连续的优势,但是又不能保留太长的长度,我们出现了quicklist,quicklist其实就是将多个ziplist通过指针链接成一个双端链表。
2.组成
cpp
typedef struct quicklist {
//quciklist的头指针
quicklistNode *head;
//quicklist的尾指针
quicklistNode *tail;
//quicklist的entry个数,由于quicklist是由多个ziplist组成,这里包含的是quicklist下面所有的ziplist所有的entry个数
unsigned long count; /* total count of all entries in all ziplists */
//quicklist中节点的个数
unsigned long len; /* number of quicklistNodes */
//表示quicklist中每个ziplist节点的大小,默认为16个entry节点
int fill : QL_FILL_BITS; /* fill factor for individual nodes */
//表示压缩深度,比如为1,只压缩首尾两个节点
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;
可以看出,quickList是由多个ziplist组成的一个双向链表,其中有两个属性需要注意,分别是fill和compress。
fill: 表示每个ziplist最多包含的entry数量或者大小。可以通过list-max-ziplist-entries 进行设置**。**如果为正,表示最多包含多少个entry,如果为负的话,表示含义如下:
|----|--------|
| -1 | 最多4kb |
| -2 | 最多8kb |
| -3 | 最多16kb |
| -4 | 最多32kb |
| -5 | 最多64kb |
compress: 表示是压缩数量,如果为-1表示只压缩首尾两个节点,默认也是如此**。**
cpp
typedef struct quicklistNode {
//上一个节点指针
struct quicklistNode *prev;
//下一个节点指针
struct quicklistNode *next;
//ziplist,真正存储数据的地方
unsigned char *zl;
//ziplist的大小
unsigned int sz; /* ziplist size in bytes */
//ziplist的字节数量
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;
所以双端链表的组成如下