在之前的文章里,我们陆续介绍了Redis用到的所有主要数据结构,比如简单动态字符串(SDS)、双端链表、字典、压缩列表、整数集合等等。
Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,每种对象都用到了至少一种我们前面所介绍的数据结构。
1 对象类型与编码
每个对象大概长下边这个样子:
typedef struct redisObject {
//类型
unsigned type:4;
//编码
unsigned encoding:4;
//指向底层实现数据结构的指针
void *ptr;
} robj;
1.1 类型
对象的类型呢也主要有以下几种:
注意: 由于redis整个就是一个key-value的数据库,key永远都是字符串对象,value可以有不同种类的对象,因此我们说“列表键”、“字符串键”等都是对value的称呼。
我们可以用TYPE命令判断数据库键 所对应的 值对象的类型:
#键为字符串对象,值为哈希对象
redis> HMSET profile name Tom age 25 career Progr ammer
OK
redis> TYPE profile
hash
不同类型有不同的输出:
1.2 编码和底层实现
对象的ptr指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定。
encoding属性记录了对象所使用的编码,也即是说这个对象使用了什么数据结构作为对象的底层实现,这个属性的值可以是下表列出的常量的其中一个。
类型和编码之间的关系可以从下表看出:
除此之外我们可以通过 OBJECT ENCODING命令查看数据库键的值对象对应的编码;
redis> SET msg "hello wrold"
OK
redis> OBJECT ENCODING msg
"embs tr"
所有可能的输出结果如下表所示:
接下来我们一个对象一个对象的介绍:
2 字符串对象
字符串对象的编码可以是int、raw 或者embstr。
- 如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面(将void*转换成long),并将字符串对象的编码设置为int。
- 如果字符串对象保存的是一一个字符串值,并且这个字符串值的长度大于32字节,那么字符串对象将使用一一个简单动态字符串( SDS)来保存这个字符串值,并将对象的编码设置为raw。
- 如果字符串对象保存的是一个字符串值,并且这个字符串值的长度小于等于32字节,那么字符串对象将使用embstr编码的方式来保存这个字符串值。
注意: embstr编码是专门用于保存短字符串的一种优化编码方式,这种编码和raw编码一样,都使用redisObject结构和sdshdr结构来表示字符串对象,但raw编码会调用两次内存分配函数来分别创建redisobject结构和sdshdr结构,而embstr编码则通过
调用一次内存分配函数来分配一块连续的空间,空间中依次包含redisObject和sdshdr两个结构,如图所示。
2.1 编码转换
int编码的字符串对象和embstr编码的字符串对象在条件满足的情况下,会被转换为raw编码的字符串对象。
- 对int编码的字符串修改使其不为int,就会变为raw
- 对embstr编码做任何的修改都会变成raw
2.2 字符串的命令实现
接下来的对象下次说吧!