Allow exec with read commands on readonly replica in cluster (#7766)
There was a bug. Although cluster replicas would allow read commands, they would not allow a MULTI-EXEC that's composed solely of read commands. Adds tests for coverage. Co-authored-by: Oran Agra <oran@redislabs.com> Co-authored-by: Eran Liberty <eranl@amazon.com>
This commit is contained in:
parent
340963b2d7
commit
b120366d48
@ -5769,8 +5769,10 @@ 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 an hash slot our master
|
* node is a slave and the request is about an hash slot our master
|
||||||
* is serving, we can reply without redirection. */
|
* is serving, we can reply without redirection. */
|
||||||
|
int is_readonly_command = (c->cmd->flags & CMD_READONLY) ||
|
||||||
|
(c->cmd->proc == execCommand && !(c->mstate.cmd_inv_flags & CMD_READONLY));
|
||||||
if (c->flags & CLIENT_READONLY &&
|
if (c->flags & CLIENT_READONLY &&
|
||||||
(cmd->flags & CMD_READONLY || cmd->proc == evalCommand ||
|
(is_readonly_command || cmd->proc == evalCommand ||
|
||||||
cmd->proc == evalShaCommand) &&
|
cmd->proc == evalShaCommand) &&
|
||||||
nodeIsSlave(myself) &&
|
nodeIsSlave(myself) &&
|
||||||
myself->slaveof == n)
|
myself->slaveof == n)
|
||||||
|
48
tests/cluster/tests/16-transactions-on-replica.tcl
Normal file
48
tests/cluster/tests/16-transactions-on-replica.tcl
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Check basic transactions on a replica.
|
||||||
|
|
||||||
|
source "../tests/includes/init-tests.tcl"
|
||||||
|
|
||||||
|
test "Create a primary with a replica" {
|
||||||
|
create_cluster 1 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Cluster should start ok" {
|
||||||
|
assert_cluster_state ok
|
||||||
|
}
|
||||||
|
|
||||||
|
set primary [Rn 0]
|
||||||
|
set replica [Rn 1]
|
||||||
|
|
||||||
|
test "Cant read from replica without READONLY" {
|
||||||
|
$primary SET a 1
|
||||||
|
catch {$replica GET a} err
|
||||||
|
assert {[string range $err 0 4] eq {MOVED}}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Can read from replica after READONLY" {
|
||||||
|
$replica READONLY
|
||||||
|
assert {[$replica GET a] eq {1}}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Can preform HSET primary and HGET from replica" {
|
||||||
|
$primary HSET h a 1
|
||||||
|
$primary HSET h b 2
|
||||||
|
$primary HSET h c 3
|
||||||
|
assert {[$replica HGET h a] eq {1}}
|
||||||
|
assert {[$replica HGET h b] eq {2}}
|
||||||
|
assert {[$replica HGET h c] eq {3}}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Can MULTI-EXEC transaction of HGET operations from replica" {
|
||||||
|
$replica MULTI
|
||||||
|
assert {[$replica HGET h a] eq {QUEUED}}
|
||||||
|
assert {[$replica HGET h b] eq {QUEUED}}
|
||||||
|
assert {[$replica HGET h c] eq {QUEUED}}
|
||||||
|
assert {[$replica EXEC] eq {1 2 3}}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "MULTI-EXEC with write operations is MOVED" {
|
||||||
|
$replica MULTI
|
||||||
|
catch {$replica HSET h b 4} err
|
||||||
|
assert {[string range $err 0 4] eq {MOVED}}
|
||||||
|
}
|
@ -422,10 +422,16 @@ proc S {n args} {
|
|||||||
[dict get $s link] {*}$args
|
[dict get $s link] {*}$args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Returns a Redis instance by index.
|
||||||
|
# Example:
|
||||||
|
# [Rn 0] info
|
||||||
|
proc Rn {n} {
|
||||||
|
return [dict get [lindex $::redis_instances $n] link]
|
||||||
|
}
|
||||||
|
|
||||||
# Like R but to chat with Redis instances.
|
# Like R but to chat with Redis instances.
|
||||||
proc R {n args} {
|
proc R {n args} {
|
||||||
set r [lindex $::redis_instances $n]
|
[Rn $n] {*}$args
|
||||||
[dict get $r link] {*}$args
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proc get_info_field {info field} {
|
proc get_info_field {info field} {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user