在redis3.2之前,sds只有一个类型,定义如下:
struct sdshdr {
unsigned int len;//表示sds当前的长度
unsigned int free;//已为sds分配的长度-sds当前的长度
char buf[];//sds实际存放的位置
};
3.2开始改成如下
struct __attribute__ ((__packed__)) sdshdr5 {
//实际上这个类型redis不会被使用。他的内部结构也与其他sdshdr不同,直接看sdshdr8就好。
unsigned char flags; //一共8位,低3位用来存放真实的flags(类型),高5位用来存放len(长度)。
char buf[];//sds实际存放的位置
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len;//表示当前sds的长度(单位是字节)
uint8_t alloc; //表示已为sds分配的内存大小(单位是字节)
unsigned char flags; //用一个字节表示当前sdshdr的类型,因为有sdshdr有五种类型,所以至少需要3位来表示000:sdshdr5,001:sdshdr8,010:sdshdr16,011:sdshdr32,100:sdshdr64。高5位用不到所以都为0。
char buf[];//sds实际存放的位置
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
flags用来判断是什么类型,只需 flags&SDS_TYPE_MASK和SDS_TYPE_n比较即可(之所以需要SDS_TYPE_MASK是因为有sdshdr5这个特例,它的高5位不一定为0
不同长度的字符串用不同的结构体,例如100byte的用sdshdr8,主要是看2^8字节长度用sdshdr8,2^16字节长度用sdshdr16,以此类推
根据len能知道字符串长度,而不用每次都遍历才能知道长度
根据长度,可以存储二进制数据,而不单单存字符串,因为在c语言里,0表示字符串结束,所以如果二进制数据中有0的话,就会表示读取结束,知道长度就可以这么用
memcpy(s, init, initlen); //memcpy不会因为'\0'而停下,支持二进制数据的拷贝
sds加长内存分配规则,如图所示

加长的时候,字符串最终长度如果小于SDS_MAX_PREALLOC,就以当前长度的2倍扩增,如果大于等于SDS_MAX_PREALLOC,给以SDS_MAX_PREALLOC递增,其中SDS_MAX_PREALLOC在sds.h里默认是1mb
如果扩充后的sdshdr类型不变,则在原有的地方realloc就好。因为len和alloc的类型还是原来的。
如果扩充后的sdshdr类型变了,那就只能重新在别的地方分配内存,然后重新赋值,释放掉旧的内存。
sds缩减的话,有三个函数:sdsclear、sdstrim、sdsrange,他们都不会改变alloc的大小即不会释放任何内存,这就是sds字符串内存管理的一种方式:惰性释放。额外调用sdsRemoveFreeSpace释放内存,这样就节省了每次sds缩减长度而导致的内存释放开销。sdsRemoveFreeSpace这个函数压缩内存,让alloc=len。如果type变小了,则另开一片内存复制,重新执行sds加长操作,如果type不变,则realloc