redis中的字符串是二进制安全的,传统C字符串以'\0'为结尾,只能用于保存纯文本,不能用于保存音频、视频等二进制文件,因为只要在中间遇到'\0'就被截断了。redis的sds模块所有api都使用二进制方式处理字符串,因此叫做字节数组更为贴切。
数据结构:一个带控制结构的字符串,内存中起始地址是一个控制结构,包含一个柔性数组用来保存字符串,结尾加'\0',使用的时候返回的是字符串起始地址,所以需要获取控制结构中内容的时候用指针减控制结构大小去获取控制结构的起始地址,由于工作在用户态,没法使用container_of,所以经常用a[-1]这样的方式手动去获取控制结构中的内容,通过使用__attribute__((packet))来保证手动算出的偏移没有问题。sds字节数组根据字符串二进制位数使用不同控制结构,包括5,8,16,32,64,其中5不适用,例如字符串位数在8到16之间,那么就使用sdshdr16,其结构定义如下:
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[]; };
这个是长度为16的,其余类似
sds模块源码在sds.h和sds.c中,sds.h中提供了字节数组相关结构的定义,提供了一系列内联函数如下:
sdslen:获取一个sds的len
sdsavail:获取一个sds的可用长度
sdssetlen:设置一个sds的长度
sdsinclen:增加一个sds的长度
sdsalloc:返回一个sds的alloc
sdssetalloc:设置要给sds的alloc
sds.c中各函数功能(按照redis_4.0.9中字母顺序):
sdsHdrSize:根据提供的type返回控制结构的字节数
sdsReqType:根据提供的字符串二进制位数返回应使用的类型
sdsnewlen:新建一个sds
sdsempty:创建一个空的sds
sdsnew:将一个C字符串创建成一个sds
sdsdup:复制一个sds
sdsfree:释放一个sds
sdsupdatelen:将len修改成第一个'\0'结尾的字符串的长度
sdsclear:清零一个sds,不释放内存
sdsMakeRoomFor:给一个sds扩充空间
sdsRomoveFreeSpace:根据一个sds的len缩减到尽可能小的长度
sdsAllocSize:返回一个sds的总长度,包括头,alloc和'\0'
sdsAllocPtr:返回一个sds的控制结构的起始地址
sdsIncrLen:给一个sds增加一段长度并增加'\0',使用前应该确保先调用了sdsMakeRoomFor保证空间足够
sdsgrowzero:给一个sds的len增加到指定长度,并将增加部分内存清零
sdscatlen:在一个sds后面连接一个给定长度的字符串
sdscat:在一个sds后面连接一个指定字符串,内层是sdcatlen
sdscatsds:在一个sds后面连接另一个sds的数据部分
sdscopylen:将一个sds复制为给定长度的字符串
sdscpy:和sdscopylen类似,是针对C字符串的,而sdscopylen针对二进制安全数据
sdsll2str:将一个long long写入一个字符串并返回长度
sdsull2str:将一个unsigned long long 写入一个字符串并返回长度
sdsfromlonglong:使用一个long long制造一个sds
sdscatvprintf:将可变长格式化字符串连接到sds后面
sdscatprintf:是sdscatvprintf的包装
sdscatfmt:和sdscatvprintf功能一样,区别是不使用sprintf族函数,性能高
sdstrim:提供一个字符串和一个sds,将sds左边和右边在字符串中出现的字符全部切掉,保留剩下的部分,使用了strchr
sdsrange:将sds切片,提供起始和终止位置,可以是负数表示从结尾开始
sdstolower:将sds的所有字母变成小写,内部是tolower
sdstoupper:将sds的所有字母变成大写,内部是toupper
sdscmp:比较两个sds,内部是memcmp
sdssplitlen:将字符串用指定的分割器分割成若干部分,存入sds指针数组,并返回这个指针数组
sdsfreesplitres:释放sdssplitlen产生的指针数组和其中的sds的内存
sdscatrepr:将给定字符串以转义的方式连接到sds后
is_hex_digit:判断char c是否是十六进制数
hex_digit_to_int:将单个十六进制字符转换成十进制
sdssplitargs:将一行读取到sds指针数组
sdsmapchars:将sds中和from字符串中相同的字符替换成to字符串中相同位置的字符
sdsjoin:将若干C字符串用提供的分割器连接起来,产生一个sds
sdsjoinsds:和sdsjoin类似,连接的是若干sds
sds_malloc:分配内存
sds_realloc:重新分配内存
sds_free:释放内存