Redis源码阅读笔记(一) sds动态字符串

  • 初看源码做一个记录,打算按照如何阅读redis源码这里的结构慢慢看下去。有兴趣的初学者也可以先看看这篇文章。
- sds简介

sds是redis中最基础的也是最简单的一个数据类型,字符串数据类型。该数据类型的所有函数API都以C字符指针操作为基础,但是由于封装了长度和剩余可用长度,使得和单纯的char*相比,具有以下几点好处:

1.对于频繁的获取字符串长度操作,可以在O(1)时间内完成

2.可以类比STL中vector的实现,对于一个sds结构有实际字符串长度,还有一个free是未使用空间的长度,但对字符串进行修改时,例如追加字符串时,只要追加的长度不大于free值那么就可以直接增加无需重新分配内存,当追加长度大于free时,那么就会根据已有的分配机制去进行一个内存的重新分配。总而言之,减少了大大减少了重新分配的次数。

3.因为显示存储了len,所以是二进制安全的。

- sds实现细节 ``` /*这里之所以使用char* 的别名sds,我认识是为了区分单纯的char*和sdshdr, *当函数api的参数为char*时就代表是一个单纯的char*,当函数参数使用sds类型时, *就说明该指针之前的地址内存有len和free两个值可以使用*/ typedef char *sds; struct sdshdr { unsigned int len; unsigned int free; char buf[]; };

static inline size_t sdslen(const sds s) {
struct sdshdr sh = (void)(s-(sizeof(struct sdshdr)));
return sh->len;
}

static inline size_t sdsavail(const sds s) {
struct sdshdr sh = (void)(s-(sizeof(struct sdshdr)));
return sh->free;
}


<h6> - sds常用api

/用void指针和一个长度来初始化一个sds字符串,如果该指针里面有一个
*字符串就用该字符串初始化,否则就用0来初始化,第一次初始化的时候不
预留空间。同时因为制定了长度,所以即使中间有\0也不影响/
sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;

if (init) {
    sh = zmalloc(sizeof(struct sdshdr)+initlen+1);   //不初始化内存
} else {
    sh = zcalloc(sizeof(struct sdshdr)+initlen+1); //初始化内存为0
}
if (sh == NULL) return NULL;
sh->len = initlen;
sh->free = 0;
if (initlen && init)
    memcpy(sh->buf, init, initlen);
sh->buf[initlen] = '\0';
return (char*)sh->buf;    //返回buf开始的指针   sds是char*别名

}
//创建一个空字符串
sds sdsempty(void) {
return sdsnewlen("",0);
}
//用一个char*创建一个sds
sds sdsnew(const char *init) {
size_t initlen = (init == NULL) ? 0 : strlen(init);
return sdsnewlen(init, initlen);
}
//复制拷贝操作
sds sdsdup(const sds s) {
return sdsnewlen(s, sdslen(s));
}
//释放一个sds
void sdsfree(sds s) {
if (s == NULL) return;
zfree(s-sizeof(struct sdshdr)); //为了从头开始释放,释放掉len和free两个int值
}
//不释放内存情况下清空字符串
void sdsclear(sds s) {
struct sdshdr sh = (void) (s-(sizeof(struct sdshdr))); //每次这一步都是为了将一个字符串指针转换为一个结构体指针,为了取出头部数据(len和free进行更改)
sh->free += sh->len;
sh->len = 0;
sh->buf[0] = ‘\0’;
}

后续还有很多操作函数都比较简单,就不一一介绍,下面给出sds的内存分配机制实现。
<h6> - sds内存扩展

/*类似于vector容器中增加可用容量操作,如果增加的值本身就比原先可用容量小,
那么直接返回即可,如果增加值大于free,则将free+addlen之和直接翻倍返回。
若翻倍之前时若超过最大可用容量,就不翻倍,只加固定的一部分。/
#define SDS_MAX_PREALLOC (1024
1024)
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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值