简单动态字符串sds
redis没有直接使用c语言标准库中传统的字符串表示,而是自己构建了简单字符串(sds)的抽象类型,它的特点是:可在常数时间复杂度获取字符串长度,因为sds结构中保存了数据的长度、杜绝缓冲区溢出,可动态扩展内存,减少重复修改字符串带来的内存重新分配次数、惰性释放内存空间、二进制安全和兼容部分c语言字符串函数。
-
sds定义
typedef char *sds;
redis采用一段连续的内存来存储数据, char*类型和传统的c语言字符串类型兼容。但是,sds和char*不同之处是,sds是二进制安全的,它可以存储任意二进制数据,不像C语言字符串那样以‘\0’来标识字符串结束,sds结构的巧妙之处是在sds头部定义中。
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
/*! 记录buf数组中已使用的字节的数量,等于sds所保存字符串的长度*/
uint8_t len; /* used */
/*! 记录buf数组中未使用的字节数量,这个长度不包含sds头部和'\0'结束符长度*/
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
为了节省空间,sds另外还定义了sdshdr16、sdshdr32、sdshdr64结构,分别保存不同长度的数据。
sds的数据结构示例图为:
sds与c字符串相比的一些特点:
- 可在常数时间复杂度内获取字符串的长度,因为sds的头部结构中存储了字符串的长度。
- 杜绝缓冲区溢出,在修改sds内容时,sds的api先判断存储空间是否足够,之后再决定是否进行动态分配。
- 减少修改字符串时带来的内存重分配次数,采用了空间预分配与惰性空间释放。
- 二进制安全。
- 兼容部分c语言字符串函数。