最近在改造redis,有必要熟悉一下redis一部分命令的执行过程。先从熟悉命令表开始吧。
参考GitHub上的源码解析,自己再熟悉一下。
命令表如下:
struct redisCommand redisCommandTable[] = {
{"get",getCommand,2,"r",0,NULL,1,1,1,0,0},
{"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},
{"setnx",setnxCommand,3,"wm",0,NULL,1,1,1,0,0},
{"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},
{"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0},
{"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0},
{"strlen",strlenCommand,2,"r",0,NULL,1,1,1,0,0},
{"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0},
{"exists",existsCommand,2,"r",0,NULL,1,1,1,0,0},
{"setbit",setbitCommand,4,"wm",0,NULL,1,1,1,0,0},
{"getbit",getbitCommand,3,"r",0,NULL,1,1,1,0,0},
{"setrange",setrangeCommand,4,"wm",0,NULL,1,1,1,0,0},
{"getrange",getrangeCommand,4,"r",0,NULL,1,1,1,0,0},
{"substr",getrangeCommand,4,"r",0,NULL,1,1,1,0,0},
{"incr",incrCommand,2,"wm",0,NULL,1,1,1,0,0},
//以上展示部分命令函数
}
以{“set”,setCommand,-3,”wm”,0,NULL,1,1,1,0,0}为例来说明各项参数的含义:
name: 命令的名字
function:命令对应的函数,一个指向命令的实现函数的指针
arity: 参数的数量。可以用 -N 表示 >= N
slfags: 字符串形式的 FLAG ,用来计算以下的真实 FLAG
flag: 位掩码形式的 FLAG ,根据 字符串slfags计算得出,命令的 FLAG 首先由 SFLAG 域设置,之后 populateCommandTable() 函数从 sflags 属性中计算出真正的 FLAG 到 flags 属性中。
get_keys_proc: 一个可选的函数,用于从命令中取出 key ,仅在以下三个参数都不足以表示 key 参数时使用
first_key_index: 第一个 key的位置
last_key_index: 最后一个 key的位置
key_step: 从 first 参数和 last 参数之间,所有 key 的步数(step),不同命令的step可能不同
microseconds: 执行这个命令耗费的时间(微妙表示),初始化为0
calls: 命令被执行的总次数,初始化为0
各flag含义解析:
w: 写入命令,可能会修改 key space(涉及到键值对的更新操作)
r: 读命令,不修改 key space
m:可能会占用大量内存的命令,调用时对内存占用进行检查
a: 管理用途的命令,比如 SAVE 和 SHUTDOWN
p: 发布/订阅相关的命令
f: 无视 server.dirty ,强制复制这个命令。
s:不允许在脚本中使用的命令
R: 随机命令。命令是非确定性的:对于同样的命令,同样的参数,同样的键,结果可能不同。比如 SPOP 和 RANDOMKEY 就是这样的例子。
S: 如果命令在 Lua 脚本中执行,那么对输出进行排序,从而得出确定性的输出。
l:允许在载入数据库时使用的命令。
t: 允许在附属节点带有过期数据时执行的命令。 这类命令很少有,只有几个。
M:不要在 MONITOR 模式下自动广播的命令。
k:为这个命令执行一个显式的 ASKING ,使得在集群模式下,一个被标示为 importing 的槽可以接收这命令。
接下来分析setcommand的执行流程。