存储结构
说明
- zlbytes: 压缩列表的字节长度,占4个字节,因此压缩列表最多有
2^32 -1个字节 - zltail: 压缩列表尾元素相对于压缩列表起始地址的偏移量,占4个字节
- zllen: 压缩列表的元素个数,占用两个字节。zllen无法存储超过65535(2^16-1)的压缩列表,必须遍历整个压缩列表才能获取到元素个数
- entryX: 压缩列表存储的元素,可以是字节数组或者整数,长度不限。
- zlend: 压缩列表的结尾,占1个字节,恒为0XFF
宏定义实现压缩列表各个字段的存取操作
问题
zlentry
对于压缩列表的任意元素,获取前一个元素的长度、判断存储的数据类型、获取数据内容都需要经过复杂的解码运算。
/* We use this function to receive information about a ziplist entry.
* Note that this is not how the data is actually encoded, is just what we
* get filled by a function in order to operate more easily. */
typedef struct zlentry {
unsigned int prevrawlensize; /* Bytes used to encode the previous entry len*/
unsigned int prevrawlen; /* Previous entry len. */
unsigned int lensize; /* Bytes used to encode this entry type/len.
For example strings have a 1, 2 or 5 bytes
header. Integers always use a single byte.*/
unsigned int len; /* Bytes used to represent the actual entry.
For strings this is just the string length
while for integers it is 1, 2, 3, 4, 8 or
0 (for 4 bit immediate) depending on the
number range. */
unsigned int headersize; /* prevrawlensize + lensize. */
unsigned char encoding; /* Set to ZIP_STR_* or ZIP_INT_* depending on
the entry encoding. However for 4 bits
immediate integers this can assume a range
of values and must be range-checked. */
unsigned char *p; /* Pointer to the very start of the entry, that
is, this points to prev-entry-len field. */
} zlentry;
如何遍历压缩列表?
对于任意一个元素,我们如何判断其存储的是什么类型?
如何获取字节的长度
操作
创建
#define intrev32ifbe(v) (v)
/* Create a new empty ziplist. */
unsigned char *ziplistNew(void) {
unsigned int bytes = ZIPLIST_HEADER_SIZE+ZIPLIST_END_SIZE;
unsigned char *zl = zmalloc(bytes);
ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);
ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);
ZIPLIST_LENGTH(zl) = 0;
zl[bytes-1] = ZIP_END;
return zl;
}
插入
插入步骤
- 元素内容编码
- 计算previous_entry_length
- 计算encoding字段
- 计算content字段
- 重新分配空间
- 复制数据
/* Insert an entry at "p". */
unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {
return __ziplistInsert(zl,p,s,slen);
}
创建
创建