Redis数据结构:SDS
首先需要知道的是redis是用C语言实现的,那么我们需要提前知道一些C语言的常识。这里就不带大家去学习C语言了,仅会在需要的时候去介绍。
什么是SDS
SDS(simple dynamic string)是redis设计出来专门用于存储字符类型的数据结构。
- 数据结构
struct sdshdr{
//表示已经使用了多少字节
//即buf里面保存的数据的长度。
int len;
//表示还有多少剩余空间可用
int free;
//字符数据,用于实际保存数据
char buf[];
}
SDS的优点
1、更安全:
(1)二进制安全:若用原始C语言字符串进行存储,那么只能存储文本。但是对于图像、视频、音频等文件就不能存储了。
- 如:要保存 redis \0 test。C的话就会直接忽视后面的test内容,但是SDS就不会了。因为SDS为了二进制安全,对于所存储的内容不会进行任何的假设、过滤等操作。全部按照二进制进行读取,然后配合上len。那么就能做到二进制安全。
(2)不会内存溢出和内存泄露:在分配前会首先对free进行判断,若不否用会进行空间重新分配,然后才进行修改。若够用则直接修改。而这些操作都是封装在API 里面的,直接用就行。不会造成溢出。
2、效率更高:
(1)获取长度的复杂度是o(1)。C语言里的字符数组获取长度的复杂度是o(n)。
(2)空间预分配:就是当进行append的时候如果空间不够了。那么就进行空间申请。但是不会只申请所需字节。而是会多申请一些,那么这里申请多少具体是怎么计算的呢?
- 若修改后len的小于1MB,则free = len。如:len = 5 , free = 5。需要append 8 字节。那么最终len = 10, free = 10。buf的大小等于 10 + 10 + 1,此处的1是用于保存结束字符"\0"的。
- 若修改后len的大于1MB,则free = 1MB。如:len = 5MB,free = 2B。需要append 1MB。那么最终len = 6MB, free = 1MB。buf的大小等于 6MB + 1MB + 1。
(3)空间惰性释放:就是当我们要进行trim的时候,并不是立即就进行空间的释放。而是把需要释放的空间放在free里面,并且操作buf进行相应处理。但是此时free + len和原始初始的free + len是一样的。那么这样会不会造成空间的浪费呢?确实会,但是redis会在需要的时候真正的去释放空间。所以不需要担心。
总而言之 2 和 3 就是为了减少空间重新分配的次数。 不然若直接用C语言原始字符串,那么只要进行修改就会进行空间的重新分配。而空间的重新分配是挺耗时的。
注意
buf仍以“\0”结尾,但是不计算在len里面。其目的主要就是为了便于使用一些C语言的函数,避免重复造轮子。