第8章 对象
从redisObject的type、encoding、ptr、refcount和lru连接五类对象与多种底层编码 覆盖11个正式节点,并以Redis 3.0源码、故障和恢复对账验收。
学习目标
- 能说明 redisObject 的类型与编码字段
- 能解释编码随数据规模切换的规则
- 能说明引用计数与对象共享的作用
为什么从“对象类型—编码切换台”开始
第8章 对象的核心任务是从redisObject的type、encoding、ptr、refcount和lru连接五类对象与多种底层编码。命令返回值只暴露外层合同;实现解释还必须连接内存结构、写入与读取路径、事件顺序以及失败后的旧状态回收。对象类型—编码切换台把这些关系放进同一条可复位轨迹。
先写预测:当对象类型由“聚合对象”进入“有序集合”时,哪个可观察状态最先变化?再规定什么结果会推翻当前解释。交互中的分数只表达透明因果方向,不冒充真实Redis测量。
来源、版次与独立重写边界
黄健宏作者读者服务页确认正式出版新版以Redis 3.0为源码基线,列出4部分、24章及完整小节,并链接Redis 3.0中文注释源码。本课程据此映射24个正式单元、145个目录节点,另设学习地图和总复习;未取得出版正文授权,目录只界定范围,不宣称复现原书正文。
本章字段与控制流由Redis官方3.0源码:object.c和作者注释源码交叉核对;Redis当前持久化文档只用于辨认版本差异。中文解释、图示、交互、实验与答案均为独立教学重写,不把目录页或代码仓库许可证误报为原书许可证。
本章术语与源码合同
第8章 对象必须守住“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”。观察同时记录对象类型—编码切换台一致率与数据形态分叉风险;只有结构快照、函数入口、运行结果和故障反例互相一致,才接受实现结论。
- 1.对象系统:redisObject = type + encoding + refcount + ptr。编码随数据规模自动切换,命令按 type 检查合法性。
作者目录逐项深读
对象的类型与编码
四级证据 1/11。 redisObject的type声明用户语义,encoding说明ptr指向的底层表示;同一类型可因数据形态切换编码。本节点用“对象的类型与编码”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证对象的类型与编码时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
字符串对象
四级证据 2/11。 字符串可用整数或SDS表示,数值命令与字符串命令会按语义选择转换,但用户值保持一致。本节点用“字符串对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证字符串对象时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
列表对象
四级证据 3/11。 Redis 3.0列表对象在满足元素数与长度阈值时使用ziplist,否则使用linkedlist。本节点用“列表对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证列表对象时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
哈希对象
四级证据 4/11。 小而短的字段值可压缩在ziplist中,越过阈值后转换为hashtable以获得更稳定的查改成本。本节点用“哈希对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证哈希对象时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
集合对象
四级证据 5/11。 全为可表示整数的小集合可用intset,否则用hashtable;插入不兼容成员会触发转换。本节点用“集合对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证集合对象时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
有序集合对象
四级证据 6/11。 全为可表示整数的小集合可用intset,否则用hashtable;插入不兼容成员会触发转换。本节点用“有序集合对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证有序集合对象时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
类型检查与命令多态
四级证据 7/11。 命令先检查对象type,再根据encoding选择实现;错误类型不能落入不匹配的底层读取路径。本节点用“对象的类型与编码”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证类型检查与命令多态时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
内存回收
四级证据 8/11。 refcount降到零才按类型释放ptr;容器、共享对象与客户端引用都必须计入所有权。本节点用“字符串对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证内存回收时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
对象共享
四级证据 9/11。 共享对象通过增加引用计数复用常见值,但比较共享收益时也要考虑查找与引用维护成本。本节点用“列表对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证对象共享时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
对象的空转时长
四级证据 10/11。 lru字段记录近似访问时间,OBJECT IDLETIME由当前时钟与该字段计算,适合近似淘汰信息而非精确审计。本节点用“哈希对象”作观察点,执行rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c或等价源码探针,保存版本、输入、前后状态和能推翻解释的反例。
验证对象的空转时长时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
重点回顾
四级证据 11/11。 第8章 对象的回顾要重新证明“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,并用同一输入比较结构前态、变更轨迹、故障首错与恢复后态
验证重点回顾时,先预测对象类型从“聚合对象”切到“有序集合”会改变哪个字段、偏移、文件或消息;再固定数据形态做一次对照。若故障注入没有破坏“对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确”,就撤回当前解释而不是补写故事。
最小源码与运行切片
+git clone --branch 3.0 --depth 1 https://github.com/redis/redis.git redis-3.0
+cd redis-3.0
+rg 'create.*Object|tryObjectEncoding|decrRefCount' src/object.c该切片固定Redis 3.0分支、编译器、配置、数据集和命令序列;先保存结构或函数位置,再运行隔离实例。任何持久化损坏、断线、故障转移、大键或高流量实验都必须使用临时数据并规定CPU、内存、磁盘、延迟和停止上限。
unit: rdi-08-object
source_file: object.c
axis_a: "对象类型"
axis_b: "数据形态"
fault: "把TYPE当底层编码,或编码转换后改变了用户可见值与引用计数"
invariant: "对象类型决定命令集合,编码与ptr结构匹配,转换不改变用户值,引用计数和空转时间正确"
replay: same_version_same_input三个必须主动触发的误区
误区 1
现象 → 对键做跨类型操作 原因 → WRONGTYPE 报错中断流程 修法 → 先 TYPE 确认或用探测命令
误区 2
现象 → 小改大 value 对象 原因 → 整值读写放大成本 修法 → 用哈希字段或位操作局部更新
误区 3
现象 → 忽视共享整数对象 原因 → 误以为每次独立分配 修法 → 理解小整数全局共享机制
小结
- 对象系统统一类型与编码
- redisObject 记录类型编码与计数
- 编码随数据规模自动切换
- 共享对象节省重复值内存
- 类型检查命令保障操作合法
练习、答案与节点验证
练习
问题 1: redisObject 的 encoding 字段为什么必要?
问题 2: OBJECT ENCODING 返回 ziplist 的哈希键,何时会变 hashtable?
问题 3: 为一个用户资料哈希选择编码并验证转换时机。(独立实现)
术语复核与本章回顾
完成第8章 对象意味着能从object.c解释从redisObject的type、encoding、ptr、refcount和lru连接五类对象与多种底层编码,能运行章专属状态实验,能制造反例并在复位后证明旧状态没有残留。