Redis源码学习简记(九)t_hash原理与个人理解

本文记录了Redis源码学习中关于t_hash部分的理解,涉及根据robj结构体查找、添加、删除键值对的操作。Redis使用dict或ziplist存储hash表,根据编码模式调用不同API。此外,还介绍了初始化、迭代和释放迭代器的过程,以及如何通过迭代器获取key-value数据。
摘要由CSDN通过智能技术生成

        对于redis的基本数据结构,经过一个多星期的分析大概是明了了。接下来根据计划是分析t_前缀的大量的接口函数。这里面就比底层数据更加接近用户的逻辑代码了。其实本人比较期待的后面集群,服务器等这些代码的实现。话不多说,马上来分析一下吧。

    这部分的代码并没有头文件。直接一个c文件里面包含了所有的函数,我经过整理后,根据比较合适的阅读顺序来发每一个函数吧。这部分的函数主要做的工作都是,通过前面的robj结构体,获取key-value,以及添加删除等操作的qpi。

    首先为查找value的操作。对于hash表的存储,redis的策略是使用dict或者ziplist来存储。所以就会出现两种情况,根据编码模式调用不同的取值函数。

/* Higher level function of hashTypeGet*() that returns the hash value
 * associated with the specified field. If the field is found C_OK
 * is returned, otherwise C_ERR. The returned object is returned by
 * reference in either *vstr and *vlen if it's returned in string form,
 * or stored in *vll if it's returned as a number.
 *
 * If *vll is populated *vstr is set to NULL, so the caller
 * can always check the function return by checking the return value
 * for C_OK and checking if vll (or vstr) is NULL. */
int hashTypeGetValue(robj *o, sds field, unsigned char **vstr, unsigned int *vlen, long long *vll) {
    //该函数根据编码模式,从上一次分析的封装对象中,获取与field对应的值。
    //redis是key-value的nosql数据库,获取每一个value必定存在其key
    if (o->encoding == OBJ_ENCODING_ZIPLIST) {// 根据类型调用相应的函数
        *vstr = NULL;
        if (hashTypeGetFromZiplist(o, field, vstr, vlen, vll) == 0)

            return C_OK;
    } else if (o->encoding == OBJ_ENCODING_HT) {
        sds value;
        if ((value = hashTypeGetFromHashTable(o, field)) != NULL) {
            *vstr = (unsigned char*) value;
            //此时vstr存储对应的数据
            *vlen = sdslen(value);
            //vlen存储数据的长度。
            return C_OK;
        }
    } else {
        serverPanic("Unknown hash encoding");
    }
    return C_ERR;
}

下面分别是两种编码结构的具体实现,主要是调用了其结构提供的api。

/* Get the value from a ziplist encoded hash, identified by field.
 * Returns -1 when the field cannot be found. */
//如应为所所找到的话返回到vll中或者vstr中,根据类型进行选择
//若没有找到则直接返回-1,研究源码不要太过深究,重在数据结构与设计思路。
//太过深究,时间花太多,反而没有兴致了。
//对于太过复杂的问题就应该不求甚解的学习方式
int hashTypeGetFromZiplist(robj *o, sds field,
                           unsigned char **vstr,
                           unsigned int *vlen,
                           long long *vll)
{
    unsigned char *zl, *fptr = NULL, *vptr = NULL;
    int ret;
    

    serverAssert(o->encoding == OBJ_ENCODING_ZIPLIST);

    zl = o->ptr;
    fptr = ziplistIndex(zl, ZIPLIST_HEAD);
    //ziplist_head 为 0 找到的为第一个元素的地址
    //下面对于ziplist的一顿操作,都是根据field值找到该元素。
    if (fptr != NULL) {
        fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
        
        //发现这个list也是以key-value的方式进行存储,那么就需要设置skip数为1
        //那么相当于两个两个对数据进行遍历。
        //找到key的值后,value的值就是next。
        //下面调用ziplistNext的原因迎刃而解。
        if (fptr != NULL) {
            /* Grab pointer to the value (fptr points to the field) */
            vptr = ziplistNext(zl, fptr);
            //这边的指向下个元素,原因也不懂,可能是由于没有认真看ziplist中的所有函数所造成的。
            serverAssert(vptr != NULL);
        }
    }

    if (vptr != NULL) {
        ret = ziplistGet(vptr, vstr, vlen, vll);
        serverAssert(ret);
        return 0;
    }

    return -1;
}

/* Get the value from a hash table encoded hash, identified by field.
 * Returns NULL when the field cannot be found, otherwise the SDS value
 * is returned. */
sds hashTypeGetFromHashTable(robj *o, sds field) {
    dictEntry *de;
    //dict就更加好理解了
    //直接调用dictFind找出元素,并且获取其值,以sds(字符串)的方式返回
    serverAssert(o->encoding == OBJ_ENCODING_HT);

    de = dictFind(o->ptr, field);
    if (de == NULL) return NULL;
    return dictGetVal(de);
}

通过查找返回一个robj结构体,调用前面的查找函数。

/* Like hashTypeGetValue() but returns a Redis object, which is useful for
 * interaction with the hash type outside t_hash.c.
 * The function returns NULL if the field is not found in the hash. Otherwise
 * a newly allocated string object with the value is retur
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值