Redis设计与实现——数据结构与对象(一)
1、 简单的动态字符串
-
sds用途
-
实现字符串对象
-
在Redis程序内部用作char* 类型的替代品(why?)
char*类型的功能单一,抽象的层次太低,并且不能高效地支持Redis常用的操作(比如追加操作和长度计算操作)
-
-
sds的定义
typedef char *sds; struct sdshdr { // buf 已占用长度 int len; // buf 剩余可用长度 int free; // 实际保存字符串数据的地方 char buf[]; };
-
SDS与C字符串的区别
-
常量复杂度获取字符串的长度
-
杜绝缓冲区溢出
除了获取字符串长度的复杂度高除外,C字符串不记录自身长度带来的另一个问题是容易造成缓冲区溢出
-
减少修改字符串时带来的内存重新分配次数
- 空间预分配(不仅仅会分配SDS分配修改必须要的空间,还会为SDS分配额外的未使用的空间)
- 惰性空间的释放:当SDS的API需要缩短SDS保存的字符串时,程序不立即内存重新分配,而是使用free特性将字节数记录起来以便以后使用
-
二进制安全:c字符串中的字符必须符合某种编码,除去某位之外,不得包含任何空格,否则会被认为是某位,故C字符串智能保存文本,而不能保存图片、音频、视频、压缩文件这样的二进制数据
-
兼容部分C字符串函数
遵循C字符串以空字符结尾的管理
-
-
SDS的API
函数 作用 算法复杂度 sdsnewlen
创建一个指定长度的 sds
,接受一个 C 字符串作为初始化值O(N)O(N) sdsempty
创建一个只包含空白字符串 ""
的sds
O(1)O(1) sdsnew
根据给定 C 字符串,创建一个相应的 sds
O(N)O(N) sdsdup
复制给定 sds
O(N)O(N) sdsfree
释放给定 sds
O(N)O(N) sdsupdatelen
更新给定 sds
所对应sdshdr
结构的free
和len
O(N)O(N) sdsclear
清除给定 sds
的内容,将它初始化为""
O(1)O(1) sdsMakeRoomFor
对 sds
所对应sdshdr
结构的buf
进行扩展O(N)O(N) sdsRemoveFreeSpace
在不改动 buf
的情况下,将buf
内多余的空间释放出去O(N)O(N) sdsAllocSize
计算给定 sds
的buf
所占用的内存总数O(1)O(1) sdsIncrLen
对 sds
的buf
的右端进行扩展(expand)或修剪(trim)O(1)O(1) sdsgrowzero
将给定 sds
的buf
扩展至指定长度,无内容的部分用\0
来填充O(N)O(N) sdscatlen
按给定长度对 sds
进行扩展,并将一个 C 字符串追加到sds
的末尾O(N)O(N) sdscat
将一个 C 字符串追加到 sds
末尾O(N)O(N) sdscatsds
将一个 sds
追加到另一个sds
末尾O(N)O(N) sdscpylen
将一个 C 字符串的部分内容复制到另一个 sds
中,需要时对sds
进行扩展O(N)O(N) sdscpy
将一个 C 字符串复制到 sds
O(N)