大纲:简述六种底层数据结构
简单动态字符串SDS
链表
字典
跳跃表
整数集合
压缩列表
阅读本文你将收获什么:
了解Redis底层的六种数据结构。
了解每种数据结构的实现方式以及设计上的优点。
Redis为什么这么快?
作为高速KV数据库,Redis的速度已经经过各大小公司的实战考验了,至于为什么这么快,各个理由从google上一搜大同小异,今天我们来聊一聊其底层实现的六大数据结构。
Redis的高效与其基本的数据结构也是密不可分的,为了满足效率和安全这些需求,Redis根据自身需要量身定制了数据结构。
一.简单动态字符串(simple dynamic string,SDS)
SDS:每个sdshdr结构表示一个SDS值
struct sdshdr {
// 记录buf数组中已使用字节的数量
// 等于SDS所保存字符串的长度
int len;
// 记录buf数组中未使用字节的数量
int free;
// 字节数组,用于保存字符串
char buf[ ];
};
图一·SDS示例
free属性值为0,表示这个SDS没有分配任何未使用空间。
len属性值为5,表示这个SDS保存了一个五字节长的字符串。
buf属性是一个char类型的数组,以'\0'结尾,不计算在len属性中。
优点:
以'\0'结尾可以直接使用C字符串函数库里的函数。
常数复杂度获取字符串长度O(1),只需要访问len属性即可。
杜绝缓冲区溢出,当SDS API需要对SDS进行修改时,会先检查SDS的空间是否满足需要,不满足则自动扩容,避免溢出。
减少修改字符串时带来的内存重分配次数。因为内存重分配涉及复杂的算法,并且可能需要执行系统调用,所以它通常是一个比较耗时的操作。
二进制安全。所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,数据在写入时是什么样的,它被读取时就是什么样。
空间预分配
如果对SDS修改后,其长度小于1M将分配和len属性同样大小的未使用空间,这时候len属性与free属性值相同。
如果对SDS修改后其长度大于1M,那么程序会分配1M的未使用空间。
惰性空间释放
惰性空间释放用于优化SDS的字符串缩短操作,当SDS的API需要缩短其保存的字符串时,程序不立即使用内存重新分配来回收多出来的字节,而是使用free属性将其记录,留待以后使用。
二.链表
listNode:每个链表节点用一个listNode结构来表示
typedef struct listNode {
// 前置节点
struct listNode *prev;
// 后置节点
struct listNode *next;
// 节点的值
void *value
}listNode;
list:虽然多个listNode结构可以组成链表,但由list来持有链表操作方便许多
typedef struct list {
// 表头结点
listNode *head;
// 表尾节点
listNode *tail;
// 链表所包含的节点数量
uns