redis数据结构和对象二
- 跳跃表(skiplist)
跳跃表是一种有序数据结构。跳跃表支持平均O(logN),最坏O(N)复杂度的节点查找,大部分情况下,跳跃表的效率可以和平衡树相媲美,并且因为跳跃表的实现比平衡树简单,所有不少程序都用跳跃表代替平衡树。Redis使用跳跃表作为有序集合的底层实现,另一个是在集群节点中用作内部数据结构。
1.1 跳跃表的实现

typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;
- header:指向跳跃表的表头节点。
- tail:指向跳跃表的表尾节点。
- level:记录目前跳跃表内,层数最大的那个节点的层数(表头节点的层数不计算在内)
- lenght:记录跳跃表的长度,即跳跃表目前包含节点的数量(表头节点的层数不计算在内)
typedef struct zskiplistNode {
robj *obj;
double score;
struct zskiplistNode *backward;
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned int span;
} level[];
} zskiplistNode;
- 层(level):节点中用L1, L2, L3等字样标记节点的各个层,L1代表第一层,L2代表第二层,依次类推。每个层都带有两个属性:前进指针和跨度。
- 前进(level[i].forward)属性:用于从表头向表尾方向的访问节点。遍历跳跃表中所有节点的路径。
- 跨度(level[i].span)属性:用于记录两个节点之间的距离。两个节点直接的跨度越大,他们相距的就越远。指向NULL的所有指针的跨度都为0,因为他们没有连向任何节点。
- 后退(backward)指针:节点中用BW字样标记节点的后退指针,他指向位于当前节点的前一个节点。后退指针在程序从表尾向表头遍历使用。
- 分值(score):各个节点中的1.0,2.0和3.0是节点所保存的分值。在跳跃表中节点按各自所保存的分值从小到大排列。
- 成员对象(obj): 各个节点中o1、o2、o3是节点所保存的成员对象。
- 整数集合(intset)
整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合元素数量不多时,Redis就会使用整数集合作为集合键的底层实现。
typedef struct intset {
uint32_t encoding;
uint32_t length;
int8_t contents[];
} intset;
- contents数组时整数集合的底层实现:各个元素在数组中按值大小从小到大有序地排列,并且数组中不包含任何重复项。
- length属性记录了整数集合包含的元素数量,即contents数组数组的长度。
虽然intset结构将contents属性声明为int8_t类型的数组,但实际上contents数组并不保存任何int8_t类型的值,contents数组的真正类型取决于encoding属性值。 - 如果encoding属性的值为INTSET_ENC_INT16,那么contents就是一个int16_t类型的数组。数组长度sizeof(int16_t)*length
- 如果encoding属性的值为INTSET_ENC_INT32,那么contents就是一个int32_t类型的数组。数组长度sizeof(int32_t)*length
- 如果encoding属性的值为INTSET_ENC_INT64,那么contents就是一个int64_t类型的数组。数组长度sizeof(int64_t)*length

整数集合升级,不支持降级。
每当将一个元素添加到整数集合里面,并且新元素的类型比整数集合现有所有元素的类型都要长时,整数集合需要先进行升级,然后才能添加到整数集合里面。升级分三步进行:
1)根据新元素的类型,扩展整数集合底层数组的空间大小,并为新元素分配空间。
2)将底层数组现有的所有元素都转换成与新元素相同的元素类型,并将类型转换后的元素放置到正确的位置。
3)将新元素添加到底层数组里面。
升级的好处
1)提升灵活性。因为语言时静态类型语言,不能将两种不同类型的值放在同一个数据结构里面。因为整数集合可以自动升级底层数组来适应新元素。
2)节约内存。 要让一个数组同时可以保存int16_t,int32_t, int64_t三种类型通常做法直接使用int64_t类型作为数组,这样出现浪费内存。
升级例子:将一个类型int32_t的数值65535添加到int16_t类型集合里面:



- 压缩列表(ziplist)
压缩列表时列表键和哈希键的底层实现只一,当一个列表只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表。
3.1 压缩列表的构成
压缩列表时Redis为了节约内存而开发,是由一系列特殊编码的连续内存块组成的顺序型的数据结构。一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值。

3.1 压缩列表节点的构成
每个压缩列表节点可以保存一个字节数组或者一个整数值。其中,字节数组可以是以下三种长度中的一种:
长度小于等于63(2^6-1)字节的字节数组;
长度小于等于16383(2^14-1)字节的字节数组
长度小于等于4294967295(2^32-1)字节的字节数组
整数值可以是以下6种长度中的一种:
4位长,介于0至12之间的无符号整数
1字节长的有符号整数
3字节长的有符号整数
int16_t类型整数
int32_t类型整数
int64_t类型整数

节点的 previous_entry_length属性以字节为单位,记录了压缩列表中前一个节点的长度。
如果前一节点的长度小于254字节,那么 previous_entry_length属性的长度为1字节,
如果前一节点的长度大于等于254字节,那么 previous_entry_length属性的长度为5字节:其中属性的第一字节会被设置为0xFE(十进制值254),而之后的四个字节则用于保存前一节点的长度。
节点的encoding属性记录了节点的content属性所保存数据的类型以及长度。
一字节、两字节或者五字节长,值的最高位为00、01或者10的是字节数组编码:这种编码表示节点的 content属性保存着字节数组,数组的长度由编码除去最高两位之后的其他位记录。
一字节长,值的最高位以11开头的是整数编码:这种编码表示节点的content属性保存着整数值,整数值的类型和长度由编码除去最高两位之后的其他位记录。
节点的content属性负责保存节点的值,节点值可以是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定。
节点的content属性负责保存节点的值,节点值可以是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定
redis数据结构和对象二的更多相关文章
- Redis数据结构和对象三
1.Redis 对象系统 Redis用到的所有主要数据结构,简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合.跳跃表. Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些 ...
- redis数据结构整理(二)
摘要: 1.各个数据结构的应用举例 1.1 String类型应用举例 1.2List类型应用举例 1.3Set类型应用举例 1.4Sorted Set类型应用举例 1.5Hash类型应用举例 内容: ...
- redis数据结构和对象一
1. SDS:简单动态字符串(simple dynamic string) Redis没有直接使用C语言的字符串,而是自己构建了一种名为简单动态字符串类型,并将SDS用作Redis的默认字符串. SD ...
- redis 系列9 对象类型(字符串,哈希,列表,集合,有序集合)与数据结构关系
一.概述 在前面章节中,主要了解了 Redis用到的主要数据结构,包括:简单动态字符串.链表(双端链表).字典.跳跃表. 整数集合.压缩列表(后面再了解).Redis没有直接使用这些数据结构来实现键值 ...
- Redis 的底层数据结构(对象)
目前为止,我们介绍了 redis 中非常典型的五种数据结构,从 SDS 到 压缩列表,这都是 redis 最底层.最常用的数据结构,相信你也掌握的不错. 但 redis 实际存储键值对的时候,是基于对 ...
- [redis读书笔记] 第一部分 数据结构与对象 对象类型
- 从前面redis的基本数据结构来看,可以看出,redis都是在基本结构(string)的基础上,封装了一层统计的结构(SDS),这样让对基本结构的访问能够更快更准确,提高可控制度. - redis ...
- Redis学习笔记(二)redis 底层数据结构
在上一节提到的图中,我们知道,可以通过 redisObject 对象的 type 和 encoding 属性.可以决定Redis 主要的底层数据结构:SDS.QuickList.ZipList.Has ...
- Redis学习笔记一:数据结构与对象
1. String(SDS) Redis使用自定义的一种字符串结构SDS来作为字符串的表示. 127.0.0.1:6379> set name liushijie OK 在如上操作中,name( ...
- Redis 基础数据结构与对象
Redis用到的底层数据结构有:简单动态字符串.双端链表.字典.压缩列表.整数集合.跳跃表等,Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包 ...
随机推荐
- zjnu1786 PROSJEK(二分)
Description Sample Input 4 1 1 2 3 4 Sample Output 4.000000 题意:给你n个数,让你找到长度大于等于k的连续串的最大平均值. 思路:我们可以二 ...
- 【noi 2.6_9285】盒子与小球之三(DP)
题意:有N个相同的球,M个不同的盒子,每个盒子最多放K个球.请计算将这N个球全部放入盒子中的方案数模1000007后的结果. 解法:f[i][j]表示i个盒子里放j个球的方案数. 1.得到3重循环的坐 ...
- B. Queue
During the lunch break all n Berland State University students lined up in the food court. However, ...
- HDU - 2159 dp
题目: 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务.久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级.现在的问题是,xhd升掉最后一级还 ...
- Codeforces Round #653 (Div. 3) D. Zero Remainder Array (数学,模拟)
题意:有一组数,刚开始时\(x=0\),每次可以让\(x\)++或让某一个元素+=\(x\)后\(x\)++,每个元素只能加一次\(x\),问最少操作多少次使得所有元素能被\(k\)整除. 题解:每个 ...
- docker 支持systemctl start|stop|status等操作
用docker运行centos7容器时候,无法使用systemctl,官方解释是centos7的一个bug,可以有修复的办法: 在docker run的时候,加上--privileged 并且cmd使 ...
- 2.使用Helm构建ElasticSearch集群
作者 微信:tangy8080 电子邮箱:914661180@qq.com 更新时间:2019-05-24 16:08:53 星期五 欢迎您订阅和分享我的订阅号,订阅号内会不定期分享一些我自己学习过程 ...
- SPOJ SUBST1 New Distinct Substrings(后缀数组 本质不同子串个数)题解
题意: 问给定串有多少本质不同的子串? 思路: 子串必是某一后缀的前缀,假如是某一后缀\(sa[k]\),那么会有\(n - sa[k] + 1\)个前缀,但是其中有\(height[k]\)个和上一 ...
- In_array()函数弱比较
0x01 定义 (PHP 4, PHP 5, PHP 7) in_array - 检查数组中是否存在某个值 说明 in_array ( mixed $needle , array $haystack ...
- Linux 驱动框架---驱动中的异步
异步IO是对阻塞和轮询IO的机制补充,所谓异步IO就是在设备数据就绪时主动通知所属进程进行处理的机制.之所以说是异步是相对与被通知进程的,因为进程不知道也无法知道什么时候会被通知:这一机制非常类似于硬 ...