I'm learning the data structure of redis. When I use command [memory usage xxx] to analyse memory usage of a key, I found that the key using raw encoding takes up two bytes more than using embstr encoding. So I read the source code and I found the following code in method [size_t objectComputeSize(robj *o, size_t sample_size);]:

if (o->type == OBJ_STRING) {
        if(o->encoding == OBJ_ENCODING_INT) {
            asize = sizeof(*o);
        } else if(o->encoding == OBJ_ENCODING_RAW) {
            asize = sdsZmallocSize(o->ptr)+sizeof(*o);
        } else if(o->encoding == OBJ_ENCODING_EMBSTR) {
            asize = sdslen(o->ptr)+2+sizeof(*o);
        } else {
            serverPanic("Unknown string encoding");
        }
}

I want to know what + 2 means in the expression that computes memory when using embstr encoding. I found embstr encoding uses sdshdr8, its fixed extra byte should be 4. Is this a bug? My version is redis 4.0, thanks.

Comment From: sundb

2 contain header of sds(1byte) and end of sds(\0). This code on unstable branch has been modified to a new way of calculating.

Comment From: ertong0129

2 contain header of sds(1byte) and end of sds(\0).

Thanks for your answer! But I still don't know why the length of sds head is 1. And I think it is should be 3.

struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
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;
}

Comment From: sundb

@ertong0129 It was indeed wrong, so it was discussed in #6263, and fixed in #9095.

Comment From: ertong0129

@ertong0129 It was indeed wrong, so it was discussed in #6263, and fixed in #9095.

I got it,thank you very much!