(我贴的代码是本机6.2.1版本)
string:SDS(简单动态字符串)
redis是以c语言编写,但是redis的字符串没有直接使用C语言的以null结尾的字符串,而是采用SDS(Simple Dynamic String:简单动态字符串)
struct SDS<T> {
T capacity; // 数组容量Redis 字符串的长度不得超过 512M 字节。创建字符串时 len 和 capacity 一样长,不会多分配冗余空间,这是因为绝大多数场景下我们不会使用 append 操作来修改字符串。
T len; // 数组长度 因为把长度写在头部,不用像C语言一样以\0识别字符串结束符,所以sds是二进制安全的
byte flags; // sds类型,5 8 16 32 64位
byte[] content; // 数组内容
}
//追加字符串append
sds sdscatlen(sds s, const void *t, size_t len) {
size_t curlen = sdslen(s);//原字符串长度
s = sdsMakeRoomFor(s,len);//空间调整
if (s == NULL) return NULL;//内存不足
memcpy(s+curlen, t, len);//追加字符串到当前的content数组中
sdssetlen(s, curlen+len);//设置追加后的长度值
s[curlen+len] = '\0';//与C语言字符串一致,可以printf()调试、便于直接使用 glibc 的字符串处理函数
return s;
}
//按需调整空间
sds sdsMakeRoomFor(sds s, size_t addlen) {
void *sh, *newsh;
size_t avail = sdsavail(s);
size_t len, newlen;
char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen;
size_t usable;
/* 空间足够就直接返回新字符串 */
if (avail >= addlen) return s;
//接下来是空间不足的操作
len = sdslen(s);
sh = (char*)s-sdsHdrSize(oldtype);
newlen = (len+addlen);
assert(newlen > len); /* Catch size_t overflow */
if (newlen < SDS_MAX_PREALLOC) //小于SDS_MAX_PREALLOC(1M)时,每次分配的空间加倍
newlen *= 2;
else //大于SDS_MAX_PREALLOC后,每次加1M
newlen += SDS_MAX_PREALLOC;
type = sdsReqType(newlen);//根据长度划分新字符串所属的SDS数据类型
/* 不要使用类型5:用户正在追加字符串,而类型5无法记住空格,因此必须在每次追加操作时调用sdsMakeRoomFor() */
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
hdrlen = sdsHdrSize(type);//根据所属SDS数据类型计算所占内存
assert(hdrlen + newlen + 1 > len); /* Catch size_t overflow */
if (oldtype==type) {//所属的SDS数据类型不变时
newsh = s_realloc_usable(sh, hdrlen+newlen+1, &usable);
if (newsh == NULL) return NULL;
s = (char*)newsh+hdrlen;
} else {
/* Since the header size changes, need to move the string forward,
* and can't use realloc
如果类型发生变化,地址内容不可复用,所以找新的空间
*/
newsh = s_malloc_usable(hdrlen+newlen+1, &usable);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len+1);//将s复制到(char*)newsh+hdrlen +1是复制上\0
s_free(sh);//释放前面的内存空间
s = (char*)newsh+hdrlen;//调整s开始的位置,即地址空间指向新的buf开始的位置
s[-1] = type;//flag位置
sdssetlen(s, len);//分配len的值
}
usable = usable-hdrlen-1;
if (usable > sdsTypeMaxSize(type))//实际占用不能大于所属SDS数据类型最长占用字节
usable = sdsTypeMaxSize(type);
sdssetalloc(s, usable);//(根据类型)设置sds字符串容量
return s;
}<