2025年Redis 设计与实现 3:字符串 SDS

Redis 设计与实现 3:字符串 SDS在 Redis 中 字符串都用自定义的结构简单动态字符串 Simple Dynamic Strings SDS Redis 中使用到的字符串都是用 SDS 例如 key string 类型的值 sorted set 的 member hash 的 field 等等等等 数据结构 旧版本的结构 在 3 2 版本之前 sds 的定义是这样的 struct sdshdr

大家好,我是讯享网,很高兴认识大家。

数据结构
旧版本的结构
在 3.2 版本之前,sds 的定义是这样的:

struct sdshdr {
// buf 数组中已使用的字节数量,也就是 sds 本身的字符串长度
unsigned int len;
// buf 数组中未使用的字节数量
unsigned int free;
// 字节数组,用于保存字符串
char buf[];
};
旧版本 SDS 结构示例

这样的结构有几个好处:

单独记录长度len,获取字符串长度的时间复杂度是 O(1) 。传统的 C 字符串获取长度需要遍历字符串,直到遇到\0,时间复杂度是 O(N)。
buf 数组末尾遵循 C 字符串以 \0 结尾的惯例,可以兼容 C 处理字符串的函数。
减少修改字符串带来的内存重分配次数,Redis 使用了 空间预分配(预先申请大一点点的空间) 和 空间惰性释放(字符串变短修改len字段即可)来减少字符串修改引起的内存重新分配。
不以\0为结尾的判断,二进制安全。因为图片等二进制数据中,可能包含\0,传统 C 字符串一遇到 \0 就认为字符串结束了,会导致不能完整保存。
缺点:

len 和 free 的定义用了 4 个字节,可以表示 2^32 的长度。但是我们实际使用的字符串,往往没有那么长。4 个字节造成了浪费。
新版本的结构
旧版本中我们说到,len 和 free 的缺点是用了太长的变量,新版本解决了这个问题。
我们来看一下新版本的 SDS 结构。

在 Redis 3.2 版本之后,Redis 将 SDS 划分为 5 种类型:


讯享网

类型 字节 位
sdshdr5 < 1 <8
sdshdr8 1 8
sdshdr16 2 16
sdshdr32 4 32
sdshdr64 8 64
新版本新增加了一个 flags 字段来标识类型,长度 1 字节(8 位)。
类型只占用了前 3 位。在 sdshdr5 中,后 5 位用来保存字符串的长度。其他类型后 5 位没有用。

struct attribute ((packed)) sdshdr5 {
unsigned char flags; /* 前 3 位保存类型,后 5 位保存字符串长度 /
char buf[];
};
struct attribute ((packed)) sdshdr8 {
uint8_t len; /
字符串长度,1 字节 8 位 /
uint8_t alloc; /
申请的总长度,1 字节 8 位 /
unsigned char flags; /
前 3 位保存类型,后 5 位未使用 /
char buf[];
};
struct attribute ((packed)) sdshdr16 {
uint16_t len; /
字符串长度,2 字节 16 位 /
uint16_t alloc; /
申请的总长度,2 字节 16 位 /
unsigned char flags; /
前 3 位保存类型,后 5 位未使用 /
char buf[];
};
struct attribute ((packed)) sdshdr32 {
uint32_t len; /
字符串长度,4 字节 32 位 /
uint32_t alloc; /
申请的总长度,4 字节 32 位 /
unsigned char flags; /
前 3 位保存类型,后 5 位未使用 /
char buf[];
};
struct attribute ((packed)) sdshdr64 {
uint64_t len; /
字符串长度,8 字节 64 位 /
uint64_t alloc; /
申请的总长度,8 字节 64 位 /
unsigned char flags; /
前 3 位保存类型,后 5 位未使用 */
char buf[];
};
旧版本 SDS 结构示例

优点:

旧版本相对于传统 C 字符串的优点,新版本都有
相对于旧版本,新版本可以通过字符串的长度,选择不同的结构,可以节约内存
使用 attribute ((packed)) ,让编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,可以节约内存
SDS 的初始化
sds 的定义,跟传统的C语言字符串保持类型兼容 char *。但是 sds 是二进制安全的,中间可能包含\0。

sds.h

// 初始化 sds
sds sdsnewlen(const void *init, size_t initlen) {
// 指向 sdshdr 开始地方的指针
void *sh;
// sds 实际是一个指针,指向 buf 开始的位置
sds s;
// 根据初始化的长度,返回 sds 的类型
char type = sdsReqType(initlen);
// initlen == 0,是空字符串,空字符串往往就是用来往后添加字节的,使用 SDS_TYPE_8 比 SDS_TYPE_5 更好
if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
// 根据类型获取 struct sdshdr 的长度
int hdrlen = sdsHdrSize(type);
// flags 字段的指针
unsigned char fp;
https://github.com/a9r036f3/kptbymhxiy/discussions/781
https://github.com/fdxr69x2/lfwjghixlp/discussions/785
https://github.com/a9r036f3/kptbymhxiy/discussions/782
https://github.com/fdxr69x2/lfwjghixlp/discussions/786
https://github.com/a9r036f3/kptbymhxiy/discussions/783
https://github.com/fdxr69x2/lfwjghixlp/discussions/787
https://github.com/a9r036f3/kptbymhxiy/discussions/784
https://github.com/fdxr69x2/lfwjghixlp/discussions/788
https://github.com/a9r036f3/kptbymhxiy/discussions/785
https://github.com/fdxr69x2/lfwjghixlp/discussions/789
https://github.com/a9r036f3/kptbymhxiy/discussions/786
https://github.com/fdxr69x2/lfwjghixlp/discussions/790
https://github.com/a9r036f3/kptbymhxiy/discussions/787
https://github.com/fdxr69x2/lfwjghixlp/discussions/791
https://github.com/a9r036f3/kptbymhxiy/discussions/788
https://github.com/fdxr69x2/lfwjghixlp/discussions/792
https://github.com/a9r036f3/kptbymhxiy/discussions/789
https://github.com/fdxr69x2/lfwjghixlp/discussions/793
https://github.com/a9r036f3/kptbymhxiy/discussions/790
https://github.com/a9r036f3/kptbymhxiy/discussions/791
https://github.com/fdxr69x2/lfwjghixlp/discussions/794
https://github.com/a9r036f3/kptbymhxiy/discussions/792
https://github.com/fdxr69x2/lfwjghixlp/discussions/795
https://github.com/a9r036f3/kptbymhxiy/discussions/793
https://github.com/fdxr69x2/lfwjghixlp/discussions/796
https://github.com/91sipp68/jgvawurmpd/discussions/303
https://github.com/l32nyw20/pmtfvfmhdz/discussions/294
https://github.com/l32nyw20/pmtfvfmhdz/discussions/295
https://github.com/91sipp68/jgvawurmpd/discussions/304
https://github.com/91sipp68/jgvawurmpd/discussions/305
https://github.com/l32nyw20/pmtfvfmhdz/discussions/296
https://github.com/l32nyw20/pmtfvfmhdz/discussions/297
https://github.com/91sipp68/jgvawurmpd/discussions/306
https://github.com/91sipp68/jgvawurmpd/discussions/307
https://github.com/91sipp68/jgvawurmpd/discussions/308
https://github.com/l32nyw20/pmtfvfmhdz/discussions/298
https://github.com/91sipp68/jgvawurmpd/discussions/309
https://github.com/91sipp68/jgvawurmpd/discussions/310
https://github.com/l32nyw20/pmtfvfmhdz/discussions/299
https://github.com/l32nyw20/pmtfvfmhdz/discussions/300
https://github.com/91sipp68/jgvawurmpd/discussions/311
https://github.com/91sipp68/jgvawurmpd/discussions/312
https://github.com/l32nyw20/pmtfvfmhdz/discussions/301
https://github.com/l32nyw20/pmtfvfmhdz/discussions/302
https://github.com/91sipp68/jgvawurmpd/discussions/313
https://github.com/l32nyw20/pmtfvfmhdz/discussions/303
https://github.com/91sipp68/jgvawurmpd/discussions/314
https://github.com/l32nyw20/pmtfvfmhdz/discussions/304
https://github.com/91sipp68/jgvawurmpd/discussions/315
https://github.com/l32nyw20/pmtfvfmhdz/discussions/305
https://github.com/91sipp68/jgvawurmpd/discussions/316
https://github.com/l32nyw20/pmtfvfmhdz/discussions/306
https://github.com/91sipp68/jgvawurmpd/discussions/317
https://github.com/l32nyw20/pmtfvfmhdz/discussions/307
https://github.com/91sipp68/jgvawurmpd/discussions/318
https://github.com/l32nyw20/pmtfvfmhdz/discussions/308
https://github.com/91sipp68/jgvawurmpd/discussions/319
https://github.com/91sipp68/jgvawurmpd/discussions/320
https://github.com/l32nyw20/pmtfvfmhdz/discussions/309
https://github.com/91sipp68/jgvawurmpd/discussions/321
https://github.com/l32nyw20/pmtfvfmhdz/discussions/310
https://github.com/91sipp68/jgvawurmpd/discussions/322
https://github.com/l32nyw20/pmtfvfmhdz/discussions/311
https://github.com/91sipp68/jgvawurmpd/discussions/323
https://github.com/l32nyw20/pmtfvfmhdz/discussions/312
https://github.com/91sipp68/jgvawurmpd/discussions/324
https://github.com/l32nyw20/pmtfvfmhdz/discussions/313
https://github.com/91sipp68/jgvawurmpd/discussions/325
https://github.com/l32nyw20/pmtfvfmhdz/discussions/314
https://github.com/91sipp68/jgvawurmpd/discussions/326
https://github.com/l32nyw20/pmtfvfmhdz/discussions/315
https://github.com/91sipp68/jgvawurmpd/discussions/327
https://github.com/l32nyw20/pmtfvfmhdz/discussions/316
https://github.com/91sipp68/jgvawurmpd/discussions/328
https://github.com/l32nyw20/pmtfvfmhdz/discussions/317
https://github.com/l32nyw20/pmtfvfmhdz/discussions/318
https://github.com/91sipp68/jgvawurmpd/discussions/329
https://github.com/91sipp68/jgvawurmpd/discussions/330
https://github.com/l32nyw20/pmtfvfmhdz/discussions/319
https://github.com/l32nyw20/pmtfvfmhdz/discussions/320
https://github.com/91sipp68/jgvawurmpd/discussions/331
https://github.com/91sipp68/jgvawurmpd/discussions/332
https://github.com/l32nyw20/pmtfvfmhdz/discussions/321
https://github.com/91sipp68/jgvawurmpd/discussions/333
https://github.com/l32nyw20/pmtfvfmhdz/discussions/322
https://github.com/l32nyw20/pmtfvfmhdz/discussions/323
https://github.com/91sipp68/jgvawurmpd/discussions/334
https://github.com/91sipp68/jgvawurmpd/discussions/335
https://github.com/l32nyw20/pmtfvfmhdz/discussions/324
https://github.com/91sipp68/jgvawurmpd/discussions/336
https://github.com/l32nyw20/pmtfvfmhdz/discussions/325
https://github.com/91sipp68/jgvawurmpd/discussions/337
https://github.com/l32nyw20/pmtfvfmhdz/discussions/326
https://github.com/91sipp68/jgvawurmpd/discussions/338
https://github.com/l32nyw20/pmtfvfmhdz/discussions/327
https://github.com/91sipp68/jgvawurmpd/discussions/339
https://github.com/l32nyw20/pmtfvfmhdz/discussions/328
https://github.com/91sipp68/jgvawurmpd/discussions/340
https://github.com/91sipp68/jgvawurmpd/discussions/341
https://github.com/l32nyw20/pmtfvfmhdz/discussions/329
https://github.com/91sipp68/jgvawurmpd/discussions/342
https://github.com/l32nyw20/pmtfvfmhdz/discussions/330
https://github.com/91sipp68/jgvawurmpd/discussions/343
https://github.com/l32nyw20/pmtfvfmhdz/discussions/331
https://github.com/l32nyw20/pmtfvfmhdz/discussions/332
https://github.com

小讯
上一篇 2025-02-08 23:05
下一篇 2025-03-05 20:59

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/34852.html