单值的情况下可以使用set命令。
set key value
set命令在源码会直接调用setCommand
//set命令 set key value
void setCommand(client *c) {
....
//值的编码
c->argv[2] = tryObjectEncoding(c->argv[2]);
setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL);
}
tryObjectEncoding会对传进来的值进行编码,如果小于20个字节采用int编码编码成64位,如果是小于44个字节会采用EMBSTR编码,比44字节大会采用raw编码
这三种编码模式的示意图:
int编码的具体实现:
//编码stirng类型目的是为了节省内存空间
robj *tryObjectEncoding(robj *o) {
long value;
sds s = o->ptr;
size_t len;
//确认是string类型
serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
//如果不是RAW也不是EMBSTR编码,直接返回
if (!sdsEncodedObject(o)) return o;
//如果是共享的对象,直接返回
if (o->refcount > 1) return o;
//少于20个子节点时候采用INT编码为LONG整型
len = sdslen(s);
if (len <= 20 && string2l(s,len,&value)) {
........
}
//如果长度小于OBJ_ENCODING_EMBSTR_SIZE_LIMIT的RAW编码,
//采用EMBSTR编码会更高效
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;
}
错误检查完成,把key value的键值对插入进对应db的字典里面
//把键值对添加进redis,是db的字典里面查找,如果没有直接添加进去,如果存在
//直接修改
void genericSetKey(client *c, redisDb *db, robj *key, robj *val, int keepttl, int signal) {
if (lookupKeyWrite(db,key) == NULL) {
dbAdd(db,key,val);
} else {
dbOverwrite(db,key,val);
}
incrRefCount(val);
if (!keepttl) removeExpire(db,key);
if (signal) signalModifiedKey(c,db,key);
}
//根据key查找redisobj对象
robj *lookupKey(redisDb *db, robj *key, int flags) {
dictEntry *de = dictFind(db->dict,key->ptr);
if (de) {
robj *val = dictGetVal(de);
/* Update the access time for the ageing algorithm.
* Don't do it if we have a saving child, as this will trigger
* a copy on write madness. */
if (!hasActiveChildProcess() && !(flags & LOOKUP_NOTOUCH)){
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
updateLFU(val);
} else {
val->lru = LRU_CLOCK();
}
}
return val;
} else {
return NULL;
}
}
如果是一个10字节的整数,会采用INT整型编码,最后的使用的内存空间会变成64个字节。
分为三部分:
int编码: 元数据8B + INT 8b
long型整数: key 8 字节 + value 8个字节
dictEntry: key 8B + value 8B + next 8B
因为采用的是jemalloc的内存分配,jemalloc内存分配的时候会根据申请的字节数N,找一个比N大,但是最接近N的2次幂作为分配的空间,所以dictEntry最后是32位。
三部分加起来的总和是64位。