姬如祎 2024-04-26 18:50 采纳率: 0%
浏览 5

关于#redis#的问题,请各位专家解答!(语言-c语言)


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

    serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);

    if (!sdsEncodedObject(o)) return o;
     if (o->refcount > 1) return o;

    len = sdslen(s);
    if (len <= 20 && string2l(s,len,&value)) {
        if ((server.maxmemory == 0 ||
            !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) &&
            value >= 0 &&
            value < OBJ_SHARED_INTEGERS)
        {
            
            decrRefCount(o);
            incrRefCount(shared.integers[value]);
            return shared.integers[value];
        } else {
            if (o->encoding == OBJ_ENCODING_RAW) {
                sdsfree(o->ptr);
                o->encoding = OBJ_ENCODING_INT;
                o->ptr = (void*) value;
                return o;
            } else if (o->encoding == OBJ_ENCODING_EMBSTR) {
                decrRefCount(o);
                return createStringObjectFromLongLongForValue(value);
            }
        }
    }

    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) {
        robj *emb;

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

    trimStringObjectIfNeeded(o);
    return o;
}
o->ptr = (void*) value;
return o;

上面的这段代码为什么可以这么写?
具体位置在:

if (len <= 20 && string2l(s,len,&value)) 下的
if (o->encoding == OBJ_ENCODING_RAW)

  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-26 18:50
    关注

    引自免费微信小程序:皆我百晓生

    在 Redis 的源码中,tryObjectEncoding 函数用于尝试对字符串对象进行编码优化,以节省内存空间。这里涉及到了 Redis 字符串对象的两种主要编码方式:OBJ_ENCODING_RAWOBJ_ENCODING_INT

    当字符串长度小于等于 20,并且可以成功转换为一个长整型数字(string2l 成功),并且满足其他条件时,Redis 可能会将字符串对象转换为整型对象。这样做的目的是为了利用更少的空间存储数据,因为整型对象只需要指向一个共享的整型值,而不是复制整个字符串。

    下面是相关代码段的详细解释:

    1. 判断字符串是否已经使用了最高效的编码:

      if (!sdsEncodedObject(o)) return o;
      
    2. 如果字符串对象被多个地方引用,不进行优化,因为改变其编码可能会影响其他引用:

      if (o->refcount > 1) return o;
      
    3. 当字符串长度小于等于 20 并且可以转换为长整型时:

      if (len <= 20 && string2l(s,len,&value)) {
          ...
      }
      
    4. 检查是否可以使用共享整数池(如果有足够大的内存限制):

      if ((server.maxmemory == 0 ||
             !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) &&
          value >= 0 &&
          value < OBJ_SHARED_INTEGERS)
      
    5. 如果可以使用共享整数,释放原始对象并返回共享整数对象:

      decrRefCount(o);
      incrRefCount(shared.integers[value]);
      return shared.integers[value];
      
    6. 如果不能使用共享整数但当前编码是 OBJ_ENCODING_RAW,则将字符串转换为整型编码:

      else if (o->encoding == OBJ_ENCODING_RAW) {
          sdsfree(o->ptr);
          o->encoding = OBJ_ENCODING_INT;
          o->ptr = (void*) value;
          return o;
      }
      

    这里的关键在于 o->ptr = (void*) value; 这一行。在 C 语言中,可以通过 (void*) 来强制类型转换。由于 value 是长整型变量,将其赋值给 o->ptr 后,o->ptr 就变成了指向整型值的指针。这使得字符串对象 o 转变为一个整型对象,不再存储字符串,而是直接指向整数值。

    注意,这样做有一个前提,即 o->encoding 必须已经是 OBJ_ENCODING_RAW,表示原始未压缩的字符串格式。这是因为只有在这种情况下,Redis 才允许将字符串内容替换为整型值。如果 o->encoding 不是 OBJ_ENCODING_RAW,那么 Redis 会选择创建一个新的嵌入式字符串对象(createEmbeddedStringObject)并返回它,而不是直接修改 o->ptr

    总之,在这个上下文中,通过 (void*) 类型转换,Redis 将字符串对象的内部存储从原始字符串转为整型指针,从而实现了对象编码的优化。这样做的目的是为了节省内存,特别是当字符串内容可以被简单地表示为一个整数时。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月26日

悬赏问题

  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失