携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情 >>
redis数据结构——ZipList
对于Redis,相信各位朋友都不陌生,下面咱们就一起来学习一下Redis的其中一种数据结构——ZipList。
ZipList的基本介绍
其实,ZipList 可以理解为一种特殊的“双端链表” ,由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作, 并且该操作的时间复杂度为 O(1)。
下面展示的是ZipList的一个结构图:
通过上面这个图,我们可以非常清楚地看到每个属性的表示意义及其表示范围:
- zlbytes :它记录的是整个ZipList在内存中占用的字节数
- zltail :它表示的是尾结点距离整个ZipList起始地址之间的字节数,通过这个属性可以很块地定位到尾结点
- zllen:它记录的是整个ZipList中存放了多少个结点
- zlend :这个最要是用作标志位的,使用它来标志ZipList已经到达了末尾
经过了上面的介绍,相信大家都已经对ZipList的整体结构有了一个大致的认识了,下面再深入总结以下ZIpList的属性及其用途。
| 属性 | 类型 | 长度 | 作用 |
|---|---|---|---|
| zlbytes | uint32_t | 4 字节 | 它记录的是整个ZipList在内存中占用的字节数 |
| zltail | uint32_t | 4 字节 | 它表示的是尾结点距离整个ZipList起始地址之间的字节数,通过这个属性可以很块地定位到尾结点 |
| zllen | uint16_t | 2 字节 | 它记录的是整个ZipList中存放了多少个结点,即包含的结点数, 最大值为UINT16_MAX (65534),如果超过这个值,此处会记录为65535,但节点的真实数量需要遍历整个压缩列表才能计算得出。 |
| entry | 列表节点 | 不定 | 压缩列表包含的各个节点,节点的长度由节点保存的内容决定。 |
| zlend | uint8_t | 1 字节 | 这个是一个标志位,里面是一个特殊值 0xFF ,转换为十进制就是255,使用它来标志ZipList已经到达了末尾。 |
ZipList的实现
在文章的开头,我们说了ZipList可以看成一个特殊的双端链表。
相信大家对双端链表都非常熟悉吧,在一个结点里不仅要记录下一个结点是谁,还要记录上一个结点是谁。
虽然双端链表这个特性在某些情况下还是非常好用的,但是因为它每个结点都需要记录上一个结点、下一个结点,需要的额外空间变大了。
所以ZIpList的“双端链表”并不是像普通的双端链表那样实现的,ZipList表没有记录上一个结点或者下一个结点。
下面我们一起来看看ZipList中一个entry结点的结构(具体实现):
- previous_entry_length: 这个属性记录的是上一个结点的长度
- encoding: 这个属性,记录着content的数据类型(同时通过它还可以知道当前结点的长度,以此可以找到下一个结点)
- content: 这个属性是负责保存结点数据的,当然,这个数据包括字符串或者整数。
综上所述,ZIpList是一个特殊的双端链表,但是为了减少内存消耗,它的每个结点并不会去记录上一个结点或者下一个结点;ZIpList中记录的只是每一个结点的长度。
假如当前结点为 cur,其上一个结点为 pre,其下一个结点为 last。因为cur结点中记录了pre和cur的长度,所以cur地址减去pre的长度就找到了pre;cur地址加上 cur的长度就到了 last结点的起始位置。
总结
本文通过从ZipList的一个基本介绍到它的实现的讲述,让我们对ZipList有了一个比较好的认识,不管是新学习,还是复习都是由意义的。