Redis没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串SD S(simple dynamic string)的数据结构 ,并将SDS用作Redis的默认字符串表示。
Redis内部所有字符串都由SDS来表示,其本质就是动态字节数组,和python的bytearray
类似。
SDS 实现
1 | /* |
使用SDS时,一般是通过指向buf数组的指针而不是sdshdr,这样相关接口就和C字符串兼容。同时需要使用到len和free相关属性时,通过计算指针偏移来得到sdshdr指针,整体设计比较高效。1
2
3
4static inline size_t sdslen(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
return sh->len;
}
创建新SDS
创建比较简单,注意buf末尾的\0
,以及最后返回的buf指针1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
// 根据是否有初始化内容,选择适当的内存分配方式
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 中
if (initlen && init)
memcpy(sh->buf, init, initlen);
// 以 \0 结尾
sh->buf[initlen] = '\0';
// 返回 buf 部分,而不是整个 sdshdr
return (char*)sh->buf;
}
容量调整
既然是动态数组,就会涉及到容量调整。
Redis的调整策略,当所需空间小于SDS_MAX_PREALLOC(当前版本是1MB)时是指数增长, 否则线性增长SDS_MAX_PREALLOC的大小。
1 | sds sdsMakeRoomFor(sds s, size_t addlen) { |
参考
- redis 3.0 源码
- redis 设计与实现