diff options
author | Oran Agra <oran@redislabs.com> | 2020-10-06 21:43:30 +0300 |
---|---|---|
committer | Oran Agra <oran@redislabs.com> | 2020-10-27 08:49:22 +0200 |
commit | 89c68ba3f7fba1e1050c0ecfc7c2e57f64ec15f5 (patch) | |
tree | 0b4441c8136ba2c9f67b7a40e769df6bce39f2bd | |
parent | fcda82930e78dbfe92a3b0024212eb75fc08a919 (diff) | |
download | redis-89c68ba3f7fba1e1050c0ecfc7c2e57f64ec15f5.tar.gz |
Allow blocked XREAD on a cluster replica (#7881)
I suppose that it was overlooked, since till recently none of the blocked commands were readonly.
other changes:
- add test for the above.
- add better support for additional (and deferring) clients for
cluster tests
- improve a test which left the client in MULTI state.
(cherry picked from commit 216c1106099f7c66c991a5a811c8fbacbb0ab17c)
-rw-r--r-- | src/cluster.c | 9 | ||||
-rw-r--r-- | tests/cluster/tests/16-transactions-on-replica.tcl | 70 | ||||
-rw-r--r-- | tests/instances.tcl | 23 |
3 files changed, 100 insertions, 2 deletions
diff --git a/src/cluster.c b/src/cluster.c index 5966d0561..3e19f88eb 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -5741,6 +5741,15 @@ int clusterRedirectBlockedClientIfNeeded(client *c) { int slot = keyHashSlot((char*)key->ptr, sdslen(key->ptr)); clusterNode *node = server.cluster->slots[slot]; + /* if the client is read-only and attempting to access key that our + * replica can handle, allow it. */ + if ((c->flags & CLIENT_READONLY) && + (c->lastcmd->flags & CMD_READONLY) && + nodeIsSlave(myself) && myself->slaveof == node) + { + node = myself; + } + /* We send an error and unblock the client if: * 1) The slot is unassigned, emitting a cluster down error. * 2) The slot is not handled by this node, nor being imported. */ diff --git a/tests/cluster/tests/16-transactions-on-replica.tcl b/tests/cluster/tests/16-transactions-on-replica.tcl new file mode 100644 index 000000000..da3017bc2 --- /dev/null +++ b/tests/cluster/tests/16-transactions-on-replica.tcl @@ -0,0 +1,70 @@ +# 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}} +} + +# didn't cherry pick b120366d4 to 5.0 yet +#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}} + catch {$replica exec} err + assert {[string range $err 0 8] eq {EXECABORT}} +} + +test "read-only blocking operations from replica" { + set rd [redis_deferring_client redis 1] + $rd readonly + $rd read + $rd XREAD BLOCK 0 STREAMS k 0 + + wait_for_condition 1000 50 { + [RI 1 blocked_clients] eq {1} + } else { + fail "client wasn't blocked" + } + + $primary XADD k * foo bar + set res [$rd read] + set res [lindex [lindex [lindex [lindex $res 0] 1] 0] 1] + assert {$res eq {foo bar}} + $rd close +} diff --git a/tests/instances.tcl b/tests/instances.tcl index 357b34818..352b2a2e5 100644 --- a/tests/instances.tcl +++ b/tests/instances.tcl @@ -334,10 +334,16 @@ proc S {n 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. proc R {n args} { - set r [lindex $::redis_instances $n] - [dict get $r link] {*}$args + [Rn $n] {*}$args } proc get_info_field {info field} { @@ -509,3 +515,16 @@ proc restart_instance {type id} { } } +proc redis_deferring_client {type id} { + set port [get_instance_attrib $type $id port] + set host [get_instance_attrib $type $id host] + set client [redis $host $port 1] + return $client +} + +proc redis_client {type id} { + set port [get_instance_attrib $type $id port] + set host [get_instance_attrib $type $id host] + set client [redis $host $port 0] + return $client +} |