日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網(wǎng)站首頁 編程語言 正文

redis 為什么對數(shù)字/字符串a(chǎn)ppend操作后,編碼格式object encoding從int/embstr變成raw了

作者:liuhmmjj 更新時間: 2022-04-22 編程語言

不單單int編碼類型(type是string),進行字符串操作后,會自動轉(zhuǎn)碼為raw;對普通的短字符串(長度小于等于44個字節(jié))?進行append操作后,編碼格式也會發(fā)生改變(即使操作后長度還是小于等于44個字節(jié)也會由原來的embstr變成raw)!

embstr存儲形式將 RedisObject 對象頭和 SDS 對象連續(xù)存在一起,使用 malloc 方法一次分配。

redis 3.2之后empstr只能容納44字節(jié):

?????embstr的最小占用空間為19(16+3),而64-19-1(結(jié)尾的\0)=44,所以empstr只能容納44字節(jié)。

但是當執(zhí)行append命令之后,即使append之后的字符串長度小于等于44字節(jié)也會轉(zhuǎn)化為raw

例如:

?append源碼分析:

append命令執(zhí)行后會進入到 src/t_string.c下的appendCommand方法
void appendCommand(client *c) {
    size_t totlen;
    robj *o, *append;

    o = lookupKeyWrite(c->db,c->argv[1]);
    if (o == NULL) {
        /* Create the key */
        c->argv[2] = tryObjectEncoding(c->argv[2]);
        dbAdd(c->db,c->argv[1],c->argv[2]);
        incrRefCount(c->argv[2]);
        totlen = stringObjectLen(c->argv[2]);
    } else {
        /* Key exists, check type */
        if (checkType(c,o,OBJ_STRING))
            return;

        /* "append" is an argument, so always an sds */
        append = c->argv[2];
        totlen = stringObjectLen(o)+sdslen(append->ptr);
        if (checkStringLength(c,totlen) != C_OK)
            return;

        /* Append the value */
        o = dbUnshareStringValue(c->db,c->argv[1],o);
        o->ptr = sdscatlen(o->ptr,append->ptr,sdslen(append->ptr));
        totlen = sdslen(o->ptr);
    }
    signalModifiedKey(c,c->db,c->argv[1]);
    notifyKeyspaceEvent(NOTIFY_STRING,"append",c->argv[1],c->db->id);
    server.dirty++;
    addReplyLongLong(c,totlen);
}
打斷點會進入到上面的dbUnshareStringValue方法
robj *dbUnshareStringValue(redisDb *db, robj *key, robj *o) {
    serverAssert(o->type == OBJ_STRING);
    if (o->refcount != 1 || o->encoding != OBJ_ENCODING_RAW) {
        robj *decoded = getDecodedObject(o);
        o = createRawStringObject(decoded->ptr, sdslen(decoded->ptr));
        decrRefCount(decoded);
        dbOverwrite(db,key,o);
    }
    return o;
}

然后重點關(guān)注一下這一行:

o = createRawStringObject(decoded->ptr, sdslen(decoded->ptr));
robj *createRawStringObject(const char *ptr, size_t len) {
    return createObject(OBJ_STRING, sdsnewlen(ptr,len));
}

接著進入到createObject方法

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. */
    if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
        o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;
    } else {
        o->lru = LRU_CLOCK();
    }
    return o;
}
從這一行o->encoding = OBJ_ENCODING_RAW;可以看到創(chuàng)建的新object的編碼格式為raw類型。
總結(jié):在對embstr對象修改時其實都是新創(chuàng)建了一個raw對象,然后對raw對象進行修改,因此,當執(zhí)行append命令之后,即使append之后的字符串長度小于等于44字節(jié)也會轉(zhuǎn)化為raw

原文鏈接:https://blog.csdn.net/u014082714/article/details/122923849

欄目分類
最近更新