redis对象编码源码阅读——字符串编码过程

18 篇文章 0 订阅
17 篇文章 1 订阅
本文深入探讨了Redis中字符串对象的编码过程,包括如何判断字符串是否可编码为整型、编码为共享对象,以及在无法编码时如何释放多余内存。
摘要由CSDN通过智能技术生成

redis对象编码源码阅读——字符串编码过程

对于RAW类型的字符串,需要进一步进行编码,判断它是不是可以表示为整型数;更进一步地,看它能否成为共享变量。当然这都是为了节约内存。

/* Try to encode a string object in order to save space */
robj *tryObjectEncoding(robj *o) {
    long value;
    sds s = o->ptr;
    size_t len;

1. 判断是不是能编码

    /* 确保这是一个字符串对象,
    * 这是我们在这个函数中编码的唯一类型。
    * 其他类型使用编码的高效内存表示,但由实现该类型的命令处理。 */
    // 判断是不是字符串对象
    redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);

    // 判断它的编码类型
    if (!sdsEncodedObject(o)) return o;

    // 判断它是不是共享对象,引用数是不是大于 1
    if (o->refcount > 1) return o;

2. 判断是不是能编码为INT

    /* 检查是否可以把这个字符串表示成一个长整数。
    * 请注意,大于21字符的字符串是不可表示为32位或64位整数的。 */
    len = sdslen(s);
    // string2l: string 对象转 long 对象的函数
    if (len <= 21 && string2l(s,len,&value)) {
        /* 此对象可编码为long对象。尝试使用共享对象。
        * 注意,当使用 maxmemory 时,我们避免使用共享整数,
        * 因为每个对象都需要有一个私有的LRU字段,以便LRU算法正常工作。 */
        if ((server.maxmemory == 0 ||
            (server.maxmemory_policy != REDIS_MAXMEMORY_VOLATILE_LRU &&
            server.maxmemory_policy != REDIS_MAXMEMORY_ALLKEYS_LRU)) &&
            value >= 0 &&
            value < REDIS_SHARED_INTEGERS)
        {
            // 释放原来的 string 对象
            decrRefCount(o);
            // 添加新的全局 long 类型引用
            incrRefCount(shared.integers[value]);
            return shared.integers[value];
        } else {
            // 把对象类型从 string 转为 int
            if (o->encoding == REDIS_ENCODING_RAW) sdsfree(o->ptr);
            o->encoding = REDIS_ENCODING_INT;
            o->ptr = (void*) value;
            return o;
        }
    }

3. 判断是不是能编码为EMBSTR

    /* 如果字符串很小,仍然是原始编码,
    * 那么尝试EMBSTR编码,它更有效。
    * 在这种表示中,对象和SDS字符串在相同的内存块中分配,
    * 以节省空间和缓存丢失。 */
    if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) {
        robj *emb;

        if (o->encoding == REDIS_ENCODING_EMBSTR) return o;
        emb = createEmbeddedStringObject(s,sdslen(s));
        decrRefCount(o);
        return emb;
    }

4. 没法编码,判断是否需要释放多余空间

    /* We can't encode the object...
    *
    * Do the last try, and at least optimize the SDS string inside
    * the string object to require little space, in case there
    * is more than 10% of free space at the end of the SDS string.
    *
    * We do that only for relatively large strings as this branch
    * is only entered if the length of the string is greater than
    * REDIS_ENCODING_EMBSTR_SIZE_LIMIT. */
    // sdsavail: 返回 SDS 的未使用空间字节数
    if (o->encoding == REDIS_ENCODING_RAW &&
        sdsavail(s) > len/10)
    {
        o->ptr = sdsRemoveFreeSpace(o->ptr);
    }

    /* Return the original object. */
    return o;
}
/* Reallocate the sds string so that it has no free space at the end. The
 * contained string remains not altered, but next concatenation operations
 * will require a reallocation.
 *
 * After the call, the passed sds string is no longer valid and all the
 * references must be substituted with the new pointer returned by the call. */
sds sdsRemoveFreeSpace(sds s) {
    struct sdshdr *sh;

    // s 指的是 sdshdr 末尾的位置,即 sdshdr 的字符串的首地址
    // 所以这里 (s-(sizeof(struct sdshdr))) 正好是指向 sdshdr 的首地址
    sh = (void*) (s-(sizeof(struct sdshdr)));
    // 释放掉多余的空间
    sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);
    sh->free = 0;
    return sh->buf;
}

zrealloc函数会保存原来的字符串,然后释放老的空间,然后重新申请一个小一点的正好容下当前字符串的空间

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值