原文链接
redisObject
在redis中,不同的数据类型有不同的操作命令。如: LPUSH 和 LLEN 只能用于列表键, 而 SADD 和 SRANDMEMBER 只能用于集合键。
因此redis 必须让每个键都带有类型信息,是的程序可以检查键的类型,并为它选择合适的处理方式,
操作数据类型的命令除了要对键的类型进行检查外,还需要根据数据类型的不同编码进行多态处理。
redis 构建了自己的类型系统,这个系统的主要功能包括:
- redisObject 对象
- 基于redisObject对象的类型检测
- 基于redisObject对象的显示多态函数
- 对redisObject进行分配、共享和销毁的机制
typedef struct redisObject {
// 类型
unsigned type:4;
// 编码方式
unsigned encoding:4;
// LRU - 24位, 记录最末一次访问时间(相对于lru_clock); 或者 LFU(最少使用的数据:8位频率,16位访问时间)
unsigned lru:LRU_BITS; // LRU_BITS: 24
// 引用计数
int refcount;
// 指向底层数据结构实例
void *ptr;
} robj;
- type 记录了对象所保存的值的类型,它的值可能是以下常量中的一个:
/*
* 对象类型
*/
#define OBJ_STRING 0 // 字符串
#define OBJ_LIST 1 // 列表
#define OBJ_SET 2 // 集合
#define OBJ_ZSET 3 // 有序集
#define OBJ_HASH 4 // 哈希表
- encoding 记录了对象所保存的值的编码,它的值可能是以下常量中的一个:
/*
* 对象编码
*/
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3 /* 注意:版本2.6后不再使用. */
#define OBJ_ENCODING_LINKEDLIST 4 /* 注意:不再使用了,旧版本2.x中String的底层之一. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
- ptr是一个指针,指向实际保存值的数据结构,这个数据结构由type 和 encoding 共同决定
- lru属性:记录了对象最后一次被程序访问的时间
命令的类型检查和多态
当执行一个处理数据类型命令的时候,redis执行以下步骤:
- 根据给定的key,在数据库字典中查找和他相对应的redisObject,如果没找到,就返回NULL;
- 检查redisObject的type属性和执行命令所需的类型是否相符,如果不相符,返回类型错误;
- 根据redisObject的encoding属性所指定的编码,选择合适的操作函数来处理底层的数据结构;
- 返回数据结构的操作结果作为命令的返回值。