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 字段
相关推荐
Mr Aokey2 小时前
Spring MVC参数绑定终极手册:单&多参/对象/集合/JSON/文件上传精讲
java·后端·spring
地藏Kelvin2 小时前
Spring Ai 从Demo到搭建套壳项目(二)实现deepseek+MCP client让高德生成昆明游玩4天攻略
人工智能·spring boot·后端
菠萝013 小时前
共识算法Raft系列(1)——什么是Raft?
c++·后端·算法·区块链·共识算法
长勺3 小时前
Spring中@Primary注解的作用与使用
java·后端·spring
小奏技术4 小时前
基于 Spring AI 和 MCP:用自然语言查询 RocketMQ 消息
后端·aigc·mcp
编程轨迹4 小时前
面试官:如何在 Java 中读取和解析 JSON 文件
后端
lanfufu4 小时前
记一次诡异的线上异常赋值排查:代码没错,结果不对
java·jvm·后端
编程轨迹4 小时前
如何在 Java 中实现 PDF 与 TIFF 格式互转
后端
编程轨迹4 小时前
面试官:你知道如何在 Java 中创建对话框吗
后端
编程轨迹4 小时前
深入理解 Java 中的信号机制
后端