diff options
author | antirez <antirez@gmail.com> | 2018-12-11 11:39:18 +0100 |
---|---|---|
committer | antirez <antirez@gmail.com> | 2018-12-11 11:39:21 +0100 |
commit | 274531396caedd710595f46cc14010ed68a0c931 (patch) | |
tree | db7787ede988e38fd2dccbfc356136ef0ce2eaf0 /src/multi.c | |
parent | 086363babf0e47162d975a265bd8d77e8d49dfb1 (diff) | |
download | redis-274531396caedd710595f46cc14010ed68a0c931.tar.gz |
Reject EXEC containing write commands against RO replica.
Thanks to @soloestoy for discovering this issue in #5667.
This is an alternative fix in order to avoid both cycling the clients
and also disconnecting clients just having valid read-only transactions
pending.
Diffstat (limited to 'src/multi.c')
-rw-r--r-- | src/multi.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/src/multi.c b/src/multi.c index 8159adcb3..c2e641879 100644 --- a/src/multi.c +++ b/src/multi.c @@ -35,6 +35,7 @@ void initClientMultiState(client *c) { c->mstate.commands = NULL; c->mstate.count = 0; + c->mstate.cmd_flags = 0; } /* Release all the resources associated with MULTI/EXEC state */ @@ -67,6 +68,7 @@ void queueMultiCommand(client *c) { for (j = 0; j < c->argc; j++) incrRefCount(mc->argv[j]); c->mstate.count++; + c->mstate.cmd_flags |= c->cmd->flags; } void discardTransaction(client *c) { @@ -137,6 +139,21 @@ void execCommand(client *c) { goto handle_monitor; } + /* If there are write commands inside the transaction, and this is a read + * only slave, we want to send an error. This happens when the transaction + * was initiated when the instance was a master or a writable replica and + * then the configuration changed (for example instance was turned into + * a replica). */ + if (server.masterhost && server.repl_slave_ro && + !(c->flags & CLIENT_MASTER) && c->mstate.cmd_flags & CMD_WRITE) + { + addReplyError(c, + "Transaction contains write commands but instance " + "is now a read-only slave. EXEC aborted."); + discardTransaction(c); + goto handle_monitor; + } + /* Exec all the queued commands */ unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */ orig_argv = c->argv; |