diff options
Diffstat (limited to 'examples/redis-unstable/tests/unit/moduleapi/blockedclient.tcl')
| -rw-r--r-- | examples/redis-unstable/tests/unit/moduleapi/blockedclient.tcl | 310 |
1 files changed, 0 insertions, 310 deletions
diff --git a/examples/redis-unstable/tests/unit/moduleapi/blockedclient.tcl b/examples/redis-unstable/tests/unit/moduleapi/blockedclient.tcl deleted file mode 100644 index 7dcc1d6..0000000 --- a/examples/redis-unstable/tests/unit/moduleapi/blockedclient.tcl +++ /dev/null | |||
| @@ -1,310 +0,0 @@ | |||
| 1 | set testmodule [file normalize tests/modules/blockedclient.so] | ||
| 2 | |||
| 3 | start_server {tags {"modules external:skip"}} { | ||
| 4 | r module load $testmodule | ||
| 5 | |||
| 6 | test {Locked GIL acquisition} { | ||
| 7 | assert_match "OK" [r acquire_gil] | ||
| 8 | } | ||
| 9 | |||
| 10 | test {Locked GIL acquisition during multi} { | ||
| 11 | r multi | ||
| 12 | r acquire_gil | ||
| 13 | assert_equal {{Blocked client is not supported inside multi}} [r exec] | ||
| 14 | } | ||
| 15 | |||
| 16 | test {Locked GIL acquisition from RM_Call} { | ||
| 17 | assert_equal {Blocked client is not allowed} [r do_rm_call acquire_gil] | ||
| 18 | } | ||
| 19 | |||
| 20 | test {Blocking command are not block the client on RM_Call} { | ||
| 21 | r lpush l test | ||
| 22 | assert_equal [r do_rm_call blpop l 0] {l test} | ||
| 23 | |||
| 24 | r lpush l test | ||
| 25 | assert_equal [r do_rm_call brpop l 0] {l test} | ||
| 26 | |||
| 27 | r lpush l1 test | ||
| 28 | assert_equal [r do_rm_call brpoplpush l1 l2 0] {test} | ||
| 29 | assert_equal [r do_rm_call brpop l2 0] {l2 test} | ||
| 30 | |||
| 31 | r lpush l1 test | ||
| 32 | assert_equal [r do_rm_call blmove l1 l2 LEFT LEFT 0] {test} | ||
| 33 | assert_equal [r do_rm_call brpop l2 0] {l2 test} | ||
| 34 | |||
| 35 | r ZADD zset1 0 a 1 b 2 c | ||
| 36 | assert_equal [r do_rm_call bzpopmin zset1 0] {zset1 a 0} | ||
| 37 | assert_equal [r do_rm_call bzpopmax zset1 0] {zset1 c 2} | ||
| 38 | |||
| 39 | r xgroup create s g $ MKSTREAM | ||
| 40 | r xadd s * foo bar | ||
| 41 | assert {[r do_rm_call xread BLOCK 0 STREAMS s 0-0] ne {}} | ||
| 42 | assert {[r do_rm_call xreadgroup group g c BLOCK 0 STREAMS s >] ne {}} | ||
| 43 | |||
| 44 | assert {[r do_rm_call blpop empty_list 0] eq {}} | ||
| 45 | assert {[r do_rm_call brpop empty_list 0] eq {}} | ||
| 46 | assert {[r do_rm_call brpoplpush empty_list1 empty_list2 0] eq {}} | ||
| 47 | assert {[r do_rm_call blmove empty_list1 empty_list2 LEFT LEFT 0] eq {}} | ||
| 48 | |||
| 49 | assert {[r do_rm_call bzpopmin empty_zset 0] eq {}} | ||
| 50 | assert {[r do_rm_call bzpopmax empty_zset 0] eq {}} | ||
| 51 | |||
| 52 | r xgroup create empty_stream g $ MKSTREAM | ||
| 53 | assert {[r do_rm_call xread BLOCK 0 STREAMS empty_stream $] eq {}} | ||
| 54 | assert {[r do_rm_call xreadgroup group g c BLOCK 0 STREAMS empty_stream >] eq {}} | ||
| 55 | |||
| 56 | } | ||
| 57 | |||
| 58 | test {Monitor disallow inside RM_Call} { | ||
| 59 | set e {} | ||
| 60 | catch { | ||
| 61 | r do_rm_call monitor | ||
| 62 | } e | ||
| 63 | set e | ||
| 64 | } {*ERR*DENY BLOCKING*} | ||
| 65 | |||
| 66 | test {subscribe disallow inside RM_Call} { | ||
| 67 | set e {} | ||
| 68 | catch { | ||
| 69 | r do_rm_call subscribe x | ||
| 70 | } e | ||
| 71 | set e | ||
| 72 | } {*ERR*DENY BLOCKING*} | ||
| 73 | |||
| 74 | test {RM_Call from blocked client} { | ||
| 75 | r hset hash foo bar | ||
| 76 | r do_bg_rm_call hgetall hash | ||
| 77 | } {foo bar} | ||
| 78 | |||
| 79 | test {RM_Call from blocked client with script mode} { | ||
| 80 | r do_bg_rm_call_format S hset k foo bar | ||
| 81 | } {1} | ||
| 82 | |||
| 83 | test {RM_Call from blocked client with oom mode} { | ||
| 84 | r config set maxmemory 1 | ||
| 85 | # will set server.pre_command_oom_state to 1 | ||
| 86 | assert_error {OOM command not allowed*} {r hset hash foo bar} | ||
| 87 | r config set maxmemory 0 | ||
| 88 | # now its should be OK to call OOM commands | ||
| 89 | r do_bg_rm_call_format M hset k1 foo bar | ||
| 90 | } {1} {needs:config-maxmemory} | ||
| 91 | |||
| 92 | test {RESP version carries through to blocked client} { | ||
| 93 | for {set client_proto 2} {$client_proto <= 3} {incr client_proto} { | ||
| 94 | if {[lsearch $::denytags "resp3"] >= 0} { | ||
| 95 | if {$client_proto == 3} {continue} | ||
| 96 | } elseif {$::force_resp3} { | ||
| 97 | if {$client_proto == 2} {continue} | ||
| 98 | } | ||
| 99 | r hello $client_proto | ||
| 100 | r readraw 1 | ||
| 101 | set ret [r do_fake_bg_true] | ||
| 102 | if {$client_proto == 2} { | ||
| 103 | assert_equal $ret {:1} | ||
| 104 | } else { | ||
| 105 | assert_equal $ret "#t" | ||
| 106 | } | ||
| 107 | r readraw 0 | ||
| 108 | r hello 2 | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | foreach call_type {nested normal} { | ||
| 113 | test "Busy module command - $call_type" { | ||
| 114 | set busy_time_limit 50 | ||
| 115 | set old_time_limit [lindex [r config get busy-reply-threshold] 1] | ||
| 116 | r config set busy-reply-threshold $busy_time_limit | ||
| 117 | set rd [redis_deferring_client] | ||
| 118 | |||
| 119 | # run command that blocks until released | ||
| 120 | set start [clock clicks -milliseconds] | ||
| 121 | if {$call_type == "nested"} { | ||
| 122 | $rd do_rm_call slow_fg_command 0 | ||
| 123 | } else { | ||
| 124 | $rd slow_fg_command 0 | ||
| 125 | } | ||
| 126 | $rd flush | ||
| 127 | |||
| 128 | # send another command after the blocked one, to make sure we don't attempt to process it | ||
| 129 | $rd ping | ||
| 130 | $rd flush | ||
| 131 | |||
| 132 | # make sure we get BUSY error, and that we didn't get it too early | ||
| 133 | wait_for_condition 50 100 { | ||
| 134 | ([catch {r ping} reply] == 1) && | ||
| 135 | ([string match {*BUSY Slow module operation*} $reply]) | ||
| 136 | } else { | ||
| 137 | fail "Failed waiting for busy slow response" | ||
| 138 | } | ||
| 139 | assert_morethan_equal [expr [clock clicks -milliseconds]-$start] $busy_time_limit | ||
| 140 | |||
| 141 | # abort the blocking operation | ||
| 142 | r stop_slow_fg_command | ||
| 143 | wait_for_condition 50 100 { | ||
| 144 | [catch {r ping} e] == 0 | ||
| 145 | } else { | ||
| 146 | fail "Failed waiting for busy command to end" | ||
| 147 | } | ||
| 148 | assert_equal [$rd read] "1" | ||
| 149 | assert_equal [$rd read] "PONG" | ||
| 150 | |||
| 151 | # run command that blocks for 200ms | ||
| 152 | set start [clock clicks -milliseconds] | ||
| 153 | if {$call_type == "nested"} { | ||
| 154 | $rd do_rm_call slow_fg_command 200000 | ||
| 155 | } else { | ||
| 156 | $rd slow_fg_command 200000 | ||
| 157 | } | ||
| 158 | $rd flush | ||
| 159 | after 10 ;# try to make sure redis started running the command before we proceed | ||
| 160 | |||
| 161 | # make sure we didn't get BUSY error, it simply blocked till the command was done | ||
| 162 | r ping | ||
| 163 | # The command blocks for 200ms, allow 1-2ms clock skew (1%) | ||
| 164 | # to accommodate differences between using of monotonic timer and ustime | ||
| 165 | assert_morethan_equal [expr [clock clicks -milliseconds]-$start] 198 | ||
| 166 | $rd read | ||
| 167 | |||
| 168 | $rd close | ||
| 169 | r config set busy-reply-threshold $old_time_limit | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | test {RM_Call from blocked client} { | ||
| 174 | set busy_time_limit 50 | ||
| 175 | set old_time_limit [lindex [r config get busy-reply-threshold] 1] | ||
| 176 | r config set busy-reply-threshold $busy_time_limit | ||
| 177 | |||
| 178 | # trigger slow operation | ||
| 179 | r set_slow_bg_operation 1 | ||
| 180 | r hset hash foo bar | ||
| 181 | set rd [redis_deferring_client] | ||
| 182 | set start [clock clicks -milliseconds] | ||
| 183 | $rd do_bg_rm_call hgetall hash | ||
| 184 | |||
| 185 | # send another command after the blocked one, to make sure we don't attempt to process it | ||
| 186 | $rd ping | ||
| 187 | $rd flush | ||
| 188 | |||
| 189 | # wait till we know we're blocked inside the module | ||
| 190 | wait_for_condition 50 100 { | ||
| 191 | [r is_in_slow_bg_operation] eq 1 | ||
| 192 | } else { | ||
| 193 | fail "Failed waiting for slow operation to start" | ||
| 194 | } | ||
| 195 | |||
| 196 | # make sure we get BUSY error, and that we didn't get here too early | ||
| 197 | assert_error {*BUSY Slow module operation*} {r ping} | ||
| 198 | assert_morethan_equal [expr [clock clicks -milliseconds]-$start] $busy_time_limit | ||
| 199 | # abort the blocking operation | ||
| 200 | r set_slow_bg_operation 0 | ||
| 201 | |||
| 202 | wait_for_condition 50 100 { | ||
| 203 | [r is_in_slow_bg_operation] eq 0 | ||
| 204 | } else { | ||
| 205 | fail "Failed waiting for slow operation to stop" | ||
| 206 | } | ||
| 207 | assert_equal [r ping] {PONG} | ||
| 208 | |||
| 209 | r config set busy-reply-threshold $old_time_limit | ||
| 210 | assert_equal [$rd read] {foo bar} | ||
| 211 | assert_equal [$rd read] {PONG} | ||
| 212 | $rd close | ||
| 213 | } | ||
| 214 | |||
| 215 | test {blocked client reaches client output buffer limit} { | ||
| 216 | r hset hash big [string repeat x 50000] | ||
| 217 | r hset hash bada [string repeat x 50000] | ||
| 218 | r hset hash boom [string repeat x 50000] | ||
| 219 | r config set client-output-buffer-limit {normal 100000 0 0} | ||
| 220 | r client setname myclient | ||
| 221 | catch {r do_bg_rm_call hgetall hash} e | ||
| 222 | assert_match "*I/O error*" $e | ||
| 223 | reconnect | ||
| 224 | set clients [r client list] | ||
| 225 | assert_no_match "*name=myclient*" $clients | ||
| 226 | } | ||
| 227 | |||
| 228 | test {module client error stats} { | ||
| 229 | r config resetstat | ||
| 230 | |||
| 231 | # simple module command that replies with string error | ||
| 232 | assert_error "ERR unknown command 'hgetalllll'" {r do_rm_call hgetalllll} | ||
| 233 | assert_equal [errorrstat ERR r] {count=1} | ||
| 234 | |||
| 235 | # simple module command that replies with string error | ||
| 236 | assert_error "ERR unknown subcommand 'bla'. Try CONFIG HELP." {r do_rm_call config bla} | ||
| 237 | assert_equal [errorrstat ERR r] {count=2} | ||
| 238 | |||
| 239 | # module command that replies with string error from bg thread | ||
| 240 | assert_error "NULL reply returned" {r do_bg_rm_call hgetalllll} | ||
| 241 | assert_equal [errorrstat NULL r] {count=1} | ||
| 242 | |||
| 243 | # module command that returns an arity error | ||
| 244 | r do_rm_call set x x | ||
| 245 | assert_error "ERR wrong number of arguments for 'do_rm_call' command" {r do_rm_call} | ||
| 246 | assert_equal [errorrstat ERR r] {count=3} | ||
| 247 | |||
| 248 | # RM_Call that propagates an error | ||
| 249 | assert_error "WRONGTYPE*" {r do_rm_call hgetall x} | ||
| 250 | assert_equal [errorrstat WRONGTYPE r] {count=1} | ||
| 251 | assert_match {*calls=1,*,rejected_calls=0,failed_calls=1} [cmdrstat hgetall r] | ||
| 252 | |||
| 253 | # RM_Call from bg thread that propagates an error | ||
| 254 | assert_error "WRONGTYPE*" {r do_bg_rm_call hgetall x} | ||
| 255 | assert_equal [errorrstat WRONGTYPE r] {count=2} | ||
| 256 | assert_match {*calls=2,*,rejected_calls=0,failed_calls=2} [cmdrstat hgetall r] | ||
| 257 | |||
| 258 | assert_equal [s total_error_replies] 6 | ||
| 259 | assert_match {*calls=5,*,rejected_calls=0,failed_calls=4} [cmdrstat do_rm_call r] | ||
| 260 | assert_match {*calls=2,*,rejected_calls=0,failed_calls=2} [cmdrstat do_bg_rm_call r] | ||
| 261 | } | ||
| 262 | |||
| 263 | set master [srv 0 client] | ||
| 264 | set master_host [srv 0 host] | ||
| 265 | set master_port [srv 0 port] | ||
| 266 | start_server [list overrides [list loadmodule "$testmodule"] tags {"external:skip"}] { | ||
| 267 | set replica [srv 0 client] | ||
| 268 | set replica_host [srv 0 host] | ||
| 269 | set replica_port [srv 0 port] | ||
| 270 | |||
| 271 | # Start the replication process... | ||
| 272 | $replica replicaof $master_host $master_port | ||
| 273 | wait_for_sync $replica | ||
| 274 | |||
| 275 | test {WAIT command on module blocked client} { | ||
| 276 | pause_process [srv 0 pid] | ||
| 277 | |||
| 278 | $master do_bg_rm_call_format ! hset bk1 foo bar | ||
| 279 | |||
| 280 | assert_equal [$master wait 1 1000] 0 | ||
| 281 | resume_process [srv 0 pid] | ||
| 282 | assert_equal [$master wait 1 1000] 1 | ||
| 283 | assert_equal [$replica hget bk1 foo] bar | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | test {Unblock by timer} { | ||
| 288 | # When the client is unlock, we will get the OK reply. | ||
| 289 | assert_match "OK" [r unblock_by_timer 100 0] | ||
| 290 | } | ||
| 291 | |||
| 292 | test {block time is shorter than timer period} { | ||
| 293 | # This command does not have the reply. | ||
| 294 | set rd [redis_deferring_client] | ||
| 295 | $rd unblock_by_timer 100 10 | ||
| 296 | # Wait for the client to unlock. | ||
| 297 | after 120 | ||
| 298 | $rd close | ||
| 299 | } | ||
| 300 | |||
| 301 | test {block time is equal to timer period} { | ||
| 302 | # These time is equal, they will be unlocked in the same event loop, | ||
| 303 | # when the client is unlock, we will get the OK reply from timer. | ||
| 304 | assert_match "OK" [r unblock_by_timer 100 100] | ||
| 305 | } | ||
| 306 | |||
| 307 | test "Unload the module - blockedclient" { | ||
| 308 | assert_equal {OK} [r module unload blockedclient] | ||
| 309 | } | ||
| 310 | } | ||
