Redis 6.2 redis创建一个字符串对象是如何选择合适的编码方式(源码)

通过Redis 6.2 key的创建SDS(源码)知道String在redis中是有多种编码方式存储的,但是实际上创建一个字符串对象是如何选择编码方式的,下面是源码

*RM_CreateString(创建一个字符串对象的入口方法)

/* Create a new module string object. The returned string must be freed
 * with RedisModule_FreeString(), unless automatic memory is enabled.
 *创建一个新的模块字符串对象。必须使用 RedisModule_FreeString() 释放返回的字符串,除非启用了自动内存
 * The string is created by copying the `len` bytes starting
 * at `ptr`. No reference is retained to the passed buffer.
 *该字符串是通过复制从 `ptr` 开始的 `len` 字节来创建的。不保留对传递缓冲区的引用
 * The module context 'ctx' is optional and may be NULL if you want to create
 * a string out of the context scope. However in that case, the automatic
 * memory management will not be available, and the string memory must be
 * managed manually.
 *模块上下文 'ctx' 是可选的,如果您想在上下文范围之外创建字符串,它可能为 NULL。但是在这种情况下,自动内存管理将不可用,必须手动管理字符串内存
 */
RedisModuleString *RM_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len) {
    RedisModuleString *o = createStringObject(ptr,len);
    if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_STRING,o);
    return o;
}

*createStringObject(选择String类型的编码方式)

/* Create a string object with EMBSTR encoding if it is smaller than
 * OBJ_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
 * used.
 *如果小于OBJ_ENCODING_EMBSTR_SIZE_LIMIT(值是44字节的字符串),则创建一个带有EMBSTR编码的字符串对象,否则使用RAW编码
 *
 * The current limit of 44 is chosen so that the biggest string object
 * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc.
 *选择当前限制 44 以便我们分配为 EMBSTR 的最大字符串对象仍然适合 jemalloc 的 64 字节领域
 */
#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
        return createEmbeddedStringObject(ptr,len);
    else
        return createRawStringObject(ptr,len);
}

从判断可以看出来,是OBJ_ENCODING_EMBSTR_SIZE_LIMIT 的大小决定是按哪种编码方式,目前是44个字节

createRawStringObject(OBJ_ENCODING_RAW 编码方式)

/* Create a string object with encoding OBJ_ENCODING_RAW, that is a plain
 * string object where o->ptr points to a proper sds string.
 *创建一个编码为 OBJ_ENCODING_RAW 的字符串对象,这是一个普通的字符串对象,其中 o->ptr 指向一个正确的 sds 字符串
 */
robj *createRawStringObject(const char *ptr, size_t len) {
    return createObject(OBJ_STRING, sdsnewlen(ptr,len));
}
//创建新的sds
sds sdsnewlen(const void *init, size_t initlen) {
    return _sdsnewlen(init, initlen, 0);
}
//根据type创建存储对象,其中*ptr根据上面的sdsnewlen知道是新的sds
robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));
    o->type = type;
    o->encoding = OBJ_ENCODING_RAW;
    o->ptr = ptr;
    o->refcount = 1;

    /* Set the LRU to the current lruclock (minutes resolution), or
     * alternatively the LFU counter. 
	将 LRU 设置为当前的 lruclock(分钟分辨率),或者 LFU 计数器*/
    if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
        o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;
    } else {
        o->lru = LRU_CLOCK();
    }
    return o;
}

createEmbeddedStringObject(OBJ_ENCODING_EMBSTR 编码方式)

/* Create a string object with encoding OBJ_ENCODING_EMBSTR, that is
 * an object where the sds string is actually an unmodifiable string
 * allocated in the same chunk as the object itself.
 *创建一个编码为 OBJ_ENCODING_EMBSTR 的字符串对象,即一个对象,其中 sds 字符串实际上是一个不可修改的字符串,与对象本身分配在同一块中
 */
robj *createEmbeddedStringObject(const char *ptr, size_t len) {
    robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1);
    struct sdshdr8 *sh = (void*)(o+1);

    o->type = OBJ_STRING;
    o->encoding = OBJ_ENCODING_EMBSTR;
    o->ptr = sh+1;
    o->refcount = 1;
    if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
        o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;
    } else {
        o->lru = LRU_CLOCK();
    }

    sh->len = len;
    sh->alloc = len;
    sh->flags = SDS_TYPE_8;
    if (ptr == SDS_NOINIT)
        sh->buf[len] = '\0';
    else if (ptr) {
        memcpy(sh->buf,ptr,len);
        sh->buf[len] = '\0';
    } else {
        memset(sh->buf,0,len+1);
    }
    return o;
}

这里robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1)
将robj和sds放在一个连续的内存块中分配,有利于减少内存碎片

• 16个字节的robj结构。
• 3个字节的sdshdr8头。
• 最多44个字节的sds字符数组。
• 1个NULL结束符。

加起来一共不超过64字节(16+3+44+1),因此这样的一个短字符串可以完全分配在一个64字节长度的内存块中,而且前面创建时对长度也加了限制,44字节,所以不会太长

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值