源码位置: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. |