不单单int编码类型(type是string),进行字符串操作后,会自动转码为raw;对普通的短字符串(长度小于等于44个字节) 进行append操作后,编码格式也会发生改变(即使操作后长度还是小于等于44个字节也会由原来的embstr变成raw)!
embstr存储形式将 RedisObject 对象头和 SDS 对象连续存在一起,使用 malloc 方法一次分配。
redis 3.2之后empstr只能容纳44字节:
embstr的最小占用空间为19(16+3),而64-19-1(结尾的)=44,所以empstr只能容纳44字节。
但是当执行append命令之后,即使append之后的字符串长度小于等于44字节也会转化为raw。
例如:
append源码分析:
append命令执行后会进入到 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) { 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 { if (checkType(c,o,OBJ_STRING)) return; append = c->argv[2]; totlen = stringObjectLen(o)+sdslen(append->ptr); if (checkStringLength(c,totlen) != C_OK) return; 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;}
然后重点关注一下这一行:
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; 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;可以看到创建的新object的编码格式为raw类型。总结:在对embstr对象修改时其实都是新创建了一个raw对象,然后对raw对象进行修改,因此,当执行append命令之后,即使append之后的字符串长度小于等于44字节也会转化为raw