redis源码分析1---结构体---简单动态字符串sds
redis的底层数据结构主要有简单动态字符串,链表,字典,跳跃表,整数集合,压缩列表,对象等组成。
这些数据结构的实现直接影响redis的表现效果,所以第一部分我先打算从这几个角度来对redis的底层数据结构
从源码上进行分析,具体的实现等。
1 SDS定义
redis大量的数据表现都是以字符串的形式。redis中使用了自己定义的字符串结构,我们先从整体上理解这一部分是怎么样实现的。
首先sds的声明如下

SDS中声明了长度,剩余空间,异界用于保存字符串的数组;
举例说明


那么打印字符串的内存,就直接使用这样的语句 printf("%s",s->buf)。
2 SDS和C字符串的区别
既然在结构体SDS增加了两个属性,那么区别就很明显了
区别1)常数复杂度获取字符串长度
区别2)杜绝缓冲区溢出
SDS在在数据处理之前会先检查空间是否足够,不够再分配;
区别3)减少修改字符串时带来的内存重新分配
这个点我们一般都不打能做好,涉及到内存的分配就容易出现这样的问题,为什么会遇到这样的问题?
因为:

那么redis是如何解决的呢?
①空间预分配
当对SDS进行修改的时候,分配方式如下:

②惰性空间释放
顾名思义,就是晚一点释放;具体的做法是当SDS的API需要缩短SDS保存的字符串时
,程序不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些自己的数量记录下来
并等到将来使用;
区别4)二进制安全
就是能够保存除了文本以外的数据,比如图片,音频,视频等。
总的来说

3 主要的API
4 源代码分析
4.1 结构体定义
typedef char *sds;
根据这个定义,那么如何得到保存字符串的长度和可用空间的长度呢?
4.2 初始化
/* * 根据给定的初始化字符串 init 和字符串长度 initlen * 创建一个新的 sds * * 参数 * init :初始化字符串指针 * initlen :初始化字符串的长度 * * 返回值 * sds :创建成功返回 sdshdr 相对应的 sds * 创建失败返回 NULL * * 复杂度 * T = O(N) */ sds sdsnewlen(const void *init, size_t initlen) { struct sdshdr *sh; // 根据是否有初始化内容,选择适当的内存分配方式 // T = O(N) if (init) { // zmalloc 不初始化所分配的内存 sh = zmalloc(sizeof(struct sdshdr)+initlen+1); } else { // zcalloc 将分配的内存全部初始化为 0 sh = zcalloc(sizeof(struct sdshdr)+initlen+1); } // 内存分配失败,返回 if (sh == NULL) return NULL; // 设置初始化长度 sh->len = initlen; // 新 sds 不预留任何空间 sh->free = 0; // 如果有指定初始化内容,将它们复制到 sdshdr 的 buf 中 // T = O(N) if (initlen && init) memcpy(sh->buf, init, initlen); // 以 结尾 sh->buf[initlen] = '