redis学习笔记: sds
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis学习笔记: sds相关的知识,希望对你有一定的参考价值。
sds(Simple Dynamic String): 它其实就是普通的字符串,只是在每个字符串的前面加了一个管理用的头部,相关类型结构的定义如下
typedef char *sds;
struct sdshdr {
unsigned int len; /* buf里面字符串的长度的 */
unsigned int free; /* buf里面剩余空间的大小,不算‘\0‘ */
char buf[];
};
它使用了零长数组,所以头部跟实际的内容是在一块连续的空间上,因此对外只需要返回buf的地址(也是sds),对内由sds的地址就能找到sdshdr(sds减8个字节)
相应地,sds内部实现了一些基本的操作,与c库最大的区别可能是sds的copy操作使用的是二进制(带长度的)操作。
sds内部分配新内存的原则是:
如果fee大于新增的长度,则不用新分配。
如果新的长度小于1M,则按新长度的2倍加sdshdr再1个字节来分配;
否则,分配的空间比新长度大1M加sdshdr再1个字节。
例如:一个sds存储"foo",那么其sdshdr={3,0,"foo"}。现在需要在其后面拼接" bar"四个字符。由于free是0,所以需要新的空间。由于3+4=7 < 1M,所以zrealloc时会指定长度为8 + 14 + 1。
zrealloc之后,sdshdr={7,7,"foo bar"}。只是,zrealloc之后,sdshdr本身的地址可能会变化?
具体可见函数sdsMakeRoomFor
sds sdsMakeRoomFor(sds s, size_t addlen) {
struct sdshdr *sh, *newsh;
size_t free = sdsavail(s);
size_t len, newlen;
if (free >= addlen) return s;
len = sdslen(s);
sh = (void*) (s-(sizeof(struct sdshdr)));
newlen = (len+addlen);
if (newlen < SDS_MAX_PREALLOC)
newlen *= 2;
else
newlen += SDS_MAX_PREALLOC;
newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
if (newsh == NULL) return NULL;
newsh->free = newlen - len;
return newsh->buf;
}
以上是关于redis学习笔记: sds的主要内容,如果未能解决你的问题,请参考以下文章