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并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包 ...
随机推荐
- C#脚本引擎RulesEngine
当编写应用程序时,经常性需要花费大量的时间与精力处理业务逻辑,往往业务逻辑的变化需要重构或者增加大量代码,对开发测试人员很不友好. 之前在这篇文章说过,可以使用脚本引擎来将我们需要经常变化的代码进行动 ...
- 使用Python调用SMTP服务自动发送Email
需求背景 假设我们想设计一个定时任务,比如每天定时的用python来测试服务是否在正常运行,但是又不希望每天登录到系统后台去查看服务状态.这里我们就可以采取python的smtp模块进行任务结果广播, ...
- AtCoder Beginner Contest 174
第一次 ak ABC,纪念一下. 比赛链接:https://atcoder.jp/contests/abc174 A - Air Conditioner #include <bits/stdc+ ...
- codeforces626D . Jerry's Protest (概率)
Andrew and Jerry are playing a game with Harry as the scorekeeper. The game consists of three rounds ...
- Codeforces Round #680 (Div. 2, based on Moscow Team Olympiad) D. Divide and Sum (思维,数学,逆元)
题意:有一个长度为\(2n\)数组,从中选分别选\(n\)个元素出来组成两个序列\(p\)和\(q\),(\(p\)和\(q\)中只要有任意一个元素在\(a\)的原位置不同,就算一个新的情况),选完后 ...
- CF1466-D. 13th Labour of Heracles
CF1466-D. 13th Labour of Heracles 题意: 给出一个由\(n\)个点构成的树,每个点都有一个权值.现在你可以用\(k,k\subset\)\([1, n]\)个颜色来给 ...
- Leetcode(9)-回文数
判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...
- sqll-libs(3)
单引号测试,最外层单引号错误信息near ''1'') LIMIT 0,1' at line 1 由此我们可以确定SQL后台语句为select * from table where id =('inp ...
- CSS pseudo classes All In One
CSS pseudo classes All In One CSS 伪类 https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes ...
- React Hooks: useReducer All In One
React Hooks: useReducer All In One useReducer https://reactjs.org/docs/hooks-reference.html#usereduc ...