From a1b1c1ea3adb864c8c2e3feb4eaed890a9b505cf Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 16 Oct 2012 17:35:50 +0200 Subject: [PATCH] Fix MULTI / EXEC rendering in MONITOR output. Before of this commit it used to be like this: MULTI EXEC ... actual commands of the transaction ... Because after all that is the natural order of things. Transaction commands are queued and executed *only after* EXEC is called. However this makes debugging with MONITOR a mess, so the code was modified to provide a coherent output. What happens is that MULTI is rendered in the MONITOR output as far as possible, instead EXEC is propagated only after the transaction is executed, or even in the case it fails because of WATCH, so in this case you'll simply see: MULTI EXEC An empty transaction. --- src/multi.c | 11 ++++++++++- src/redis.c | 12 +++++++++--- src/redis.h | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/multi.c b/src/multi.c index eee9748c5..3846021b3 100644 --- a/src/multi.c +++ b/src/multi.c @@ -96,7 +96,7 @@ void execCommand(redisClient *c) { c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS); unwatchAllKeys(c); addReply(c,shared.nullmultibulk); - return; + goto handle_monitor; } /* Replicate a MULTI request now that we are sure the block is executed. @@ -132,6 +132,15 @@ void execCommand(redisClient *c) { * always send the MULTI command (we can't know beforehand if the * next operations will contain at least a modification to the DB). */ server.dirty++; + +handle_monitor: + /* Send EXEC to clients waiting data from MONITOR. We do it here + * since the natural order of commands execution is actually: + * MUTLI, EXEC, ... commands inside transaction ... + * Instead EXEC is flagged as REDIS_CMD_SKIP_MONITOR in the command + * table, and we do it here with correct ordering. */ + if (listLength(server.monitors) && !server.loading) + replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); } /* ===================== WATCH (CAS alike for MULTI/EXEC) =================== diff --git a/src/redis.c b/src/redis.c index 784d56e48..effab5ecc 100644 --- a/src/redis.c +++ b/src/redis.c @@ -110,6 +110,7 @@ struct redisCommand *commandTable; * t: Allow command while a slave has stale data but is not allowed to * server this data. Normally no command is accepted in this condition * but just a few. + * M: Do not automatically propagate the command on MONITOR. */ struct redisCommand redisCommandTable[] = { {"get",getCommand,2,"r",0,NULL,1,1,1,0,0}, @@ -216,7 +217,7 @@ struct redisCommand redisCommandTable[] = { {"lastsave",lastsaveCommand,1,"r",0,NULL,0,0,0,0,0}, {"type",typeCommand,2,"r",0,NULL,1,1,1,0,0}, {"multi",multiCommand,1,"rs",0,NULL,0,0,0,0,0}, - {"exec",execCommand,1,"s",0,NULL,0,0,0,0,0}, + {"exec",execCommand,1,"sM",0,NULL,0,0,0,0,0}, {"discard",discardCommand,1,"rs",0,NULL,0,0,0,0,0}, {"sync",syncCommand,1,"ars",0,NULL,0,0,0,0,0}, {"replconf",replconfCommand,-1,"ars",0,NULL,0,0,0,0,0}, @@ -1386,6 +1387,7 @@ void populateCommandTable(void) { case 'S': c->flags |= REDIS_CMD_SORT_FOR_SCRIPT; break; case 'l': c->flags |= REDIS_CMD_LOADING; break; case 't': c->flags |= REDIS_CMD_STALE; break; + case 'M': c->flags |= REDIS_CMD_SKIP_MONITOR; break; default: redisPanic("Unsupported command flag"); break; } f++; @@ -1461,7 +1463,7 @@ struct redisCommand *lookupCommandByCString(char *s) { } /* Propagate the specified command (in the context of the specified database id) - * to AOF, Slaves and Monitors. + * to AOF and Slaves. * * flags are an xor between: * + REDIS_PROPAGATE_NONE (no propagation of command at all) @@ -1491,8 +1493,12 @@ void call(redisClient *c, int flags) { /* Sent the command to clients in MONITOR mode, only if the commands are * not geneated from reading an AOF. */ - if (listLength(server.monitors) && !server.loading) + if (listLength(server.monitors) && + !server.loading && + !(c->cmd->flags & REDIS_CMD_SKIP_MONITOR)) + { replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); + } /* Call the command. */ redisOpArrayInit(&server.also_propagate); diff --git a/src/redis.h b/src/redis.h index 24efef57b..5e8df1460 100644 --- a/src/redis.h +++ b/src/redis.h @@ -86,6 +86,7 @@ #define REDIS_CMD_SORT_FOR_SCRIPT 256 /* "S" flag */ #define REDIS_CMD_LOADING 512 /* "l" flag */ #define REDIS_CMD_STALE 1024 /* "t" flag */ +#define REDIS_CMD_SKIP_MONITOR 2048 /* "M" flag */ /* Object types */ #define REDIS_STRING 0 -- GitLab