源码位置:ziplist.c/ziplist.h
ziplist在redis中主要用于Hash与List数据结构的底层实现之一,ziplist没有定义专门的结构体,其在内存块中的表示如下图所示:
ziplist结构:
| 属性 | 类型 | 长度 | 用途 | 
|---|---|---|---|
| zlbytes | uint_32t | 4B | 记录整个压缩列表占用的内存字节数:在对压缩列表进行内存重分配, 或者计算 zlend的位置时使用 | 
| zltail | uint_32t | 4B | 记录压缩列表表尾节点距离压缩列表的起始地址有多少字节:通过这个偏移量,程序无须遍历整个压缩列表就可以确定表尾节点的地址。 | 
| zllen | uint_16t | 2B | 记录了压缩列表包含的节点数量: 当这个属性的值小于UINT16_ MAX (65535)时, 这个属性的值就是压缩列表包含节点的数量; 当这个值等于 UINT16_MAX 时, 节点的真实数量需要遍历整个压缩列表才能计算得出。 | 
| entry | 列表节点 | 不定 | 压缩列表包含的各个节点,节点的长度由节点保存的内容决定。 | 
| zlend | uint_8t | 1B | 0xFF(255),用于标记压缩列表的末端。 | 
entry结构:
prevrawlen: 前置节点的长度
- 如果长度小于254个字节,则使用1字节(uint8_t)来存储prevrawlen。
 - 如果长度大于或等于254字节,则使用5字节(uint32_t)来存储prevrawlen。
 
len/encoding: 当前节点的长度(编码类型)
data: 数据
实际上,源码里有定义zlentry的结构体,但是这个结构体并不是实际上存储的节点结构,它仅做中间结构操作使用。
时间复杂度:
| 函数 | 作用 | 时间复杂度 | 
|---|---|---|
| ziplistNew | 创建跳跃表 | O(1) | 
| ziplistInsert | 插入节点 | 平均O(N)(耗时在连锁更新) | 
| ziplistDelete | 删除节点 | 平均O(N)(耗时在连锁更新) | 
| ziplistFind | 查找节点 | 平均O(N) | 
结构体与宏定义
1  | // ziplist.h:  | 
函数功能总览
1  | unsigned char *ziplistNew(void);  | 
主要函数实现
创建:
1  | // 创建新的压缩列表  | 
插入:
1  | unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where) {  | 
编码encoding字段相关:
1  | // 判断是不是整数字符串,如果是,确定其编码类型  | 
查找:
1  | /* Find pointer to the entry equal to the specified entry. Skip 'skip' entries  | 
遍历相关:
1  | // 返回下一个节点的位置  | 
查找:
1  | // 获取节点p的数据,如果是字符串,则填充到sstr和slen中,如果是整数,则填充到sval中  | 
删除:
1  | /* Delete a single entry from the ziplist, pointed to by *p.  | 


