Redis设计与实现——数据结构(四)
来源:互联网 发布:数据分析报告的结尾 编辑:程序博客网 时间:2024/06/13 03:49
整数集合
简介
整数集合(intset)是集合键的底层实现之一: 当一个集合只包含整数值元素, 并且这个集合的元素数量不多时, Redis 就会使用整数集合作为集合键的底层实现。
实现
每个 intset.h/intset 结构表示一个整数集合:
typedef struct intset { // 编码方式 uint32_t encoding; // 集合包含的元素数量 uint32_t length; // 保存元素的数组 int8_t contents[];} intset;
虽然 intset 结构将 contents 属性声明为 int8_t 类型的数组, 但实际上 contents 数组并不保存任何 int8_t 类型的值 —— contents 数组的真正类型取决于 encoding 属性的值:
- 如果 encoding 属性的值为 INTSET_ENC_INT16 , 那么 contents 就是一个 int16_t 类型的数组, 数组里的每个项都是一个 int16_t 类型的整数值 (最小值为 -32,768 ,最大值为 32,767 )。
- 如果 encoding 属性的值为 INTSET_ENC_INT32 , 那么 contents 就是一个 int32_t 类型的数组, 数组里的每个项都是一个 int32_t 类型的整数值 (最小值为 -2,147,483,648 ,最大值为 2,147,483,647 )。
- 如果 encoding 属性的值为 INTSET_ENC_INT64 , 那么 contents 就是一个 int64_t 类型的数组, 数组里的每个项都是一个 int64_t 类型的整数值 (最小值为 -9,223,372,036,854,775,808 ,最大值为 9,223,372,036,854,775,807 )。
升级
每当我们要将一个新元素添加到整数集合里面, 并且新元素的类型比整数集合现有所有元素的类型都要长时, 整数集合需要先进行升级, 然后才能将新元素添加到整数集合里面。
升级整数集合并添加新元素共分为三步进行:
- 根据新元素的类型, 扩展整数集合底层数组的空间大小, 并为新元素分配空间。
- 将底层数组现有的所有元素都转换成与新元素相同的类型, 并将类型转换后的元素放置到正确的位上, 而且在放置元素的过程中, 需要继续维持底层数组的有序性质不变。
- 将新元素添加到底层数组里面。
整数集合不支持降级操作
压缩列表
简介
压缩列表是 Redis 为了节约内存而开发的, 由一系列特殊编码的连续内存块组成的顺序型数据结构。
一个压缩列表可以包含任意多个节点(entry), 每个节点可以保存一个字节数组或者一个整数值。
压缩列表节点
每个压缩列表节点可以保存一个字节数组或者一个整数值, 其中, 字节数组可以是以下三种长度的其中一种:
- 长度小于等于 63 (2^{6}-1)字节的字节数组;
- 长度小于等于 16383 (2^{14}-1) 字节的字节数组;
- 长度小于等于 4294967295 (2^{32}-1)字节的字节数组;
而整数值则可以是以下六种长度的其中一种:
- 4 位长,介于 0 至 12 之间的无符号整数;
- 1 字节长的有符号整数;
- 3 字节长的有符号整数;
- int16_t 类型整数;
- int32_t 类型整数;
- int64_t 类型整数。
每个压缩列表节点都由 previous_entry_length 、 encoding 、 content 三个部分组成
previous_entry_length
节点的 previous_entry_length 属性以字节为单位, 记录了压缩列表中前一个节点的长度。
previous_entry_length 属性的长度可以是 1 字节或者 5 字节:
- 如果前一节点的长度小于 254 字节, 那么 previous_entry_length 属性的长度为 1 字节: 前一节点的长度就保存在这一个字节里面。
- 如果前一节点的长度大于等于 254 字节, 那么 previous_entry_length 属性的长度为 5 字节: 其中属性的第一字节会被设置为 0xFE (十进制值 254), 而之后的四个字节则用于保存前一节点的长度。
encoding
节点的 encoding 属性记录了节点的 content 属性所保存数据的类型以及长度:
- 一字节、两字节或者五字节长, 值的最高位为 00 、 01 或者 10 的是字节数组编码: 这种编码表示节点的 content 属性保存着字节数组, 数组的长度由编码除去最高两位之后的其他位记录;
- 一字节长, 值的最高位以 11 开头的是整数编码: 这种编码表示节点的 content 属性保存着整数值, 整数值的类型和长度由编码除去最高两位之后的其他位记录;
content
节点的 content 属性负责保存节点的值, 节点值可以是一个字节数组或者整数, 值的类型和长度由节点的 encoding 属性决定。
连锁更新
由于每个节点的 previous_entry_length 属性长度可能为1字节或5字节,现在, 考虑这样一种情况: 在一个压缩列表中, 有多个连续的、长度介于 250 字节到 253 字节之间的节点 e1 至 eN
因为 e1 至 eN 的所有节点的长度都小于 254 字节, 所以记录这些节点的长度只需要 1 字节长的 previous_entry_length 属性。
这时, 如果我们将一个长度大于等于 254 字节的新节点 new 设置为压缩列表的表头节点:
因为 e1 的 previous_entry_length 属性仅长 1 字节, 它没办法保存新节点 new 的长度, 所以程序将对压缩列表执行空间重分配操作。后面的元素依次都要进行分配操作。
要注意的是, 尽管连锁更新的复杂度较高, 但它真正造成性能问题的几率是很低的:
- 首先, 压缩列表里要恰好有多个连续的、长度介于 250 字节至 253 字节之间的节点, 连锁更新才有可能被引发, 在实际中, 这种情况并不多见;
- 其次, 即使出现连锁更新, 但只要被更新的节点数量不多, 就不会对性能造成任何影响: 比如说, 对三五个节点进行连锁更新是绝对不会影响性能的;
参考资料
- 《Redis 设计与实现》
- Redis设计与实现——数据结构(四)
- Redis设计与实现——数据结构(一)
- Redis设计与实现——数据结构(二)
- Redis设计与实现——数据结构(三)
- Redis设计与实现——数据结构(五)
- Redis设计与实现——数据结构与对象
- redis设计与实现(四)字典
- Redis设计与实现 --- 数据结构
- redis数据结构存储SDS设计细节(redis的设计与实现笔记)
- AOF — Redis 设计与实现
- Redis 数据结构与实现
- 《Redis设计与实现》[第一部分]数据结构与对象-C源码阅读(一)
- 《Redis设计与实现》[第一部分]数据结构与对象-C源码阅读(二)
- 《Redis设计与实现》学习笔记-基础数据结构
- RedisTemplate访问Redis数据结构(四)——Set
- 《Redis设计与实现》[第二部分]单机数据库的实现-C源码阅读(四)
- Redis源码分析(四)——Redis数据结构-整数集合
- Redis设计与实现——单机数据库的实现
- C++读写文件
- Mybatis配置之<mappers>元素详述
- 系统架构师考试需求大纲
- Linux搭建ftp服务器
- 分段三次Hermite插值Matlab实现
- Redis设计与实现——数据结构(四)
- 噪音恐惧症,紫书P365Uva10048(floyd算法应用)
- 阿里巴巴Java开发手册(终极版)pdf下载
- 计算机网络 学习摘要(6)
- epoll系统调用
- 【Excel-2010】导入网站数据
- Material Design控件之CoordinatorLayout
- 第一章 入门
- elicpse中的source和refactor的用法简介