redis的简单动态字符串(SDS, Simple Dynamic String)

简单动态字符串(SDS, Simple Dynamic String)

redis里面将SDS用作redis的默认字符串表示。包含字符串的键值对在底层的实现都是由SDS实现的。

arduino 复制代码
//sds.h
/* Note: sdshdr5 is never used, we just access the flags byte directly.
 * However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

定义了5种用于实现 Redis 的 SDS (Simple Dynamic String,简单动态字符串) 数据结构的结构体。 所有结构体都使用了 __attribute__ ((__packed__)),这意味着结构体成员会紧密排列,不进行内存对齐填充,以适应高效的内存管理需求。

内存设计

  • __attribute__ 是关键字,表示这是一个编译器属性, 是 GCC(GNU Compiler Collection) 提供的一个 编译器指令(Compiler Directive) ,用于向编译器传递额外的信息,控制变量、函数、结构体等的编译行为。
  • 括号 ((...)) 内部是具体的属性名称和参数(如 packedalignednoreturn 等)
  • packed__attribute__ 的一个具体属性,用于 取消结构体(struct)或联合体(union)的内存对齐优化 ,使其成员在内存中 紧密排列(packed) ,不插入任何填充字节(padding)

结构体类型

共有 5 种结构体,分别用于不同长度的字符串:

  • sdshdr5:未实际使用,仅用于文档说明
  • sdshdr8:用于短字符串(长度 ≤ 2^8-1)
  • sdshdr16:用于中等长度字符串(长度 ≤ 2^16-1)
  • sdshdr32:用于长字符串(长度 ≤ 2^32-1)
  • sdshdr64:用于超长字符串(长度 ≤ 2^64-1)
arduino 复制代码
//sds.h
#define SDS_TYPE_5  0
#define SDS_TYPE_8  1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3

宏定义

scss 复制代码
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(s) (((unsigned char)(s[-1])) >> SDS_TYPE_BITS)

#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));: 用于声明并初始化一个指向 SDS 头结构的指针变量 shT 是 SDS 类型(如 8, 16, 32, 64), s 是指向字符串数据的指针, ## 是连接符,将 sdshdrT 连接起来形成结构体名(如 sdshdr8), 计算方式:用字符串指针 s 减去头结构的大小,得到头结构的起始地址,结果:声明了一个 sh 变量,指向 SDS 的头结构

#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))): 与第一个类似,但不声明变量,直接返回头结构指针,同样通过字符串指针 s 减去头结构大小来计算头结构地址,结果:返回一个指向 SDS 头结构的指针

#define SDS_TYPE_5_LEN(s) (((unsigned char)(s[-1])) >> SDS_TYPE_BITS): 专门用于 SDS 类型5(特殊的小字符串优化类型), 它从字符串前一个字节(s[-1])中提取长度信息,SDS_TYPE_BITS 是类型占用的位数(对于类型5是3), 右移操作 >> SDS_TYPE_BITS 是为了去掉低3位的类型信息,只保留长度部分,结果:返回类型5 SDS 字符串的长度

结构体成员

对于实际使用的 sdshdr8sdshdr64,它们包含相同的成员,只是数据类型不同:

  • len:当前字符串的实际长度(已使用的字节数)
  • alloc:分配的总内存大小(不包括头部和空终止符)
  • flags:标志字节
    • 低 3 位表示 SDS 类型(0-4 对应 sdshdr5 到 sdshdr64)
    • 高 5 位未使用(在 sdshdr5 中用于存储长度)
  • buf:柔性数组,实际存储字符串内容(包含空终止符 '\0')

sdshdr5 的特殊性

sdshdr5 没有被实际使用,它的设计是:

  • flags 字节:
    • 低 3 位表示类型(0b000)
    • 高 5 位存储字符串长度(因此最大长度为 31)
  • 没有单独的 lenalloc 字段
相关推荐
用户46653701505几秒前
git代码压缩合并
后端·github
武大打工仔4 分钟前
从零开始手搓一个MVC框架
后端
开心猴爷10 分钟前
移动端网页调试实战 Cookie 丢失问题的排查与优化
后端
用户57240561410 分钟前
解析Json
后端
舒一笑11 分钟前
Mac 上安装并使用 frpc(FRP 内网穿透客户端)指南
后端·网络协议·程序员
每天学习一丢丢17 分钟前
Spring Boot + Vue 项目用宝塔面板部署指南
vue.js·spring boot·后端
邹小邹17 分钟前
Go 1.25 强势来袭:GC 速度飙升、并发测试神器上线,内存检测更精准!
后端·go
lichenyang45321 分钟前
管理项目服务器连接数据库
数据库·后端
生无谓22 分钟前
在Windows系统上安装多个JDK版本并切换
后端
唐叔在学习31 分钟前
万字长文深度解析HTTPS协议
后端·https