redis sds
结构
sds主要由len
,alloc
和buf
构成。其中buf
是柔性数组,分配sds的时候,这个结构体会作为header。
1 | typedef char *sds; |
为sds分配空间,initlen
是字符串的长度,1是末尾的'\0'。
1 | sh = s_malloc(hdrlen+initlen+1); |
sdsnewlen、sdslen,sdsavail
sdsnewlen
返回的是char buf[]
首元素的地址,这个值作为sds
指针的值。这是sds中巧妙的地方。但是如何获取header地址,以及访问成员?毕竟相关字段是在柔性数组的前面。
sds - 1
就是flag
,由flag
可以得知header类型,也就知道header的长度,减去header的长度得到header的地址,访问len
成员即可得知buf
长度。1
sdshdr5
是一个特别的类型,长度和类型都隐藏在了flag
里面。SDS_TYPE_5
存储的是长度小于1 << 5
的字符数组,也就是可以用5 bit来表示。这样加上3 bit的类型,合起来刚好8 bit,就是一个flag
。1
*fp = type | (initlen << SDS_TYPE_BITS);
因此
flag
的3 lsb作为类型,5 msb作为长度。但sdshdr5
无法记录空闲的空间,因此无法扩容。
sdsgrowzero
- 新长度小于1MB,则buf大小翻倍
- 新长度大于等于1MB,则buf加1MB
sdstrim
trim后并未释放buf的空间。
提供了sdsRemoveFreeSpace
函数,可以完成在尾部没有空闲的空间。
sds与c字符串的区别
- 参数时间获取字符串长度
- 记录长度,避免buffer overflow
- 空间预分配、惰性释放,减少重分配次数
- 二进制安全
- 兼容部分c字符串函数
问题
- sds的定义使用了pack,内存没有对齐的情况下,会影响cpu访问内存的性能,这个是如何解决的?