zskiplist的结构如下:
typeof struct zskiplist { // 表头节点,表尾节点 struct skiplistNode *header,*tail; // 表中节点数量 unsigned long length; // 表中最大层数 int level; } zskiplist;最后我们整个跳跃表的示例图如下:
2.5整数集合(intset)整数集合是set(集合)的底层数据结构之一。当一个set(集合)只包含整数值元素,并且元素的数量不多时,Redis就会采用整数集合(intset)作为set(集合)的底层实现。
整数集合(intset)保证了元素是不会出现重复的,并且是有序的(从小到大排序),intset的结构是这样子的:
typeof struct intset { // 编码方式 unit32_t encoding; // 集合包含的元素数量 unit32_t lenght; // 保存元素的数组 int8_t contents[]; } intset;intset示例图:
说明:虽然intset结构将contents属性声明为int8_t类型的数组,但实际上contents数组并不保存任何int8_t类型的值,contents数组的真正类型取决于encoding属性的值:
INTSET_ENC_INT16
INTSET_ENC_INT32
INTSET_ENC_INT64
从编码格式的名字我们就可以知道,16,32,64编码对应能存放的数字范围是不一样的。16明显最少,64明显最大。
如果本来是INTSET_ENC_INT16的编码,想要存放大于INTSET_ENC_INT16编码能存放的整数值,此时就得编码升级(从16升级成32或者64)。步骤如下:
1)根据新元素类型拓展整数集合底层数组的空间并为新元素分配空间。
2)将底层数组现有的所以元素都转换成与新元素相同的类型,并将类型转换后的元素放到正确的位上,需要维持底层数组的有序性质不变。
3)将新元素添加到底层数组。
另外一提:只支持升级操作,并不支持降级操作。
2.6压缩列表(ziplist)压缩列表(ziplist)是list和hash的底层实现之一。如果list的每个都是小整数值,或者是比较短的字符串,压缩列表(ziplist)作为list的底层实现。
压缩列表(ziplist)是Redis为了节约内存而开发的,是由一系列的特殊编码的连续内存块组成的顺序性数据结构。
压缩列表结构图例如下:
下面我们看看节点的结构图:
压缩列表从表尾节点倒序遍历,首先指针通过zltail偏移量指向表尾节点,然后通过指向节点记录的前一个节点的长度依次向前遍历访问整个压缩列表。
三、Redis中数据结构的对象再次看回这张图,觉不觉得就很好理解了?
3.1字符串(stirng)对象在上面的图我们知道string类型有三种编码格式:
int:整数值,这个整数值可以使用long类型来表示
如果是浮点数,那就用embstr或者raw编码。具体用哪个就看这个数的长度了
embstr:字符串值,这个字符串值的长度小于39字节
raw:字符串值,这个字符串值的长度大于39字节
embstr和raw的区别:
raw分配内存和释放内存的次数是两次,embstr是一次
embstr编码的数据保存在一块连续的内存里面
编码之间的转换:
int类型如果存的不再是一个整数值,则会从int转成raw
embstr是只读的,在修改的时候回从embstr转成raw
3.2列表(list)对象在上面的图我们知道list类型有两种编码格式:
ziplist:字符串元素的长度都小于64个字节&&总数量少于512个
linkedlist:字符串元素的长度大于64个字节||总数量大于512个
ziplist编码的列表结构:
redis > RPUSH numbers 1 "three" 5 (integer) 3linkedlist编码的列表结构:
编码之间的转换:
原本是ziplist编码的,如果保存的数据长度太大或者元素数量过多,会转换成linkedlist编码的。
3.3哈希(hash)对象在上面的图我们知道hash类型有两种编码格式:
ziplist:key和value的字符串长度都小于64字节&&键值对总数量小于512
hashtable:key和value的字符串长度大于64字节||键值对总数量大于512
ziplist编码的哈希结构: