对象处理机制

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. yum升级kernel

    # uname -a Linux host -.el6.x86_64 # SMP Fri May :: BST x86_64 x86_64 x86_64 GNU/Linux # cat /etc/re ...

  2. linux -特殊符号

    在shell中常用的特殊符号罗列如下: # ;   ;; . , / \\ 'string'| !   $   ${}   $? $$   $* \"string\"* **   ...

  3. Redis为什么单进程单线程也那么快

    [转] http://www.syyong.com/db/Redis-why-the-use-of-single-process-and-single-threaded-way-so-fast.htm ...

  4. 写一个system.data.entity的simpledatarepo,实现crudq这些功能,不需要引入entityframework,直接可以使用,用到objectset

    note:you can delete reference of entityframework when using this classes.it`s just a simple repohelp ...

  5. 《Linux命令行与shell脚本编程大全 第3版》创建实用的脚本---11

    以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:

  6. centos7刚安装需要的一些基础优化

    基本操作一:更改主机名 centos7有一个新的修改主机名的命令hostnamectl # hostnamectl set-hostname --static benjamin # vim /etc/ ...

  7. hdu 1162(最小生成树)

    Eddy's picture Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  8. ***七牛跨域上传图片JS SDK

    SDK: http://developer.qiniu.com/code/v6/sdk/javascript.html#upload 上传 在页面中引入 plupload,plupload.full. ...

  9. hiho一下第129周 后缀自动机二·重复旋律6

    后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...

  10. (转)代码中实现button

    链接地址:http://www.cnblogs.com/hukezhu/p/4500206.html 随着iOS开发发展至今,在UI制作上逐渐分化为了三种主要流派:使用代码手写UI及布局:使用单个xi ...