|
跳跃表:
- typedef struct zskiplist {
- // 表头节点和表尾节点
- struct zskiplistNode *header, *tail;
- // 表中节点的数量
- unsigned long length;
- // 表中层数最大的节点的层数
- int level;
- } zskiplist;
它有几个概念:
4.2.1 层(level[])
层,也就是level[]字段,层的数量越多,访问节点速度越快。(因为它相当于是索引,层数越多,它索引就越细,就能很快找到索引值)
4.2.2 前进指针(forward)
层中有一个forward字段,用于从表头向表尾方向访问。
4.2.3 跨度(span)
用于记录两个节点之间的距离
4.2.4 后退指针(backward)
用于从表尾向表头方向访问。
案例
- level0 1---------->5
- level1 1---->3---->5
- level2 1->2->3->4->5->6->7->8
比如我要找键为6的元素,在level0中直接定位到5,然后再往后走一个元素就找到了。
5. 整数集合(intset)
Reids对整数存储专门作了优化,intset就是redis用于保存整数值的集合数据结构。当一个结合中只包含整数元素,redis就会用这个来存储。
- 127.0.0.1:6379[2]> sadd number 1 2 3 4 5 6
- (integer) 6
- 127.0.0.1:6379[2]> object encoding number
- "intset"
源码
intset数据结构:
- typedef struct intset {
- // 编码方式
- uint32_t encoding;
- // 集合包含的元素数量
- uint32_t length;
- // 保存元素的数组
- int8_t contents[];
- } intset;
你肯定很好奇编码方式(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 )。
说白了就是根据contents字段来判断用哪个int类型更好,也就是对int存储作了优化。
说到优化,那redis如何作的呢?就涉及到了升级。
5.1 encoding升级
如果我们有个Int16类型的整数集合,现在要将65535(int32)加进这个集合,int16是存储不下的,所以就要对整数集合进行升级。
它是怎么升级的呢(过程)?
假如现在有2个int16的元素:1和2,新加入1个int32位的元素65535。
- 内存重分配,新加入后应该是3个元素,所以分配3*32-1=95位。
- 选择最大的数65535, 放到(95-32+1, 95)位这个内存段中,然后2放到(95-32-32+1+1, 95-32)位...依次类推。
升级的好处是什么呢?
- 提高了整数集合的灵活性。
- 尽可能节约内存(能用小的就不用大的)。
5.2 不支持降级
按照上面的例子,如果我把65535又删掉,encoding会不会又回到Int16呢,答案是不会的。官方没有给出理由,我觉得应该是降低性能消耗吧,毕竟调整一次是O(N)的时间复杂度。
6. 压缩列表(ziplist)
ziplist是redis为了节约内存而开发的顺序型数据结构。它被用在列表键和哈希键中。一般用于小数据存储。 (编辑:湖南网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|