redis自顶向下源码阅读(十二)——读取 RDB 文件2

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;

创建列表对象,有两种编码ZIPLISTLINKEDLIST,两种编码的区别可见: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);

ziplistlinkedlist的过程见: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) 集合对象保存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值