在我们安装好redis之后,屏幕上会显示
https://github.com/redis/redis/pull/9898
当我们替换dict.c的pr的时候,运行make test发现老是报错,说明代码是问题的,于是就根据make test进行一下定位。
第一次make test
第二次make test
第三次make test
可以看到主要报错的日志就是Unknown subcommand or wrong number of arguments for ‘set’,但是出问题的命令是随机的。
可以看到redis中只有一个地方有这个日志打印
/* Add a suggestive error reply.
* This function is typically invoked by from commands that support
* subcommands in response to an unknown subcommand or argument error. */
void addReplySubcommandSyntaxError(client *c) {
sds cmd = sdsnew((char*) c->argv[0]->ptr);
sdstoupper(cmd);
addReplyErrorFormat(c,
"Unknown subcommand or wrong number of arguments for '%s'. Try %s HELP.",
(char*)c->argv[1]->ptr,cmd);
sdsfree(cmd);
}
OBJECT IDLETIME1 name 1000
所以是lookupCommand为空,
struct redisCommand *lookupCommand(robj **argv, int argc) {
return lookupCommandLogic(server.commands,argv,argc);
}
所以应该师server.commands中没有加载入正确的命令
有一个方法populateCommandTable在initServerConfig中加载命令,initServerConfig又在server.c的main方法中被调用。
/* Populates the Redis Command Table starting from the hard coded list
* we have on top of server.c file. */
void populateCommandTable(void) {
int j;
int numcommands = sizeof(redisCommandTable)/sizeof(struct redisCommand);
for (j = 0; j < numcommands; j++) {
struct redisCommand *c = redisCommandTable+j;
int retval1, retval2;
/* Translate the command string flags description into an actual
* set of flags. */
parseCommandFlags(c,c->sflags);
if (!(c->flags & CMD_SENTINEL) && server.sentinel_mode)
continue;
if (c->flags & CMD_ONLY_SENTINEL && !server.sentinel_mode)
continue;
populateCommandStructure(c);
retval1 = dictAdd(server.commands, sdsnew(c->name), c);
/* Populate an additional dictionary that will be unaffected
* by rename-command statements in redis.conf. */
retval2 = dictAdd(server.orig_commands, sdsnew(c->name), c);
serverAssert(retval1 == DICT_OK && retval2 == DICT_OK);
}
}
我们在源代码中的dictfind中打断点,发现启动的时候没有调用到dictFind,所以问题不会出现在这里。于是可以判断问题还是在,后面传参或者查找的时候失败了
/* Now lookup the command and check ASAP about trivial error conditions
* such as wrong arity, bad command name and so forth. */
c->cmd = c->lastcmd = lookupCommand(c->argv,c->argc);
if (!c->cmd) {
if (lookupCommandBySds(c->argv[0]->ptr)) {
/* If we can't find the command but argv[0] by itself is a command
* it means we're dealing with an invalid subcommand. Print Help. */
addReplySubcommandSyntaxError(c);
struct redisCommand *lookupCommand(robj **argv, int argc) {
return lookupCommandLogic(server.commands,argv,argc);
}
struct redisCommand *lookupCommandLogic(dict *commands, robj **argv, int argc) {
struct redisCommand *base_cmd = dictFetchValue(commands, argv[0]->ptr);
int has_subcommands = base_cmd && base_cmd->subcommands_dict;
if (argc == 1 || !has_subcommands) {
/* Note: It is possible that base_cmd->proc==NULL (e.g. CONFIG) */
return base_cmd;
} else {
/* Note: Currently we support just one level of subcommands */
return dictFetchValue(base_cmd->subcommands_dict, argv[1]->ptr);
}
}
struct redisCommand {
/* Declarative data */
char *name;
redisCommandProc *proc;
int arity;
char *sflags; /* Flags as string representation, one char per flag. */
keySpec key_specs_static[STATIC_KEY_SPECS_NUM];
/* Use a function to determine keys arguments in a command line.
* Used for Redis Cluster redirect (may be NULL) */
redisGetKeysProc *getkeys_proc;
/* Array of subcommands (may be NULL) */
struct redisCommand *subcommands;
/* Runtime data */
uint64_t flags; /* The actual flags, obtained from the 'sflags' field. */
/* What keys should be loaded in background when calling this command? */
long long microseconds, calls, rejected_calls, failed_calls;
int id; /* Command ID. This is a progressive ID starting from 0 that
is assigned at runtime, and is used in order to check
ACLs. A connection is able to execute a given command if
the user associated to the connection has this command
bit set in the bitmap of allowed commands. */
keySpec *key_specs;
keySpec legacy_range_key_spec; /* The legacy (first,last,step) key spec is
* still maintained (if applicable) so that
* we can still support the reply format of
* COMMAND INFO and COMMAND GETKEYS */
int key_specs_num;
int key_specs_max;
int movablekeys; /* See populateCommandMovableKeys */
dict *subcommands_dict;
struct redisCommand *parent;
};