对象处理机制

Redis 构建了自己的类型系统,这个系统的主要功能包括:
• redisObject 对象。
• 基于redisObject 对象的类型检查。
• 基于redisObject 对象的显式多态函数。
• 对redisObject 进行分配、共享和销毁的机制。

(redisObject 实际上是只是一个结构类型。)

redisObject 的定义位于redis.h :
/*
* Redis 对象
*/
typedef struct redisObject {
// 类型
unsigned type:4;
// 对齐位
unsigned notused:2;
// 编码方式
unsigned encoding:4;
// LRU 时间(相对于server.lruclock)
unsigned lru:22;
// 引用计数
int refcount;
// 指向对象的值
void *ptr;
} robj;

type 、encoding 和ptr 是最重要的三个属性。

type 记录了对象所保存的值的类型,它的值可能是以下常量的其中一个(定义位于redis.h):

/*
* 对象类型
*/
#define REDIS_STRING 0 // 字符串
#define REDIS_LIST 1 // 列表
#define REDIS_SET 2 // 集合
#define REDIS_ZSET 3 // 有序集
#define REDIS_HASH 4 // 哈希表

encoding 记录了对象所保存的值的编码,它的值可能是以下常量的其中一个(定义位于redis.h):

/*
* 对象编码
*/
#define REDIS_ENCODING_RAW 0 // 编码为字符串
#define REDIS_ENCODING_INT 1 // 编码为整数
#define REDIS_ENCODING_HT 2 // 编码为哈希表
#define REDIS_ENCODING_ZIPMAP 3 // 编码为zipmap
#define REDIS_ENCODING_LINKEDLIST 4 // 编码为双端链表
#define REDIS_ENCODING_ZIPLIST 5 // 编码为压缩列表
#define REDIS_ENCODING_INTSET 6 // 编码为整数集合
#define REDIS_ENCODING_SKIPLIST 7 // 编码为跳跃表

ptr 是一个指针,指向实际保存值的数据结构,这个数据结构由type 属性和encoding 属性决定。
举个例子, 如果一个redisObject 的type 属性为REDIS_LIST , encoding 属性为REDIS_ENCODING_LINKEDLIST ,那么这个对象就是一个Redis 列表,它的值保存在一个双端链表内,而ptr 指针就指向这个双端链表;

命令的类型检查和多态

当执行一个处理数据类型的命令时,Redis 执行以下步骤:
1. 根据给定key ,在数据库字典中查找和它像对应的redisObject ,如果没找到,就返回NULL 。
2. 检查redisObject 的type 属性和执行命令所需的类型是否相符,如果不相符,返回类型错误。
3. 根据redisObject 的encoding 属性所指定的编码,选择合适的操作函数来处理底层的数据结构。
4. 返回数据结构的操作结果作为命令的返回值。

对象共享

有一些对象在Redis 中非常常见,比如命令的返回值OK 、ERROR 、WRONGTYPE 等字符,另外,一些小范围的整数,比如个位、十位、百位的整数都非常常见。

为了利用这种常见情况,Redis 在内部使用了一个Flyweight 模式:通过预分配一些常见的值对象,并在多个数据结构之间共享这些对象,程序避免了重复分配的麻烦,也节约了一些CPU时间。

Redis 预分配的值对象有如下这些:
• 各种命令的返回值,比如执行成功时返回的OK ,执行错误时返回的ERROR ,类型错误时返回的RONGTYPE ,命令入队事务时返回的QUEUED ,等等。
• 包括0 在内, 小于redis.h/REDIS_SHARED_INTEGERS 的所有整数(REDIS_SHARED_INTEGERS 的默认值为10000)

Note: 共享对象只能被带指针的数据结构使用。
需要提醒的一点是,共享对象只能被字典和双端链表这类能带有指针的数据结构使用。

像整数集合和压缩列表这些只能保存字符串、整数等字面值的内存数据结构,就不能使用共享
对象。

引用计数以及对象的销毁

Redis 的对象系统使用了引用计数技术来负责维持和销毁对象,它的
运作机制如下:
• 每个redisObject 结构都带有一个refcount 属性,指示这个对象被引用了多少次。
• 当新创建一个对象时,它的refcount 属性被设置为1 。
• 当对一个对象进行共享时,Redis 将这个对象的refcount 增一。
• 当使用完一个对象之后,或者取消对共享对象的引用之后,程序将对象的refcount 减一。
• 当对象的refcount 降至0 时,这个redisObject 结构,以及它所引用的数据结构的内存,都会被释放。

字符串

字符串编码

字符串类型分别使用REDIS_ENCODING_INT 和REDIS_ENCODING_RAW 两种编码:
• REDIS_ENCODING_INT 使用long 类型来保存long 类型值。
• REDIS_ENCODING_RAW 则使用sdshdr 结构来保存sds (也即是char* )、long long 、double 和long double 类型值。

换句话来说,在Redis 中,只有能表示为long 类型的值,才会以整数的形式保存,其他类型的整数、小数和字符串,都是用sdshdr 结构来保存。

编码的选择

新创建的字符串默认使用REDIS_ENCODING_RAW 编码,在将字符串作为键或者值保存进数据库时,程序会尝试将字符串转为REDIS_ENCODING_INT 编码。

哈希表

REDIS_HASH (哈希表) 是HSET 、HLEN 等命令的操作对象, 它使用REDIS_ENCODING_ZIPLIST 和REDIS_ENCODING_HT 两种编码方式:

字典编码的哈希表

当哈希表使用字典编码时,程序将哈希表的键(key)保存为字典的键,将哈希表的值(value)保存为字典的值。

哈希表所使用的字典的键和值都是字符串对象。下图展示了一个包含三个键值对的哈希表:

压缩列表编码的哈希表

当使用REDIS_ENCODING_ZIPLIST 编码哈希表时,程序通过将键和值一同推入压缩列表,从而形成保存哈希表所需的键-值对结构:

新添加的key-value 对会被添加到压缩列表的表尾。
当进行查找/删除或更新操作时,程序先定位到键的位置,然后再通过对键的位置来定位值的位置。

编码的选择

创建空白哈希表时,程序默认使用REDIS_ENCODING_ZIPLIST 编码,当以下任何一个条件被满足时,程序将编码从切换为REDIS_ENCODING_HT :
• 哈希表中某个键或某个值的长度大于server.hash_max_ziplist_value (默认值为64)。
• 压缩列表中的节点数量大于server.hash_max_ziplist_entries (默认值为512 )。

列表

REDIS_LIST (列表) 是LPUSH 、LRANGE 等命令的操作对象, 它使用REDIS_ENCODING_ZIPLIST 和REDIS_ENCODING_LINKEDLIST 这两种方式编码:

编码的选择

创建新列表时Redis 默认使用REDIS_ENCODING_ZIPLIST 编码,当以下任意一个条件被满足时,列表会被转换成REDIS_ENCODING_LINKEDLIST 编码:
• 试图往列表新添加一个字符串值, 且这个字符串的长度超过server.list_max_ziplist_value (默认值为64 )。
• ziplist 包含的节点超过server.list_max_ziplist_entries (默认值为512 )。

阻塞

BLPOP 、BRPOP 和BRPOPLPUSH 三个命令都可能造成客户端被阻塞,以下将这些命令统称为列表的阻塞原语。
阻塞原语并不是一定会造成客户端阻塞:
• 只有当这些命令被用于空列表时,它们才会阻塞客户端。
• 如果被处理的列表不为空的话,它们就执行无阻塞版本的LPOP 、RPOP 或RPOPLPUSH命令。

redis学习笔记——数据类型的更多相关文章

  1. Redis学习笔记——数据类型及操作

    数据操作 redis是key-value的数据,所以每个数据都是一个键值对 键的类型是字符串 值的类型分为五种: 字符串string 哈希hash 列表list 集合set 有序集合zset 数据操作 ...

  2. Redis学习笔记(三)Redis支持的5种数据类型的总结

    继续Redis学习笔记(二)来说说剩余的三种数据类型. 三.列表类型(List) 1.介绍 列表类型可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的一段片段.列表类型内部是 ...

  3. Redis学习笔记(二)Redis支持的5种数据类型的总结之String和Hash

    引言 在Redis学习笔记(一)中我们已经会安装并且简单使用Redis了,接下来我们一起来学习下Redis支持的5大数据类型. 简介 Redis是REmote DIctionary Server(远程 ...

  4. Redis学习笔记(二) Redis 数据类型

    Redis 支持五种数据类型:string(字符串).list(列表).hash(哈希).set(集合)和 zset(有序集合),接下来我们讲解分别讲解一下这五种类型的的使用. String(字符串) ...

  5. Redis学习笔记~目录

    回到占占推荐博客索引 百度百科 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合). ...

  6. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  7. Redis学习笔记(二)-key相关命令【转载】

    转自 Redis学习笔记(二)-key相关命令 - 点解 - 博客园http://www.cnblogs.com/leny/p/5638764.html Redis支持的各种数据类型包括string, ...

  8. Redis学习笔记(1)——Redis简介

    一.Redis是什么? Remote Dictionary Server(Redis) 是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value ...

  9. Redis学习笔记4-Redis配置具体解释

    在Redis中直接启动redis-server服务时, 採用的是默认的配置文件.採用redis-server   xxx.conf 这种方式能够依照指定的配置文件来执行Redis服务. 依照本Redi ...

随机推荐

  1. vue项目--favicon设置以及动态修改favicon

    最近写公司项目时,动态更新favicon 动态更新之前需要有一个默认的favicon. 目前vue-cli搭建的vue项目里面已经有了一个static文件夹,存放静态文件. favicon图片放到该文 ...

  2. yum 和 apt-get

    yum 和apt-get 一般来说著名的linux系统基本上分两大类: 1.RedHat系列:Redhat.Centos.Fedora等 2.Debian系列:Debian.Ubuntu等 RedHa ...

  3. 多线程之:ThreadLocal

    Java中ThreadLocal类可以使创建的变量只被同一个线程进行读和写操作,即使有多个线程同时执行同一段代码,并且这段代码中又有一个指向同一个ThreadLocal变量的引用,这些线程依然不能看到 ...

  4. leetcode-Min Cost Climbing Stairs

    题目: On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed). Once you ...

  5. laravel-u-editor工具栏语言切换的方法

    更改/config/app.php/locale,可支持en,zh_CN,zh_TW,我们一般设为zh_CN

  6. Visual Studio跨平台开发(4):Xamarin Android控制项介绍

    前言 不同于iOS, Xamarin 在Visual Studio中针对Android, 可以直接设计使用者界面. 在本篇教学文章中, 笔者会针对Android的专案目录结构以及基本控制项进行介绍, ...

  7. HDU 1024 Max Sum Plus Plus(基础dp)

    Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  8. 洛谷——P1595 信封问题

    P1595 信封问题 题目描述 某人写了n封信和n个信封,如果所有的信都装错了信封.求所有信都装错信封共有多少种不同情况. 输入输出格式 输入格式: 一个信封数n(n<=20) 输出格式: 一个 ...

  9. Linq 连接运算符:Concat,Union

    //Concat()方法附加两个相同类型的序列,并返回一个新序列(集合)IList<string> strList = new List<string>() { "O ...

  10. pyttsx的中文语音识别问题及探究之路

    最近在学习pyttsx时,发现中文阅读一直都识别错误,从发音来看应该是字符编码问题,但搜索之后并未发现解决方案.自己一路摸索解决,虽说最终的原因非常可笑,大牛们可能也是一眼就能洞穿,但也值得记录一下. ...