set
用来存储string的类型数据
> set key hello
OK
复制代码
get
来获取string类型的值
> get key
"hello"
复制代码
如果在
set
执行的时候,key已经存在,则会覆盖原有key的值
> set key anotherValue
OK
> get key
"anotherValue"
复制代码
set命令执行追踪
redis.c
中数组 redisCommandTable 为所有暴漏出去的命令列表,以及实现命令的函数指针
struct redisCommand redisCommandTable[] = {
...
{"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},
{"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},
...
}
复制代码
从这里可以看到 setCommand 即为 set方法的入口。
Code.SLICE.source("c->argv[2] = tryObjectEncoding(c->argv[2]);")
.interpretation("在对set的格式做完语法校验,同时取得相应的命令属于 NX/XX/EX/PX/直接set之后,根据value来获取编码");
Code.SLICE.source("setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL);")
.interpretation("根据实际情况存储k-v对");
复制代码
在执行Set之前,redis并不是直接将原有传入的string储存,而是先选择了做一层编码,编码之后再来存
Code.SLICE.source("len = sdslen(s);")
.interpretation("获取要存储的字符串值的长度,s取值即 redisObject指向的 数据字节指针");
Code.SLICE.source("if (len <= 20 && string2l(s,len,&value))")
.interpretation("判断字符串的长度如果小于20并且能够转成long 类型,执行转成long 的逻辑,并结果存储到value");
//...
Code.SLICE.source(" o->encoding = OBJ_ENCODING_INT;\n" +
" o->ptr = (void*) value;")
.interpretation("判定好是可以转成long则设定编码方式为int,同时数据指针就直接存储值");
//...
Code.SLICE.source("if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) ")
.interpretation("如果字符串长度满足emb的长度条件(44),使用emb编码,使得通过一次内存分配函数的调用就可以拿到连续的内存空间存储 redisObject和 数据 sdshdr");
//...
Code.SLICE.source(" emb = createEmbeddedStringObject(s,sdslen(s));")
.interpretation("将值使用emb编码后再返回");
//...
Code.SLICE.source("if (o->encoding == OBJ_ENCODING_RAW &&\n" +
" sdsavail(s) > len/10)\n" +
" {\n" +
" o->ptr = sdsRemoveFreeSpace(o->ptr);\n" +
" }")
.interpretation("如果超过了emb限制,则尽量的去较少浪费的空间,将原始的内容直接返回");
//...
复制代码
对于 string 来说,编码是根据value的长度来按照不同的编码方式处理
- 小于等于20 并且能够转换成long,则存储成long类型的数字,指定编码为 OBJ_ENCODING_INT
- 如果长度小于44,则创建EmbeddedString,指定编码为 OBJ_ENCODING_EMBSTR
- 其它情况,指定编码为 OBJ_ENCODING_RAW
在转码过程中,传进来的数据会被转成 redisObject
typedef struct redisObject {
unsigned type:4; //指string/list/hash/zset/set
unsigned encoding:4; //数据自己的编码格式
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount; //数据被引用的次数,为0表示可以安全回收这个对象
void *ptr; //对象数据
} robj;
复制代码