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

本文详细介绍了Redis中读取RDB文件的过程,涵盖从字符串、列表、集合到有序集合等不同类型的对象读取方法。重点讨论了对象编码、长度读取及不同类型对象的创建。同时,提到了过期key的处理和RDB读取后的收尾工作,如校验和验证。

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) 集合对象保存的所有元素都是整数值;2) 集合对象保存的元素数量不超过512个

  • <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值