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 216c110609)
This commit is contained in:
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+21
-2
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user