1. Redis SDS介绍
Redis中的SDS(Simple Dynamic Strings)是一种动态字符串数据结构,用于代替C语言中的传统字符串。相比传统字符串,SDS拥有更多的优点,如可以避免buffer overflow的问题、能够支持O(1)的复杂度获取字符串长度等等。在Redis的实现中,SDS被广泛地应用于Redis的字符串实现、列表的实现以及哈希表的实现等方面。因此,SDS的源码非常值得学习。
2. SDS源码分析
2.1 SDS的数据类型定义
SDS数据类型的定义位于sds.h头文件中,定义如下:
/* 每一个SDS字符串都会有一个sdshdr结构体 */
struct sdshdr {
// 记录buf数组中已使用的字节数量
// 等于SDS字符串的长度
// 该属性的类型为uint32_t
uint32_t len;
// 记录buf数组中未使用的字节数量
// 等于SDS尾部可用空间的长度
// 该属性的类型为uint32_t
uint32_t free;
// 字节数组,存储字符串
// 该属性的类型为char数组
// 通过字符串指针char *(指向buf中第一个元素)就可以访问SDS的字符串内容
char buf[];
};
2.2 SDS的API实现
2.2.1 sdscatlen函数
该函数用于将长度为len的字符串t拼接到SDS字符串s的末尾,具体代码实现如下:
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)));
memcpy(s+curlen, t, len);
sh->len = curlen+len;
sh->free = sh->free-len;
s[curlen+len] = '\0';
return s;
}
从代码中可以看出,该函数主要分为三个步骤:
- 拓展SDS的空间。如果SDS的尾部空间不足以存储新来的字符串,则需要先将SDS的空间进行拓展;
- 将长度为len的字符串t拼接到SDS字符串s的末尾。将待拼接的字符串t复制到SDS空间的尾部,使得SDS末尾存储新加入的字符串,同时更新SDS的长度和可用空间信息;
- 返回拼接后的SDS字符串s。
2.2.2 sdscat函数
函数sdscat实际是函数sdscatlen的封装,用于将一个C字符串(即以'\0'为结尾的字符串)拼接到SDS字符串s的末尾。代码实现如下:
sds sdscat(sds s, const char *t) {
return sdscatlen(s, t, strlen(t));
}
从代码中可以看出,函数sdscat内部通过调用函数sdscatlen实现字符串拼接操作。
2.2.3 sdsnew函数
函数sdsnew用于创建长度为initlen的SDS字符串,具体代码实现如下:
sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
sds s = malloc(sizeof(struct sdshdr)+initlen+1);
if (!s) return NULL;
sh = (void*) s;
sh->len = initlen;
sh->free = 0;
if (initlen && init)
memcpy(s, init, initlen);
s[initlen] = '\0';
return s;
}
sds sdsnew(const char *init) {
size_t initlen = (init == NULL) ? 0 : strlen(init);
return sdsnewlen(init, initlen);
}
sdsnewlen函数的主要功能是使用malloc函数分配一段连续的内存空间用于存储SDS,根据传入的参数更新内部的结构体指针,最后返回指向SDS字符串的指针。
sdsnew函数则是sdsnewlen函数的封装,用于创建一个包含C字符串init的SDS字符串。
2.2.4 其他API实现
除了上述三个函数以外,SDS还有大量其他的API实现,包括:
- sdslen函数:用于获取指定SDS字符串的长度信息。
- sdsfree函数:用于释放指向SDS字符串的指针。
- sdstolower函数:用于将SDS字符串中的全部小写字母转换成大写字母。
- sdstrim函数:用于删除SDS字符串开头和结尾的空格字符。等等。
2.3 SDS的源码分析总结
SDS是Redis实现中重要的数据结构之一,能够以O(1)的时间复杂度获取字符串的长度信息,并且能够避免buffer overflow等问题。通过对SDS的源码分析,不仅能够加深对动态字符串数据结构的理解,同时还能够了解Redis数据结构的内部实现流程。