redis自顶向下源码阅读(十二)——读取 RDB 文件2
1. 读取value
/* Read value */
// if ((val = rdbLoadObject(type,&rdb)) == NULL) goto eoferr;
/* Load a Redis object of the specified type from the specified file.
* On success a newly allocated object is returned, otherwise NULL. */
robj *rdbLoadObject(int rdbtype, rio *rdb) {
robj *o, *ele, *dec;
size_t len;
unsigned int i;
1.1 STRING
类型
string 类型和 key 是一样的读取方式,但是是有编码的。字符串的编码可查看Redis字符串类型内部编码剖析,redis对象编码源码阅读——字符串编码与创建
if (rdbtype == REDIS_RDB_TYPE_STRING) {
/* Read string value */
if ((o = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
// 尝试节省 string 对象所占空间,即编码过程
o = tryObjectEncoding(o);
rdbLoadEncodedStringObject
robj *rdbLoadEncodedStringObject(rio *rdb) {
return rdbGenericLoadStringObject(rdb,1);
}
tryObjectEncoding: redis对象编码源码阅读——字符串编码过程
1.2 LIST
类型
跟STRING
一样,先需要用rdbjLoadLen
函数读取LIST
的长度。
} else if (rdbtype == REDIS_RDB_TYPE_LIST) {
/* Read list value */
if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
创建列表对象,有两种编码ZIPLIST
和LINKEDLIST
,两种编码的区别可见:redis对象编码源码阅读——列表对象编码与创建
/* Use a real list when there are too many entries */
if (len > server.list_max_ziplist_entries) {
o = createListObject();
} else {
o = createZiplistObject();
}
一个一个地读出列表每个元素,列表中的元素是STRING
对象
/* Load every single element of the list */
while(len--) {
// 读取 STRING 对象
if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
ziplist
编码的条件:(摘自《Redis设计与实现》70页)
- 列表对象保存的所有字符串元素长度都小于64字节
- 列表对象保存的元素数量小于512个
代码中判断的是前者。
/* If we are using a ziplist and the value is too big, convert
* the object to a real list. */
if (o->encoding == REDIS_ENCODING_ZIPLIST &&
sdsEncodedObject(ele) &&
sdslen(ele->ptr) > server.list_max_ziplist_value)
listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
ziplist
转linkedlist
的过程见:redis对象编码源码阅读——列表对象编码与创建
不需要改变编码则添加到原LIST
对象中
if (o->encoding == REDIS_ENCODING_ZIPLIST) {
// 对 ele 字符串进行解码
// RAW, EMBSTR 编码的字符串直接增加引用数
// INT 编码的字符串重新创一个新的 EMBSTR 编码字符串返回
dec = getDecodedObject(ele);
o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL);
decrRefCount(dec);
decrRefCount(ele);
} else {
ele = tryObjectEncoding(ele);
listAddNodeTail(o->ptr,ele);
}
}
1.3 SET
类型
读取value
的长度
} else if (rdbtype == REDIS_RDB_TYPE_SET) {
/* Read list/set value */
if ((len = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
SET
对象有两种编码类型:
-
intset
: 1) 集合对象保存