1、开始之前先看看一个封装命令的结构体
typedef void redisCommandProc(client *c);
typedef int *redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
struct redisCommand {
char *name;命令的名称
redisCommandProc *proc;指向命令实际执行的函数的指针
int arity;参数个数,-N表示大于等于N
char *sflags;
uint64_t flags;
redisGetKeysProc *getkeys_proc;
int firstkey;
int lastkey;
int keystep;
long long microseconds, calls;该命令的总的执行时间,和总的调用次数
int id;
};
2、下面是string所有的命令
{"get",getCommand,2,"read-only fast @string",0,NULL,1,1,1,0,0,0}
{"set",setCommand,-3,"write use-memory @string",0,NULL,1,1,1,0,0,0}
{"setnx",setnxCommand,3,"write use-memory fast @string",0,NULL,1,1,1,0,0,0}
{"setex",setexCommand,4,"write use-memory @string",0,NULL,1,1,1,0,0,0},
{"psetex",psetexCommand,4,"write use-memory @string",0,NULL,1,1,1,0,0,0},
{"append",appendCommand,3,"write use-memory fast @string",0,NULL,1,1,1,0,0,0},
{"strlen",strlenCommand,2,"read-only fast @string",0,NULL,1,1,1,0,0,0},
{"setrange",setrangeCommand,4,"write use-memory @string",0,NULL,1,1,1,0,0,0},
{"getrange",getrangeCommand,4,"read-only @string",0,NULL,1,1,1,0,0,0},
{"substr",getrangeCommand,4,"read-only @string",0,NULL,1,1,1,0,0,0},
{"incr",incrCommand,2,"write use-memory fast @string",0,NULL,1,1,1,0,0,0},
{"decr",decrCommand,2,"write use-memory fast @string",0,NULL,1,1,1,0,0,0},
{"mget",mgetCommand,-2,"read-only fast @string",0,NULL,1,-1,1,0,0,0},
{"incrby",incrbyCommand,3,"write use-memory fast @string",0,NULL,1,1,1,0,0,0},
{"decrby",decrbyCommand,3,"write use-memory fast @string",0,NULL,1,1,1,0,0,0},
{"incrbyfloat",incrbyfloatCommand,3,"write use-memory fast @string",0,NULL,1,1,1,0,0,0},
{"getset",getsetCommand,3,"write use-memory fast @string",0,NULL,1,1,1,0,0,0},
{"mset",msetCommand,-3,"write use-memory @string",0,NULL,1,-1,2,0,0,0},
{"msetnx",msetnxCommand,-3,"write use-memory @string",0,NULL,1,-1,2,0,0,0},
{"stralgo",stralgoCommand,-2,"read-only @string",0,lcsGetKeys,0,0,0,0,0,0}
3、具体实现
设置字符串
setCommand、setnxCommand、setexCommand、psetexCommand都是由setGenericCommand函数实现
批量设置字符串
msetCommand、msetnxCommand是由msetGenericCommand函数实现
获取字符串
getCommand、getsetCommand是由getGenericCommand函数实现
getrangeCommand
批量获取字符串
mgetCommand
计数器命令
incrCommand、decrCommand、incrbyCommand、decrbyCommand是由incrDecrCommand函数实现
incrbyfloatCommand
修改字符串
appendCommand
setrangeCommand
获取字符串的长度
strlenCommand
其他
stralgoCommand
是不是发现其实string的实现,一共也就是11个函数
4、设置字符串
有哪些参数呢?
key、value、NX、XX、EX、PX、KEEPTTL
对应有几种标志
#define OBJ_SET_NO_FLAGS 0 默认
#define OBJ_SET_NX (1<<0) setnx、set key value nx key不存在时设置
#define OBJ_SET_XX (1<<1) set key value xx key存在时设置
#define OBJ_SET_EX (1<<2)
#define OBJ_SET_PX (1<<3) /* Set if time in ms in given */
#define OBJ_SET_KEEPTTL (1<<4) /* Set and keep the ttl */
1、解析参数,并赋值
2、通过tryObjectEncoding对value进行编码优化,目的是节省内存
a、先看编码是不是embstr或raw,不是不做优化,直接返回
b、如果refcount大于1(共享对象),不做优化,直接返回
c、根据sds的类型,计算出已经使用的字节数
d、已经使用的字节数小于等于20,并且字符可以转为数值
e、服务器没有设置最大内存限制或淘汰策略不是lru(lfu)并且数值范围在0-9999,将
该robj的引用减一,将共享对象池中的值引用加1,返回共享对象池中的值。
f、如果robj的encoding是raw,释放原来的指针指向的字符数组,encoding设置为int,
直接将该值赋给指针ptr。
g、如果robj的encoding为embstr,将该robj的引用减一,如果服务器没有设置最大内存
限制或淘汰策略不是lru(lfu)并且数值范围在0-9999,将共享对象池中的值引用加1,返
回共享对象池中的值;如果值在long的范围内,创建一个robj,encoding为int,ptr为该
值,否则就创建一个robj,encoding为raw,ptr指向sds的字符数组的地址。
h、如果字节数小于等于44,并且encoding为embstr,直接返回。
i、否则,分配一个sizeof(robj)+sizeof(struct sdshdr8)+len+1大小的内存,并初
始化,将该robj的引用减一,返回该robj。
j、如果encoding为raw并且sds的可用长度大于已用长度的十分之一,释放多余的空间,结束
3、先看是否设置过期,将过期时间进行转化校验,如果是秒,需要*1000;如果有参数NX并且key
已经存在,回复错误;如果有参数XX并且key不存在,回复错误,结束
4、通过genericSetKey设置key,key不存在dbAdd,存在dbOverwrite,将值的引用加1,如
果设置了keepttl,删除key的过期时间;如果signal为1,发送一个修改key的信号出去
5、如果有,则设置过期时间(当前时间+传入的毫秒值),
6、触发对应事件
7、如果有,触发过期对应的事件
8、回复,结束
5、其他
robj的默认初始化是什么?