summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchendianqiang <c.d_q@163.com>2022-09-05 21:59:14 +0800
committerOran Agra <oran@redislabs.com>2022-09-21 22:42:01 +0300
commit8c702f8ddbcdc8f92728415422c2d986871c0782 (patch)
tree6cdbca1843095bd888a3752eb2b0a528295c0d6d
parent63db10ef6f27e915683698ff7d90ea5006a33ed1 (diff)
downloadredis-8c702f8ddbcdc8f92728415422c2d986871c0782.tar.gz
Correctly handle scripts with shebang (not read-only) on a cluster replica (#11223)
EVAL scripts are by default not considered `write` commands, so they were allowed on a replica. But when adding a shebang, they become `write` command (unless the `no-writes` flag is added). With this change we'll handle them as write commands, and reply with MOVED instead of READONLY when executed on a redis cluster replica. Co-authored-by: chendianqiang <chendianqiang@meituan.com> (cherry picked from commit e42d98ed27364a100d0ba5cb1340bcd7fbcca710)
-rw-r--r--src/cluster.c7
-rw-r--r--tests/cluster/tests/16-transactions-on-replica.tcl8
2 files changed, 12 insertions, 3 deletions
diff --git a/src/cluster.c b/src/cluster.c
index 54e58e28b..7cd36c890 100644
--- a/src/cluster.c
+++ b/src/cluster.c
@@ -6716,6 +6716,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
* without redirections or errors in all the cases. */
if (n == NULL) return myself;
+ uint64_t cmd_flags = getCommandFlags(c);
/* Cluster is globally down but we got keys? We only serve the request
* if it is a read command and when allow_reads_when_down is enabled. */
if (server.cluster->state != CLUSTER_OK) {
@@ -6729,7 +6730,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
* cluster is down. */
if (error_code) *error_code = CLUSTER_REDIR_DOWN_STATE;
return NULL;
- } else if (cmd->flags & CMD_WRITE) {
+ } else if (cmd_flags & CMD_WRITE) {
/* The cluster is configured to allow read only commands */
if (error_code) *error_code = CLUSTER_REDIR_DOWN_RO_STATE;
return NULL;
@@ -6767,7 +6768,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
* involves multiple keys and we don't have them all, the only option is
* to send a TRYAGAIN error. */
if (importing_slot &&
- (c->flags & CLIENT_ASKING || cmd->flags & CMD_ASKING))
+ (c->flags & CLIENT_ASKING || cmd_flags & CMD_ASKING))
{
if (multiple_keys && missing_keys) {
if (error_code) *error_code = CLUSTER_REDIR_UNSTABLE;
@@ -6780,7 +6781,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
/* Handle the read-only client case reading from a slave: if this
* node is a slave and the request is about a hash slot our master
* is serving, we can reply without redirection. */
- int is_write_command = (c->cmd->flags & CMD_WRITE) ||
+ int is_write_command = (cmd_flags & CMD_WRITE) ||
(c->cmd->proc == execCommand && (c->mstate.cmd_flags & CMD_WRITE));
if (((c->flags & CLIENT_READONLY) || is_pubsubshard) &&
!is_write_command &&
diff --git a/tests/cluster/tests/16-transactions-on-replica.tcl b/tests/cluster/tests/16-transactions-on-replica.tcl
index ee9f7c6e6..ec5699c98 100644
--- a/tests/cluster/tests/16-transactions-on-replica.tcl
+++ b/tests/cluster/tests/16-transactions-on-replica.tcl
@@ -69,3 +69,11 @@ test "read-only blocking operations from replica" {
assert {$res eq {foo bar}}
$rd close
}
+
+test "reply MOVED when eval from replica for update" {
+ catch {[$replica eval {#!lua
+ return redis.call('del','a')
+ } 1 a
+ ]} err
+ assert {[string range $err 0 4] eq {MOVED}}
+} \ No newline at end of file