Unverified Commit e42d98ed authored by chendianqiang's avatar chendianqiang Committed by GitHub
Browse files

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: default avatarchendianqiang <chendianqiang@meituan.com>
parent 87e7973c
...@@ -6797,6 +6797,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6797,6 +6797,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
* without redirections or errors in all the cases. */ * without redirections or errors in all the cases. */
if (n == NULL) return myself; if (n == NULL) return myself;
uint64_t cmd_flags = getCommandFlags(c);
/* Cluster is globally down but we got keys? We only serve the request /* 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 it is a read command and when allow_reads_when_down is enabled. */
if (server.cluster->state != CLUSTER_OK) { if (server.cluster->state != CLUSTER_OK) {
...@@ -6810,7 +6811,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6810,7 +6811,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
* cluster is down. */ * cluster is down. */
if (error_code) *error_code = CLUSTER_REDIR_DOWN_STATE; if (error_code) *error_code = CLUSTER_REDIR_DOWN_STATE;
return NULL; return NULL;
} else if (cmd->flags & CMD_WRITE) { } else if (cmd_flags & CMD_WRITE) {
/* The cluster is configured to allow read only commands */ /* The cluster is configured to allow read only commands */
if (error_code) *error_code = CLUSTER_REDIR_DOWN_RO_STATE; if (error_code) *error_code = CLUSTER_REDIR_DOWN_RO_STATE;
return NULL; return NULL;
...@@ -6848,7 +6849,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6848,7 +6849,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 * involves multiple keys and we don't have them all, the only option is
* to send a TRYAGAIN error. */ * to send a TRYAGAIN error. */
if (importing_slot && 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 (multiple_keys && missing_keys) {
if (error_code) *error_code = CLUSTER_REDIR_UNSTABLE; if (error_code) *error_code = CLUSTER_REDIR_UNSTABLE;
...@@ -6861,7 +6862,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in ...@@ -6861,7 +6862,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
/* Handle the read-only client case reading from a slave: if this /* 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 * node is a slave and the request is about a hash slot our master
* is serving, we can reply without redirection. */ * 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)); (c->cmd->proc == execCommand && (c->mstate.cmd_flags & CMD_WRITE));
if (((c->flags & CLIENT_READONLY) || is_pubsubshard) && if (((c->flags & CLIENT_READONLY) || is_pubsubshard) &&
!is_write_command && !is_write_command &&
......
...@@ -69,3 +69,11 @@ test "read-only blocking operations from replica" { ...@@ -69,3 +69,11 @@ test "read-only blocking operations from replica" {
assert {$res eq {foo bar}} assert {$res eq {foo bar}}
$rd close $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
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