主要函数
简介
redis 源码版本:3.05.04
如有理解不对的地方,欢迎各位指出,大家共同交流和学习。
源码学习
sdsMakeRoomFor函数
给一个sds扩充空间以供以后使用(核心函数,后面的函数会经常使用)
sds sdsMakeRoomFor(sds s, size_t addlen) {
struct sdshdr *sh, *newsh;
size_t free = sdsavail(s); //获取的s的剩余空间
size_t len, newlen;
if (free >= addlen) return s; //剩余空间够,则直接返回
len = sdslen(s); //空间不够,获取s的长度
sh = (void*) (s-(sizeof(struct sdshdr)));//获取sds对应结构体的地址
newlen = (len+addlen); //计算新追加字符串和原来字符串所占用空间的总长度
if (newlen < SDS_MAX_PREALLOC) //如果总长度小于1M,则分配实际字符串所需空间为总长度的2倍
newlen *= 2;
else
newlen += SDS_MAX_PREALLOC; //如果总长度大于1M,则分配实际字符串所需空间为总长度的基础上增加1M
newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);//重新申请更大的内存空间
if (newsh == NULL) return NULL;
newsh->free = (int)(newlen - len); //更新剩余大小,即实际字符串所需空间总长度减去字符串的大小 WIN_PORT_FIX /* cast (int) */
return newsh->buf;
}
根据头文件可知,SDS_MAX_PREALLOC是1M空间。
#define SDS_MAX_PREALLOC (1024*1024)
此函数,采用空间换时间的方式,利用预分配策略,较少频繁分配内存。C++中的vector也是采用类似的空间换时间方式。
sdsRemoveFreeSpace函数
根据实际使用长度减少sds的分配内存
sds sdsRemoveFreeSpace(sds s) {
struct sdshdr *sh;
sh = (void*) (s-(sizeof(struct sdshdr)));
sh = (struct sdshdr *)zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);
sh->free = 0;//将剩余可用空间置为0
return sh->buf;
}
sdsAllocSize函数
返回一个sds的分配空间的总长度
//总大小包括指针前的sds头、字符串实际大小、剩余空间以及结束符
size_t sdsAllocSize(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
//见篇一
return sizeof(*sh)+sh->len+sh->free+1;
}
sdsIncrLen函数
增加一个sds的已经使用的长度
/*要求加完之后不能超过分配的内存长度
此函数用于在用户调用sdsMakeRoomFor()、在当前字符串结束后写入内容并最终需要设置新长度后修复字符串长度。
注意:可以使用负增量来右修剪字符串。*/
void sdsIncrLen(sds s, int incr) {//incr可正可负
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
if (incr >= 0)
assert(sh->free >= (unsigned int)incr);
else
assert(sh->len >= (unsigned int)(-incr));
sh->len += incr; //增加sds长度
sh->free -= incr; //减少字符串末尾的剩余可用空间
s[sh->len] = '\0';//根据“incr”的字符串结尾。设置空项在。
}
sdsgrowzero函数
将sds增长到指定长度。不属于sds原始长度的字节将设置为零。
sds sdsgrowzero(sds s, size_t len) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));//通过减去偏移量获取对应的 sdshdr 指针首地址。
size_t totlen, curlen = sh->len;
if (len <= curlen) return s; //如果指定的长度小于当前长度,则不执行任何操作。
s = sdsMakeRoomFor(s,len-curlen); //扩充空间
if (s == NULL) return NULL;
/* 确保添加的区域不包含垃圾数据 */
sh = (void*)(s-(sizeof(struct sdshdr)));
memset(s+curlen,0,(len-curlen+1)); //将增加部分内存清零
totlen = sh->len+sh->free;
sh->len = (int)len;
sh->free = (int)(totlen-sh->len);
return s;
}
sdscatlen函数
尾部追加数据
/*
s为原始字符串
t为待追加的字符串
len为待追加字符串的长度
*/
sds sdscatlen(sds s, const void *t, size_t len) {
struct sdshdr *sh;
size_t curlen = sdslen(s); //计算字符串已使用空间长度
s = sdsMakeRoomFor(s,len); //扩充空间
if (s == NULL) return NULL;
sh = (void*) (s-(sizeof(struct sdshdr)));//减去偏移量获取对应的 sdshdr 指针
memcpy(s+curlen, t, len);
sh->len = (int)(curlen+len);
sh->free = (int)(sh->free-len);
s[curlen+len] = '\0';
return s;
}
sdscat函数
拼接字符串
/*
s为原始字符串
t为待拼接的C字符串
*/
sds sdscat(sds s, const char *t) {
return sdscatlen(s, t, strlen(t));//将指定的t字符串,添加到s字符串尾部
}
sdscatsds函数
拼接字符串(两个sds字符串拼接)
sds sdscatsds(sds s, const sds t) {
return sdscatlen(s, t, sdslen(t));
}
sdscpylen函数
拷贝字符串
//拷贝t中len个字符到s中
sds sdscpylen(sds s, const char *t, size_t len) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
size_t totlen = sh->free+sh->len;//获取s字符串的总长度,包括已使用空间和分配未使用空间,但是不包括结束符‘\0’
if (totlen < len) { //如果待拷贝字符长度大于s字符串的总长度,则重新分配空间
s = sdsMakeRoomFor(s,len-sh->len);
if (s == NULL) return NULL;
sh = (void*) (s-(sizeof(struct sdshdr)));
totlen = sh->free+sh->len;
}
memcpy(s, t, len);
s[len] = '\0';
sh->len = (int)len;
sh->free = (int)(totlen-len);
return s;
}
sdscpy函数
拷贝字符串
//拷贝t字符串到s中
sds sdscpy(sds s, const char *t) {
return sdscpylen(s, t, strlen(t));
}