Redis 基础数据结构与对象
1 简单动态字符串
struct sdshdr {
unsigned int len;
unsigned int free;
char buf[];
};

redis> set name intrack
Redis将在数据库中创建一个新的键值对,其中键是一个字符串,一个保存着"name"的sds;值是一个字符串,一个保存着"intrack"的sds。
- 常数复杂度获取字符长度
- 避免缓冲区溢出
- 减少修改字符操作时引起的内存分配次数(注意:free内存大小最大为1M)
- 二进制安全的
- 兼容部分C字符串函数(因为字符串后面以'\0'结尾)
2 链表
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;

typedef struct list {
listNode *head;
listNode *tail;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
unsigned long len;
} list;
list结构链表提供了表头指针head、表尾指针tail及链表长度len,而dup/free/match用于实现存储类型无关链表所需的类型特性函数。dup用于复制一个链表节点、free用于释放一个链表节点、match用于匹配链表节点和输入的值是否相等。

- 链表被广泛用于实现Redis的各种功能,比如列表键、发布与订阅、慢查询、监视器等。
- 每个链表节点由一个listNode结构表示,每个节点都有一个指向前置节点和后置节点的指针,所以Redis中链表是双向链表。
- 每个链表使用一个list结构表示,这个结构有表头节点指针、表尾节点指针、以及链表长度信息。
- 链表表头节点的前置节点和表尾的后置节点都指向NULL,所以Redis链表是无环链表。
- 通过将链表设置不同类型的特定函数,使得Redis链表可存储不同类型的值。
3 字典
redis> set msg "hello world"
在数据库中创建了一个键为msg,值为hello world的键值对时,这个键值对就保存在代表数据库的字典里面的。除了用作数据库之外,字典还是哈希键的底层实现之一。
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask; // 哈希表大小掩码,用于计算索引值
unsigned long used; // 已有节点数量
} dictht;

typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
key保存键值对中的键,v属性保存值信息,值可以是一个指针/uint64_t整数/int64_t整数。next指向下一个哈希表节点指针,解决键值对冲突问题。

Redis的字典由dict结构定义:
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
type属性和privdata属性是针对不同类型的键值对,为创建可以存储多种类型的字典而设置的。
typedef struct dictType {
unsigned int (*hashFunction)(const void *key); // 哈希计算
void *(*keyDup)(void *privdata, const void *key); // 复制键的函数
void *(*valDup)(void *privdata, const void *obj); // 复制值的函数
int (*keyCompare)(void *privdata, const void *key1, const void *key2); // 比较键的函数
void (*keyDestructor)(void *privdata, void *key); // 销毁键的函数
void (*valDestructor)(void *privdata, void *obj); // 销毁值的函数
} dictType;

- 字典被广泛用于实现Redis的各种功能,其中包括数据库和哈希键。
- Redis中字典使用哈希表作为底层实现,每个字典有2个哈希表,一个平时使用,另一个只在rehash时使用。
- 当字典作为数据库的底层实现,或者作为哈希键的底层实现时,使用MurmurHash2算法计算键的哈希值。
- 哈希表使用分离连接法解决键冲突问题,被分配到同一个索引上多个键值会连接成一个单向链表。
- 在对哈希表进行扩展或者缩容操作时,需要将现有哈希表中键值对rehash到新哈希表中,这个rehash过程不是一次性完成的,而是渐进的。
4 跳跃表

typedef struct zskiplistNode {
robj *obj; // Redis对象
double score;
struct zskiplistNode *backward;
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned int span;
} level[];
} zskiplistNode;
span属性用于记录两个节点之间的距离,指向NULL的forward值都为0。节点的分值score是一个浮点数,跳跃表中所有节点都按照分值从小到大排列。obj属性必须指向一个字符串对象,而字符串则保存着一个sds。
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;
header和tail指针分表指向跳跃表的表头和表尾节点,通过length属性记录表长度,level属性用于保存跳跃表中层高最大的节点的层高值。每个跳跃表节点层高都是1~32的随机值,在同一个跳跃表中,多个节点可以包含相同的分值,但是每个节点的成员对象必须是唯一的。当分值相同时,节点按照成员对象的大小排序。

5 整数结合
typedef struct intset {
uint32_t encoding; // 16/32/64编码
uint32_t length; // 数组长度
int8_t contents[];
} intset;
contents数组用于存储整数,数组中的值按照值的大小从小到大有序排列,并且不会包含重复项。当encoding编码的是int型整数的话,那么contents数组中每4项用于保存一个int型整数。

6 压缩列表

7 Redis中的对象
typedef struct redisObject {
unsigned type:;
unsigned encoding:;
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
type表示对象类型,对于Redis键值对来说,键永远都是字符串,值可以是字符串、列表、哈希表、集合、有序集合中的一种。encoding表示对象编码,也就是该对象使用什么底层数据结构实现。ptr指向对象的底层数据结构。


7.1 字符串对象

embstr编码方式是redisObject结构和sdshdr结构在一块内存中,使用embstr对象只需要调用一次内存分配函数即可,而raw方式需要调用2次。因为在同一块内存中,所以对缓存是友好的。

注意,linkedlist编码的列表对象在底层双端列表中包含了多个字符串对象,这个嵌套字符串对象行为在哈希表、集合中都会出现,字符串对象是Redis五种类型中唯一一种会被其他四种类型对象嵌套的对象。

以上命令对应的压缩列表视图如下所示:
typedef struct zset {
dict *dict;
zskiplist *zsl;
} zset;
zset中的zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点保存一个集合元素,跳跃表节点的object属性保存元素的成员,score属性保存元素的分值。通过该跳跃表,可以对有序集合进行范围型操作,比如zrank、zrange命令就是基于跳跃表实现的。
Redis 基础数据结构与对象的更多相关文章
- redis 基础数据结构实现
参考文献 redis数据结构分析 Skip List(跳跃表)原理详解 redis 源码分析之内存布局 Redis 基础数据结构与对象 Redis设计与实现-第7章-压缩列表 在redis中构建了自己 ...
- redis基础数据结构及编码方式
redis基础数据结构和编码方式 一.基础数据结构 1)简单动态字符串 2)双端链表 3)字典 4)跳跃表 5)整数集合 6)压缩列表 二.对象类型与编码 在redis的数据库中创建一个新的键值对时, ...
- 1.基础: 万丈高楼平地起——Redis基础数据结构 学习记录
<Redis深度历险:核心原理和应用实践>1.基础: 万丈高楼平地起——Redis基础数据结构 学习记录http://naotu.baidu.com/file/b874e2624d3f37 ...
- Redis基础数据结构
Redis数据库中每个键值对都是由对象( c 的结构体对象)组成的. 数据库键总是一个字符串对象(string object) 数据库键的值可以使字符串对象.列表对象(list object).哈希对 ...
- Redis——基础数据结构
Redis提供了5种基础数据结构,分别是String,list,set,hash和zset. 1.String Redis所有的键都是String.Redis的String是动态字符串,内部结构类似J ...
- Redis 基础数据结构之二 list(列表)
Redis 有 5 种基础数据结构,分别为:string (字符串).list (列表).set (集合).hash (哈希) 和 zset (有序集合). 今天来说一下list(列表)这种数据结构, ...
- Redis 基础数据结构之一:string(字符串)
Redis 有 5 种基础数据结构,分别为:string (字符串).list (列表).set (集合).hash (哈希) 和 zset (有序集合),Redis存储数据的结构是键值对形式的. 首 ...
- Redis基础数据结构-基于2.8
SDS SDS是Redis中String的底层数据结构,数据结构如下,SDS保留了传统的C字符串表达方式即数组的最后一个元素是'/0'结尾.此外还添加了两个字段len和free,其中len表示字符串长 ...
- 浅析Redis基础数据结构
Redis是一种内存数据库,所以可以很方便的直接基于内存中的数据结构,对外提供众多的接口,而这些接口实际上就是对不同的数据结构进行操作的算法,首先redis本身是一种key-value的数据库,对于v ...
随机推荐
- fopen的使用小记
整理自https://msdn.microsoft.com/zh-cn/library/t3ayayh1(VS.80).aspx errno, _doserrno, _sys_errlist, and ...
- 1.各个浏览器内核?经常遇到的浏览器兼容性有哪些?解决办法?常用的hack技巧?
IE: trident内核 Firefox(火狐):gecko内核 Safari(苹果):webkit内核 Opera(欧鹏):以前是presto内核,现在是Blink内核 Chrome:Blink ...
- 自己实现的一个简单的EF框架(反射实现)
我实现了一个简单的EF框架,主要用于操纵数据库.实现了对数据库的基本操纵--CRUD 这是项目结构 这是一个 core 下的 DLL 写了一个数据库工厂,用于执行sql语句.调用sql语句工厂 写了一 ...
- SSH抛出org.apache.ibatis.exceptions.PersistenceException: 异常
抛出的异常类容如下 如果遇到这个异常,那么肯定是你在配置事物切面时出错,或者是你的写的事物的方法名称没有和这里的配置对应: 你需要注意如下几点: 1.你的名称必须是以英文开头 2.在你用着事物方法的名 ...
- webpack的多文件打包问题
1.第三方库如vue,vue-router可以利用webpack中的entry指定vendor:['vue','vue-router']来打包在一个文件中 2.将这些文件单独提取出来,在页面中使用&l ...
- 谷歌发布基于机器学习的Android APP安全检测系统:Google Play Protect
Google Play作为众所周知的在线应用市场,因为审查制度的松散,经常会有一些恶意软件伪装成其他应用混入其中.此前阿里聚安全小编就报道了2例关于恶意软件伪装在Google Play上的事件:< ...
- 关于JAVA自带MD5的方法
有空再详细解释 import java.security.MessageDigest; public class MD5 { public final static String MD51(Strin ...
- 第6章 影响 MySQL Server 性能的相关因素
前言: 大部分人都一致认为一个数据库应用系统(这里的数据库应用系统概指所有使用数据库的系统)的性能瓶颈最容易出现在数据的操作方面,而数据库应用系统的大部分数据操作都是通过数据库管理软件所提供的相关接口 ...
- nginx源码分析——线程池
源码: nginx 1.13.0-release 一.前言 nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影 ...
- linux新学篇
[学会使用快捷键] Ctrl + C:这个是用来终止当前命令的快捷键,当然你也可以输入一大串字符,不想让它运行直接Ctrl + C,光标就会跳入下一行. Tab: 这个键是最有用的键了,也是笔者敲击概 ...