summaryrefslogtreecommitdiff
path: root/src/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/multi.c')
-rwxr-xr-xsrc/multi.c41
1 files changed, 19 insertions, 22 deletions
diff --git a/src/multi.c b/src/multi.c
index 2b7e6b552..cd07971e2 100755
--- a/src/multi.c
+++ b/src/multi.c
@@ -103,13 +103,11 @@ void discardCommand(redisClient *c) {
/* Send a MULTI command to all the slaves and AOF file. Check the execCommand
* implementation for more information. */
-void execCommandReplicateMulti(redisClient *c) {
+void execCommandPropagateMulti(redisClient *c) {
robj *multistring = createStringObject("MULTI",5);
- if (server.aof_state != REDIS_AOF_OFF)
- feedAppendOnlyFile(server.multiCommand,c->db->id,&multistring,1);
- if (listLength(server.slaves))
- replicationFeedSlaves(server.slaves,c->db->id,&multistring,1);
+ propagate(server.multiCommand,c->db->id,&multistring,1,
+ REDIS_PROPAGATE_AOF|REDIS_PROPAGATE_REPL);
decrRefCount(multistring);
}
@@ -118,6 +116,7 @@ void execCommand(redisClient *c) {
robj **orig_argv;
int orig_argc;
struct redisCommand *orig_cmd;
+ int must_propagate = 0; /* Need to propagate MULTI/EXEC to AOF / slaves? */
if (!(c->flags & REDIS_MULTI)) {
addReplyError(c,"EXEC without MULTI");
@@ -133,19 +132,10 @@ void execCommand(redisClient *c) {
if (c->flags & (REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC)) {
addReply(c, c->flags & REDIS_DIRTY_EXEC ? shared.execaborterr :
shared.nullmultibulk);
- freeClientMultiState(c);
- initClientMultiState(c);
- c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);
- unwatchAllKeys(c);
+ discardTransaction(c);
goto handle_monitor;
}
- /* Replicate a MULTI request now that we are sure the block is executed.
- * This way we'll deliver the MULTI/..../EXEC block as a whole and
- * both the AOF and the replication link will have the same consistency
- * and atomicity guarantees. */
- execCommandReplicateMulti(c);
-
/* Exec all the queued commands */
unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */
orig_argv = c->argv;
@@ -156,6 +146,16 @@ void execCommand(redisClient *c) {
c->argc = c->mstate.commands[j].argc;
c->argv = c->mstate.commands[j].argv;
c->cmd = c->mstate.commands[j].cmd;
+
+ /* Propagate a MULTI request once we encounter the first write op.
+ * This way we'll deliver the MULTI/..../EXEC block as a whole and
+ * both the AOF and the replication link will have the same consistency
+ * and atomicity guarantees. */
+ if (!must_propagate && !(c->cmd->flags & REDIS_CMD_READONLY)) {
+ execCommandPropagateMulti(c);
+ must_propagate = 1;
+ }
+
call(c,REDIS_CALL_FULL);
/* Commands may alter argc/argv, restore mstate. */
@@ -166,13 +166,10 @@ void execCommand(redisClient *c) {
c->argv = orig_argv;
c->argc = orig_argc;
c->cmd = orig_cmd;
- freeClientMultiState(c);
- initClientMultiState(c);
- c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);
- /* Make sure the EXEC command is always replicated / AOF, since we
- * 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++;
+ discardTransaction(c);
+ /* Make sure the EXEC command will be propagated as well if MULTI
+ * was already propagated. */
+ if (must_propagate) server.dirty++;
handle_monitor:
/* Send EXEC to clients waiting data from MONITOR. We do it here