Commit e7a61d28 authored by antirez's avatar antirez
Browse files

API to lookup commands with their original name.

A new server.orig_commands table was added to the server structure, this
contains a copy of the commant table unaffected by rename-command
statements in redis.conf.

A new API lookupCommandOrOriginal() was added that checks both tables,
new first, old later, so that rewriteClientCommandVector() and friends
can lookup commands with their new or original name in order to fix the
client->cmd pointer when the argument vector is renamed.

This fixes the segfault of issue #986, but does not fix a wider range of
problems resulting from renaming commands that actually operate on data
and are registered into the AOF file or propagated to slaves... That is
command renaming should be handled with care.
parent 78bae8b0
...@@ -1259,7 +1259,7 @@ void rewriteClientCommandVector(redisClient *c, int argc, ...) { ...@@ -1259,7 +1259,7 @@ void rewriteClientCommandVector(redisClient *c, int argc, ...) {
/* Replace argv and argc with our new versions. */ /* Replace argv and argc with our new versions. */
c->argv = argv; c->argv = argv;
c->argc = argc; c->argc = argc;
c->cmd = lookupCommand(c->argv[0]->ptr); c->cmd = lookupCommandOrOriginal(c->argv[0]->ptr);
redisAssertWithInfo(c,NULL,c->cmd != NULL); redisAssertWithInfo(c,NULL,c->cmd != NULL);
va_end(ap); va_end(ap);
} }
...@@ -1277,7 +1277,7 @@ void rewriteClientCommandArgument(redisClient *c, int i, robj *newval) { ...@@ -1277,7 +1277,7 @@ void rewriteClientCommandArgument(redisClient *c, int i, robj *newval) {
/* If this is the command name make sure to fix c->cmd. */ /* If this is the command name make sure to fix c->cmd. */
if (i == 0) { if (i == 0) {
c->cmd = lookupCommand(c->argv[0]->ptr); c->cmd = lookupCommandOrOriginal(c->argv[0]->ptr);
redisAssertWithInfo(c,NULL,c->cmd != NULL); redisAssertWithInfo(c,NULL,c->cmd != NULL);
} }
} }
......
...@@ -1185,6 +1185,7 @@ void initServerConfig() { ...@@ -1185,6 +1185,7 @@ void initServerConfig() {
* initial configuration, since command names may be changed via * initial configuration, since command names may be changed via
* redis.conf using the rename-command directive. */ * redis.conf using the rename-command directive. */
server.commands = dictCreate(&commandTableDictType,NULL); server.commands = dictCreate(&commandTableDictType,NULL);
server.orig_commands = dictCreate(&commandTableDictType,NULL);
populateCommandTable(); populateCommandTable();
server.delCommand = lookupCommandByCString("del"); server.delCommand = lookupCommandByCString("del");
server.multiCommand = lookupCommandByCString("multi"); server.multiCommand = lookupCommandByCString("multi");
...@@ -1374,7 +1375,7 @@ void populateCommandTable(void) { ...@@ -1374,7 +1375,7 @@ void populateCommandTable(void) {
for (j = 0; j < numcommands; j++) { for (j = 0; j < numcommands; j++) {
struct redisCommand *c = redisCommandTable+j; struct redisCommand *c = redisCommandTable+j;
char *f = c->sflags; char *f = c->sflags;
int retval; int retval1, retval2;
while(*f != '\0') { while(*f != '\0') {
switch(*f) { switch(*f) {
...@@ -1395,8 +1396,11 @@ void populateCommandTable(void) { ...@@ -1395,8 +1396,11 @@ void populateCommandTable(void) {
f++; f++;
} }
retval = dictAdd(server.commands, sdsnew(c->name), c); retval1 = dictAdd(server.commands, sdsnew(c->name), c);
assert(retval == DICT_OK); /* Populate an additional dictionary that will be unaffected
* by rename-command statements in redis.conf. */
retval2 = dictAdd(server.orig_commands, sdsnew(c->name), c);
redisAssert(retval1 == DICT_OK && retval2 == DICT_OK);
} }
} }
...@@ -1464,6 +1468,20 @@ struct redisCommand *lookupCommandByCString(char *s) { ...@@ -1464,6 +1468,20 @@ struct redisCommand *lookupCommandByCString(char *s) {
return cmd; return cmd;
} }
/* Lookup the command in the current table, if not found also check in
* the original table containing the original command names unaffected by
* redis.conf rename-command statement.
*
* This is used by functions rewriting the argument vector such as
* rewriteClientCommandVector() in order to set client->cmd pointer
* correctly even if the command was renamed. */
struct redisCommand *lookupCommandOrOriginal(sds name) {
struct redisCommand *cmd = dictFetchValue(server.commands, name);
if (!cmd) cmd = dictFetchValue(server.orig_commands,name);
return cmd;
}
/* Propagate the specified command (in the context of the specified database id) /* Propagate the specified command (in the context of the specified database id)
* to AOF and Slaves. * to AOF and Slaves.
* *
......
...@@ -495,7 +495,8 @@ typedef struct redisOpArray { ...@@ -495,7 +495,8 @@ typedef struct redisOpArray {
struct redisServer { struct redisServer {
/* General */ /* General */
redisDb *db; redisDb *db;
dict *commands; /* Command table hash table */ dict *commands; /* Command table */
dict *orig_commands; /* Command table before command renaming. */
aeEventLoop *el; aeEventLoop *el;
unsigned lruclock:22; /* Clock incrementing every minute, for LRU */ unsigned lruclock:22; /* Clock incrementing every minute, for LRU */
unsigned lruclock_padding:10; unsigned lruclock_padding:10;
...@@ -945,6 +946,7 @@ int processCommand(redisClient *c); ...@@ -945,6 +946,7 @@ int processCommand(redisClient *c);
void setupSignalHandlers(void); void setupSignalHandlers(void);
struct redisCommand *lookupCommand(sds name); struct redisCommand *lookupCommand(sds name);
struct redisCommand *lookupCommandByCString(char *s); struct redisCommand *lookupCommandByCString(char *s);
struct redisCommand *lookupCommandOrOriginal(sds name);
void call(redisClient *c, int flags); void call(redisClient *c, int flags);
void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int flags); void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int flags);
void alsoPropagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int target); void alsoPropagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int target);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment