对象处理机制

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. shell脚本——项目1

    案例名称:系统初始化 背景:10台已装有linux系统的服务器 需求: 1.设置时区同步 2.禁用selinux 3.清空防火墙策略 4.历史命令显示操作时间 5.禁止root远程登录 6.禁止定时任 ...

  2. 寻宝游戏(bzoj 3991)

    Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...

  3. 大工程(bzoj 3611)

    Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 2 个国家 a,b 之间建一条新通 ...

  4. 消耗战(bzoj 2286)

    Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军 ...

  5. Intel与Motorola区别

    Intel低字节在前 Motorola高字节在前    在进行CAN总线通信设计或者测试过 程中,经常看到CAN总线信号的编码格式有两种定义:Intel格式与Motorola格式.究竟两种编码格式有什 ...

  6. [网络流24题] COGS 750 栅格网络流

    750. 栅格网络流 ★★☆   输入文件:flowa.in   输出文件:flowa.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] Bob 觉得一般图的最大流问题太 ...

  7. 狂K 线段树

    想写好树剖~~线段树very important HDU 1166 敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536 ...

  8. gdb 记录临时变量

    gdb ./pgm set logging file log set logging on ... set logging off gdb ./pgm | tee -a log ... file a. ...

  9. matlab 分析wav波形

    [x,fs,bits]=wavread('d.wav', [1 5000]); % sound(x, fs, bits); N = length(x); n = 0 : N-1; t = n/fs; ...

  10. 多目录,多可执行文件的Makfile的编写

    1.前言 在目前的工作中,我遇到这样的一个工作情景,可以认为我要开发一个库,这个库的有多个模块,每个模块的.c放到src中,.h放到include中,这应该是个标准做法. drwxr-xr-x. ro ...