背景
本次阅读的版本是redis5.0,sds共分为5种数据结构,sdshdr5,sdshdr8,sdshdr16,sdshdr32,sdshdr64。
阅读主要的源码文件为sds.h 和sds.c ,作为redis对字符串封装的结构体,它在内存控制,二进制安全,快速读取,字符串变长方面表现更好。
缺点:占用更多的内存空间,毕竟有头信息的存在。
1.sds基本结构
从上图可以看出,其基本结构可以大致分为:
头信息部分:
- 字符串总长度:
alloc - 字符串已使用长度:
len - 字符串类型标识:
flag - 字符串数组:
buff[]
而sds.c中,主要就是对于sds的各种操作,其中包括前面写的sdsnewlen(sds对象构建),sdsMakeRoomFor(sds扩容),sdsRemoveFreeSpace (sds压缩free空间)等基本操作。
通过阅读,发现对sds的操作主要分为下面几个操作:
对len操作
对alloc操作
对sds类型进行变更
对buff[]进行操作
而针对类型变更需要重新申请一片内存,然后通过复制和构造新sds,并释放旧sds。
2.sds的特殊性
虽然sds的结构体是包含4个部分,但是sds的指针并不是指向头部的,而是指向buff[]的。
这个实现其实并不新鲜,在mysql的行结构中,上一条记录指向下一条记录的指针(数据位置)也是真实数据位置,而不是行结构的头部位置。(可以参考一下我的mysql行结构解析里面的内容)
2.1 sds指向buff[]意义是啥呢?
1.跟C语言的字符串结构一致,向下兼容
2.向前拿到sds类型,就知道头的大小,就能计算出sds字符串的实际长度
3.拿到实际长度就能从sds当前指针向后读取实际长度的大小,就是实际字符串。(更快)
这样就不用单纯依据\0来作为字符串结束符来读取字符串了。(二进制安全,\0不会造成截断问题)
3.核心方法
sdsHdrSize 计算sds的头部大小sdsReqType 根据字符串长度获取sds类型sdsnewlen 根据初始值和初始长度创建sdssdsfree(sds s) 释放sdssdsupdatelen 对第一个\0终止符进行截取sdsclear 清理buff[] ,并将终止符设置到字符串的第一个位置sdsMakeRoomFor 字符串扩容一定长度sdsRemoveFreeSpace 字符串sds压缩,移除free空间,也就是len=allocsdsAllocSize sds整个结构所占字节大小*sdsAllocPtr 获取sds的头部指针
其他的方法就不一一列举了,其实,只要了解sds的结构和操作方式,其他的一些方法理解起来基本没啥问题。
|