前言
- 在【数据结构】学习中,绕不过的就是链表和数组的学习了!数组应该更容易理解点!因为他和我们平时的逻辑一样。但是链表在刚入门的同学中应该算是比较抽象的了!尤其是指针交换位置更是容一部分同学望而却步!
- 今天我们来学习下
Redis
中的常用的链表数据结构
list
- 在
Redis
低版本(3.2之前)中list数据结构底层就是使用链表来进行串联数据的!
- 上图就是
Redis
中在操作List数据结构时的结构图!在redis
中并不是仅仅使用这一种双向的链表结构.关于ziplist等其他结构我们这里暂时不讨论。 - 而针对一整条链条redis有将它 抽象化一个list对象
- node是链条中重要的组成部分,而list我们可以理解成对整个链条的描述。list中包含头结点、尾结点、链条中节点个数、节点的复制释放比对等功能!
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;
typedef struct listIter {
listNode *next;
int direction;
} listIter;
typedef struct list {
listNode *head;
listNode *tail;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
unsigned long len;
} list;
函数 | 作用 |
---|---|
dup | 复制链表节点值 |
free | 释放链表节点值 |
match | 比对链表节点值与指定值是否想的相等 |
小结
- 很明显在redis中链表是一种双指针链表,可以通过当前节点轻松定位前后节点!
- list中可以轻松获取链表头尾节点!这也就解释redis中的lpush 、 rpush命令最终的实现了。就是通过改变头、尾指针就可以了。操作那是非常迅速的
- list中len表示链表长度。就是一个节点计数器。对应着llen 命令
- 了解数据结构后基本上就可以理解redis对应的操作命令在内存中的结构了
list其他数据结构
- 上面我们提到在3.2之前的版本中redis采用链表结构进行存储list数据。在3.2之后开始出现一种ziplist结构的数据结构!
- 首先我们思考下listnode用的好好的为什么要改用ziplist结构。因为list结构中存储了头尾节点方便了我们寻址但是牺牲了内存说白了就是空间换时间
- ziplist就是针对内存浪费的问题进行了优化。
- 我們看下ziplist的存储内存分布图(以下图片来源于网络)
位置 | 作用 |
---|---|
zlbytes | ziplist字节长度;长度最长为(2^32)-1 |
zltail | 整个ziplist偏移量;四个字节 |
zllen | ziplist中存储的元素个数;两个字节 |
entryX | ziplist中元素 |
zlend | 结束位 。固定值0xFF=255 |
typedef struct zlentry {
unsigned int prevrawlensize, prevrawlen;
unsigned int lensize, len;
unsigned int headersize;
unsigned char encoding;
unsigned char *p;
} zlentry;
小结
- ziplist又称为压缩列表本质上就是一个数组。除了list以外还有hash也都使用了ziplist. 压缩列表虽然节省了内存的开销但是随之而来的问题就是连锁更新。关于什么是连锁更新我们以后在分析!本文是一篇入门级的文章。
欢迎点个赞呗