在Redis里面,C字符串只会作为字符串字面量,用在一些无须对字符串值进行修改的地方。
在Redis数据库里面,包含字符串值的键值对在底层都是由SDS实现的。
除了用来保存数据库中的字符串值之外,SDS还被用作缓冲区:AOF模块中的AOF缓冲区,以及客户端状态中的输入缓冲区。
1. SDS 的定义
每个sds.h/sdshdr结构表示一个SDS值。
// sdshdr 结构
struct sdshdr {
// buf 已占用长度
int len;
// buf 剩余可用长度
int free;
// 实际保存字符串数据的地方
// 利用c99(C99 specification 6.7.2.1.16)中引入的 flexible array member,通过buf来引用sdshdr后面的地址,
// 详情google "flexible array member"
char buf[];
};
SDS遵循C字符串以空字符串结尾的惯例(可以直接重用一部分C字符串函数库里面的函数),保存空字符的1字节空间不计算在SDS的len属性里面,由SDS函数自动完成空字符空间分配,以及空字符添加到字符串末尾。
对于SDS使用者完全透明。
2. SDS与C字符串的区别
C语言使用长度N+1的字符数组表示长度为N的字符串,并且最后一个元素总是空字符‘\0’
2.1 常数复杂度获取字符串长度
O(1)
设置和更新SDS长度的工作是由SDS的API在执行时自动完成的。
2.2 杜绝缓冲区溢出
SDS的API会先检查SDS的空间是否满足修改所需的要求,不满足,API会自动将SDS的空间扩展至执行修改所需的大小
2.3 减少修改字符串时带来的内存重新分配次数
通过未使用空间,SDS实现了空间预分配和惰性空间释放两种优化策略。
1.空间预分配
额外分配未使用空间数量由以下公式决定(空间不够时)
- 如果对SDS进行修改之后,SDS的长度(即len属性)小于1MB,那么程序分配和len属性同样大小的未使用空间,这时SDS len属性值将和free属性相同。
- 如果对SDS进行修改之后,SDS的长度将大于等于1MB,那么程序会分配1MB的未使用空间。
2.惰性空间释放
SDS的API需要缩短SDS保存的字符串时,使用free属性将这些字节的数量记录起来。
2.4 二进制安全
‘\0’
所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设,数据在写入时是什么样的,它被读取时就是什么样。
2.5 兼容部分C字符串函数
3.SDS API
sdsnew
sdsempty
sdsfree
sdslen
sdsavail
sdsdup 创建一个给定SDS的副本
sdsclear
sdscat
sdscatsds
sdscpy
sdsgrowzero 用空字符将SDS扩展至给定长度
sdsrange 保留SDS给定区间内的数据,不在区间内的数据会被覆盖或清除
sdstrim 接受一个SDS和一个C字符串作为参数,从SDS中移除所有在C字符串中出现过的字符。
sdscmp 对比两个SDS字符串是否相同个