mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
4988b92850
Currently (starting at #11012) When a module is blocked on keys it sets the CLIENT_PENDING_COMMAND flag. However in case the module decides to unblock the client not via the regular flow (eg timeout, key signal or CLIENT UNBLOCK command) it will attempt to reprocess the module command and potentially blocked again. This fix remove the CLIENT_PENDING_COMMAND flag in case blockedForKeys is issued from module context.
307 lines
9.4 KiB
Tcl
307 lines
9.4 KiB
Tcl
set testmodule [file normalize tests/modules/blockonkeys.so]
|
|
|
|
start_server {tags {"modules"}} {
|
|
r module load $testmodule
|
|
|
|
test "Module client blocked on keys: Circular BPOPPUSH" {
|
|
set rd1 [redis_deferring_client]
|
|
set rd2 [redis_deferring_client]
|
|
|
|
r del src dst
|
|
|
|
$rd1 fsl.bpoppush src dst 0
|
|
wait_for_blocked_clients_count 1
|
|
|
|
$rd2 fsl.bpoppush dst src 0
|
|
wait_for_blocked_clients_count 2
|
|
|
|
r fsl.push src 42
|
|
wait_for_blocked_clients_count 0
|
|
|
|
assert_equal {42} [r fsl.getall src]
|
|
assert_equal {} [r fsl.getall dst]
|
|
}
|
|
|
|
test "Module client blocked on keys: Self-referential BPOPPUSH" {
|
|
set rd1 [redis_deferring_client]
|
|
|
|
r del src
|
|
|
|
$rd1 fsl.bpoppush src src 0
|
|
wait_for_blocked_clients_count 1
|
|
r fsl.push src 42
|
|
|
|
assert_equal {42} [r fsl.getall src]
|
|
}
|
|
|
|
test {Module client blocked on keys (no metadata): No block} {
|
|
r del k
|
|
r fsl.push k 33
|
|
r fsl.push k 34
|
|
r fsl.bpop k 0
|
|
} {34}
|
|
|
|
test {Module client blocked on keys (no metadata): Timeout} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpop k 1
|
|
assert_equal {Request timedout} [$rd read]
|
|
}
|
|
|
|
test {Module client blocked on keys (no metadata): Blocked} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpop k 0
|
|
wait_for_blocked_clients_count 1
|
|
r fsl.push k 34
|
|
assert_equal {34} [$rd read]
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): No block} {
|
|
r del k
|
|
r fsl.push k 34
|
|
r fsl.bpopgt k 30 0
|
|
} {34}
|
|
|
|
test {Module client blocked on keys (with metadata): Timeout} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd client id
|
|
set cid [$rd read]
|
|
r fsl.push k 33
|
|
$rd fsl.bpopgt k 35 1
|
|
assert_equal {Request timedout} [$rd read]
|
|
r client kill id $cid ;# try to smoke-out client-related memory leak
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, case 1} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd client id
|
|
set cid [$rd read]
|
|
r fsl.push k 33
|
|
$rd fsl.bpopgt k 33 0
|
|
wait_for_blocked_clients_count 1
|
|
r fsl.push k 34
|
|
assert_equal {34} [$rd read]
|
|
r client kill id $cid ;# try to smoke-out client-related memory leak
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, case 2} {
|
|
r del k
|
|
r fsl.push k 32
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r fsl.push k 33
|
|
r fsl.push k 34
|
|
r fsl.push k 35
|
|
r fsl.push k 36
|
|
assert_equal {36} [$rd read]
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, DEL} {
|
|
r del k
|
|
r fsl.push k 32
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r del k
|
|
assert_error {*UNBLOCKED key no longer exists*} {$rd read}
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, FLUSHALL} {
|
|
r del k
|
|
r fsl.push k 32
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r flushall
|
|
assert_error {*UNBLOCKED key no longer exists*} {$rd read}
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, SWAPDB, no key} {
|
|
r select 9
|
|
r del k
|
|
r fsl.push k 32
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r swapdb 0 9
|
|
assert_error {*UNBLOCKED key no longer exists*} {$rd read}
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, SWAPDB, key exists, case 1} {
|
|
;# Key exists on other db, but wrong type
|
|
r flushall
|
|
r select 9
|
|
r fsl.push k 32
|
|
r select 0
|
|
r lpush k 38
|
|
r select 9
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r swapdb 0 9
|
|
assert_error {*UNBLOCKED key no longer exists*} {$rd read}
|
|
r select 9
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, SWAPDB, key exists, case 2} {
|
|
;# Key exists on other db, with the right type, but the value doesn't allow to unblock
|
|
r flushall
|
|
r select 9
|
|
r fsl.push k 32
|
|
r select 0
|
|
r fsl.push k 34
|
|
r select 9
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r swapdb 0 9
|
|
assert_equal {1} [s 0 blocked_clients]
|
|
r fsl.push k 38
|
|
assert_equal {38} [$rd read]
|
|
r select 9
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, SWAPDB, key exists, case 3} {
|
|
;# Key exists on other db, with the right type, the value allows to unblock
|
|
r flushall
|
|
r select 9
|
|
r fsl.push k 32
|
|
r select 0
|
|
r fsl.push k 38
|
|
r select 9
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r swapdb 0 9
|
|
assert_equal {38} [$rd read]
|
|
r select 9
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, CLIENT KILL} {
|
|
r del k
|
|
r fsl.push k 32
|
|
set rd [redis_deferring_client]
|
|
$rd client id
|
|
set cid [$rd read]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r client kill id $cid ;# try to smoke-out client-related memory leak
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, CLIENT UNBLOCK TIMEOUT} {
|
|
r del k
|
|
r fsl.push k 32
|
|
set rd [redis_deferring_client]
|
|
$rd client id
|
|
set cid [$rd read]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r client unblock $cid timeout ;# try to smoke-out client-related memory leak
|
|
assert_equal {Request timedout} [$rd read]
|
|
}
|
|
|
|
test {Module client blocked on keys (with metadata): Blocked, CLIENT UNBLOCK ERROR} {
|
|
r del k
|
|
r fsl.push k 32
|
|
set rd [redis_deferring_client]
|
|
$rd client id
|
|
set cid [$rd read]
|
|
$rd fsl.bpopgt k 35 0
|
|
wait_for_blocked_clients_count 1
|
|
r client unblock $cid error ;# try to smoke-out client-related memory leak
|
|
assert_error "*unblocked*" {$rd read}
|
|
}
|
|
|
|
test {Module client blocked on keys, no timeout CB, CLIENT UNBLOCK TIMEOUT} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd client id
|
|
set cid [$rd read]
|
|
$rd fsl.bpop k 0 NO_TO_CB
|
|
wait_for_blocked_clients_count 1
|
|
assert_equal [r client unblock $cid timeout] {0}
|
|
$rd close
|
|
}
|
|
|
|
test {Module client blocked on keys, no timeout CB, CLIENT UNBLOCK ERROR} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd client id
|
|
set cid [$rd read]
|
|
$rd fsl.bpop k 0 NO_TO_CB
|
|
wait_for_blocked_clients_count 1
|
|
assert_equal [r client unblock $cid error] {0}
|
|
$rd close
|
|
}
|
|
|
|
test {Module client re-blocked on keys after woke up on wrong type} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd fsl.bpop k 0
|
|
wait_for_blocked_clients_count 1
|
|
r lpush k 12
|
|
r lpush k 13
|
|
r lpush k 14
|
|
r del k
|
|
r fsl.push k 34
|
|
assert_equal {34} [$rd read]
|
|
assert_equal {1} [r get fsl_wrong_type] ;# first lpush caused one wrong-type wake-up
|
|
}
|
|
|
|
test {Module client blocked on keys woken up by LPUSH} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd blockonkeys.popall k
|
|
wait_for_blocked_clients_count 1
|
|
r lpush k 42 squirrel banana
|
|
assert_equal {banana squirrel 42} [$rd read]
|
|
$rd close
|
|
}
|
|
|
|
test {Module client unblocks BLPOP} {
|
|
r del k
|
|
set rd [redis_deferring_client]
|
|
$rd blpop k 3
|
|
wait_for_blocked_clients_count 1
|
|
r blockonkeys.lpush k 42
|
|
assert_equal {k 42} [$rd read]
|
|
$rd close
|
|
}
|
|
|
|
test {Module unblocks module blocked on non-empty list} {
|
|
r del k
|
|
r lpush k aa
|
|
# Module client blocks to pop 5 elements from list
|
|
set rd [redis_deferring_client]
|
|
$rd blockonkeys.blpopn k 5
|
|
wait_for_blocked_clients_count 1
|
|
# Check that RM_SignalKeyAsReady() can wake up BLPOPN
|
|
r blockonkeys.lpush_unblock k bb cc ;# Not enough elements for BLPOPN
|
|
r lpush k dd ee ff ;# Doesn't unblock module
|
|
r blockonkeys.lpush_unblock k gg ;# Unblocks module
|
|
assert_equal {gg ff ee dd cc} [$rd read]
|
|
$rd close
|
|
}
|
|
|
|
test {Module explicit unblock when blocked on keys} {
|
|
r del k
|
|
r set somekey someval
|
|
# Module client blocks to pop 5 elements from list
|
|
set rd [redis_deferring_client]
|
|
$rd blockonkeys.blpopn_or_unblock k 5 0
|
|
wait_for_blocked_clients_count 1
|
|
# will now cause the module to trigger pop but instead will unblock the client from the reply_callback
|
|
r lpush k dd
|
|
# we should still get unblocked as the command should not reprocess
|
|
wait_for_blocked_clients_count 0
|
|
assert_equal {Action aborted} [$rd read]
|
|
$rd get somekey
|
|
assert_equal {someval} [$rd read]
|
|
$rd close
|
|
}
|
|
}
|