近来在研读redis3.2.9的源码,虽然网上已有许多redis的源码解读文章,但大都不成系统,且纸上学来终觉浅,遂有该系列博文。部分知识点参照了黄建宏的《Redis设计与实现》。
前言
本文探究的数据结构并不是 redis 对外暴露的5种数据结构,而是redis内部使用的基础数据结构,这些基础的数据结构 redis 不仅和 redisObj 一起构成了对外暴露的5种数据结构,还被运用于 redis 内部的各种存储和逻辑交互,支撑起了 redis 的运行。
redis 的基础数据结构主要有以下7种:
- SDS(simple dynamic string):简单动态字符串
- ADList(A generic doubly linked list):双向链表
- dict(Hash Tables):字典
- intset:整数集合
- ziplist:压缩表
- quicklist:快速列表(双向链表和压缩表二合一的复杂数据结构)
- skiplist:跳跃链表
intset
整数集合是 redis 对外数据结构set
的底层实现之一,当集合元素不大于设定值并且元素都是整数时,就会用intset
作为set
的底层数据结构。
定义
inset
结构体定义如下:
typedef struct intset {
uint32_t encoding; // 编码方式,一个元素所需要的内存大小
uint32_t length; // 集合长度
int8_t contents[]; // 集合数组
} intset;
encoding
为inset
的编码方式,有3种编码方式,分别对应不同范围的整型:#define INTSET_ENC_INT16 (sizeof(int16_t)) // -32768~32767 #define INTSET_ENC_INT32 (sizeof(int32_t)) // -2147483648~2147483647 #define INTSET_ENC_INT64 (sizeof(int64_t)) // -2^63~2^63-1
intset
的编码是由最大的一个数决定的,如果有一个数是int64,那么整个inset
的编码都是int64。length
是inset
的整数个数contents
整数数组
intset
的内存是连续的,所有的数据增删改查操作都是在内存地址偏移的基础上进行的,并且整数的保存也是有序的,一个保存了5个int16的intset
的内存示意图如下:
由于intset
是在内存上直接操作赋值,并且所存储的值都超过了一个字节,所以需要考虑大小端的问题:
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位