本月开始更新redis源码系列:
其他文章链接稍后更新~~
1.sds的介绍
2.为什么不使用string而是使用sds?
1.保存了一个len,可以直接获取字符串长度
2.杜绝缓冲区溢出
3.减少字符串修改时重新分配内存次数
4.二进制安全
3.sds3.2之前的数据结构
struct sds {
int len;// buf 中已占用字节数
int free;// buf 中剩余可用字节数
char buf[];// 数据空间,柔性数组的地址和结构体是连续的,这样查找内存更快(因为不需要额外通指针找到字符串的位置);可以很方便地通过柔性数组的首地址偏移得到结构体首地址,进而能很方便地获取其余量
};
这样设计的优点
4.我们从一个简单的问题开始思考:不同长度的字符串是否有必要占用相同大小的头部?一个int占4字节,32位,在实际应用中,存放于Redis中的字符串往往没有这么长,每个字符串都用4字节存储未免太浪费空间了。我们考虑三种情况:短字符串,len和free的长度为1字节就够了;长字符串,用2字节或4字节;更长的字符串,用8字节。
问题1:如何区分这3种情况?
问题2:对于短字符串来说,头部还是太长了。以长度为1字节的字符串为例,len和free本身就占了2个字节,能不能进一步压缩呢?
对于问题1,我们考虑增加一个字段flags来标识类型,用最小的1字节来存储,且把flags加在柔性数组buf之前,这样虽然多了1字节,但通过偏移柔性数组的指针即能快速定位flags,区分类型,也可以接受;
对于问题2,由于len已经是最小的1字节了,再压缩只能考虑用位
来存储长度了。
结合两个问题,5种类型(长度1字节、2字节、4字节、8字节、小于1字节)的SDS至少要用3位来存储类型(23 =8),1个字节8位,剩余的5位存储长度,可以满足长度小于32的短字符串。
5.在Redis 5.0中,我们用如下sdshdr5结构来存储长度小于32的短字符串。
struct __attribute__ ((__packed__))sdshdr5 {
unsigned char flags; /* 低3位存储类型, 高5位存储长度 flags占1个字节,其低3位(bit)表示type,高5位(bit)表示长度