
In standalone mode, when a `-REDIRECT` error occurs, special handling is required if the client is in the `MULTI` context. We have adopted the same handling method as the cluster mode: 1. If a command in the transaction encounters a `REDIRECT` at the time of queuing, the execution of `EXEC` will return an `EXECABORT` error (we expect the client to redirect and discard the transaction upon receiving a `REDIRECT`). That is: ``` MULTI ==> +OK SET x y ==> -REDIRECT EXEC ==> -EXECABORT ``` 2. If all commands are successfully queued (i.e., `QUEUED` results are received) but a redirect is detected during `EXEC` execution (such as a primary-replica switch), a `REDIRECT` is returned to instruct the client to perform a redirect. That is: ``` MULTI ==> +OK SET x y ==> +QUEUED failover EXEC ==> -REDIRECT ``` --------- Signed-off-by: zhaozhao.zz <zhaozhao.zz@alibaba-inc.com>
108 lines
2.7 KiB
Tcl
108 lines
2.7 KiB
Tcl
# Check basic transactions on a replica.
|
|
|
|
start_cluster 1 1 {tags {external:skip cluster}} {
|
|
|
|
test "Cluster should start ok" {
|
|
wait_for_cluster_state ok
|
|
}
|
|
|
|
set primary [srv 0 "client"]
|
|
set replica [srv -1 "client"]
|
|
|
|
test "Can't read from replica without READONLY" {
|
|
$primary SET a 1
|
|
wait_for_ofs_sync $primary $replica
|
|
catch {$replica GET a} err
|
|
assert {[string range $err 0 4] eq {MOVED}}
|
|
}
|
|
|
|
test "Can't read from replica after READWRITE" {
|
|
$replica READWRITE
|
|
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 perform HSET primary and HGET from replica" {
|
|
$primary HSET h a 1
|
|
$primary HSET h b 2
|
|
$primary HSET h c 3
|
|
wait_for_ofs_sync $primary $replica
|
|
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}}
|
|
catch {$replica exec} err
|
|
assert {[string range $err 0 8] eq {EXECABORT}}
|
|
}
|
|
|
|
test "write command is QUEUED, then EXEC should be MOVED after failover" {
|
|
set rr [valkey_client]
|
|
$rr MULTI
|
|
assert {[$rr SET foo bar] eq {QUEUED}}
|
|
|
|
$replica CLUSTER FAILOVER FORCE
|
|
wait_for_condition 50 1000 {
|
|
[status $primary master_link_status] == "up"
|
|
} else {
|
|
fail "FAILOVER failed."
|
|
}
|
|
|
|
catch {$rr EXEC} err
|
|
assert {[string range $err 0 4] eq {MOVED}}
|
|
$rr close
|
|
|
|
$primary CLUSTER FAILOVER FORCE
|
|
wait_for_condition 50 1000 {
|
|
[status $replica master_link_status] == "up"
|
|
} else {
|
|
fail "FAILOVER failed."
|
|
}
|
|
}
|
|
|
|
test "read-only blocking operations from replica" {
|
|
set rd [valkey_deferring_client -1]
|
|
$rd readonly
|
|
$rd read
|
|
$rd XREAD BLOCK 0 STREAMS k 0
|
|
|
|
wait_for_condition 1000 50 {
|
|
[s -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
|
|
}
|
|
|
|
test "reply MOVED when eval from replica for update" {
|
|
catch {[$replica eval {#!lua
|
|
return server.call('del','a')
|
|
} 1 a
|
|
]} err
|
|
assert {[string range $err 0 4] eq {MOVED}}
|
|
}
|
|
|
|
} ;# start_cluster
|