diff options
Diffstat (limited to 'examples/redis-unstable/tests/unit/obuf-limits.tcl')
| -rw-r--r-- | examples/redis-unstable/tests/unit/obuf-limits.tcl | 240 |
1 files changed, 0 insertions, 240 deletions
diff --git a/examples/redis-unstable/tests/unit/obuf-limits.tcl b/examples/redis-unstable/tests/unit/obuf-limits.tcl deleted file mode 100644 index 148187b..0000000 --- a/examples/redis-unstable/tests/unit/obuf-limits.tcl +++ /dev/null | |||
| @@ -1,240 +0,0 @@ | |||
| 1 | start_server {tags {"obuf-limits external:skip logreqres:skip"}} { | ||
| 2 | r debug reply-copy-avoidance 0 ;# Disable copy avoidance because it affects memory usage | ||
| 3 | |||
| 4 | test {CONFIG SET client-output-buffer-limit} { | ||
| 5 | set oldval [lindex [r config get client-output-buffer-limit] 1] | ||
| 6 | |||
| 7 | catch {r config set client-output-buffer-limit "wrong number"} e | ||
| 8 | assert_match {*Wrong*arguments*} $e | ||
| 9 | |||
| 10 | catch {r config set client-output-buffer-limit "invalid_class 10mb 10mb 60"} e | ||
| 11 | assert_match {*Invalid*client*class*} $e | ||
| 12 | catch {r config set client-output-buffer-limit "master 10mb 10mb 60"} e | ||
| 13 | assert_match {*Invalid*client*class*} $e | ||
| 14 | |||
| 15 | catch {r config set client-output-buffer-limit "normal 10mbs 10mb 60"} e | ||
| 16 | assert_match {*Error*hard*} $e | ||
| 17 | |||
| 18 | catch {r config set client-output-buffer-limit "replica 10mb 10mbs 60"} e | ||
| 19 | assert_match {*Error*soft*} $e | ||
| 20 | |||
| 21 | catch {r config set client-output-buffer-limit "pubsub 10mb 10mb 60s"} e | ||
| 22 | assert_match {*Error*soft_seconds*} $e | ||
| 23 | |||
| 24 | r config set client-output-buffer-limit "normal 1mb 2mb 60 replica 3mb 4mb 70 pubsub 5mb 6mb 80" | ||
| 25 | set res [lindex [r config get client-output-buffer-limit] 1] | ||
| 26 | assert_equal $res "normal 1048576 2097152 60 slave 3145728 4194304 70 pubsub 5242880 6291456 80" | ||
| 27 | |||
| 28 | # Set back to the original value. | ||
| 29 | r config set client-output-buffer-limit $oldval | ||
| 30 | } | ||
| 31 | |||
| 32 | test {Client output buffer hard limit is enforced} { | ||
| 33 | r config set client-output-buffer-limit {pubsub 100000 0 0} | ||
| 34 | set rd1 [redis_deferring_client] | ||
| 35 | |||
| 36 | $rd1 subscribe foo | ||
| 37 | set reply [$rd1 read] | ||
| 38 | assert {$reply eq "subscribe foo 1"} | ||
| 39 | |||
| 40 | set omem 0 | ||
| 41 | while 1 { | ||
| 42 | # The larger content size ensures that client.buf gets filled more quickly, | ||
| 43 | # allowing us to correctly observe the gradual increase of `omem` | ||
| 44 | r publish foo [string repeat bar 50] | ||
| 45 | set clients [split [r client list] "\r\n"] | ||
| 46 | set c [split [lindex $clients 1] " "] | ||
| 47 | if {![regexp {omem=([0-9]+)} $c - omem]} break | ||
| 48 | if {$omem > 200000} break | ||
| 49 | } | ||
| 50 | assert {$omem >= 70000 && $omem < 200000} | ||
| 51 | $rd1 close | ||
| 52 | } | ||
| 53 | |||
| 54 | foreach {soft_limit_time wait_for_timeout} {3 yes | ||
| 55 | 4 no } { | ||
| 56 | if $wait_for_timeout { | ||
| 57 | set test_name "Client output buffer soft limit is enforced if time is overreached" | ||
| 58 | } else { | ||
| 59 | set test_name "Client output buffer soft limit is not enforced too early and is enforced when no traffic" | ||
| 60 | } | ||
| 61 | |||
| 62 | test $test_name { | ||
| 63 | r config set client-output-buffer-limit "pubsub 0 100000 $soft_limit_time" | ||
| 64 | set soft_limit_time [expr $soft_limit_time*1000] | ||
| 65 | set rd1 [redis_deferring_client] | ||
| 66 | |||
| 67 | $rd1 client setname test_client | ||
| 68 | set reply [$rd1 read] | ||
| 69 | assert {$reply eq "OK"} | ||
| 70 | |||
| 71 | $rd1 subscribe foo | ||
| 72 | set reply [$rd1 read] | ||
| 73 | assert {$reply eq "subscribe foo 1"} | ||
| 74 | |||
| 75 | set omem 0 | ||
| 76 | set start_time 0 | ||
| 77 | set time_elapsed 0 | ||
| 78 | set last_under_limit_time [clock milliseconds] | ||
| 79 | while 1 { | ||
| 80 | r publish foo [string repeat "x" 1000] | ||
| 81 | set clients [split [r client list] "\r\n"] | ||
| 82 | set c [lsearch -inline $clients *name=test_client*] | ||
| 83 | if {$start_time != 0} { | ||
| 84 | set time_elapsed [expr {[clock milliseconds]-$start_time}] | ||
| 85 | # Make sure test isn't taking too long | ||
| 86 | assert {$time_elapsed <= [expr $soft_limit_time+3000]} | ||
| 87 | } | ||
| 88 | if {$wait_for_timeout && $c == ""} { | ||
| 89 | # Make sure we're disconnected when we reach the soft limit | ||
| 90 | assert {$omem >= 100000 && $time_elapsed >= $soft_limit_time} | ||
| 91 | break | ||
| 92 | } else { | ||
| 93 | assert {[regexp {omem=([0-9]+)} $c - omem]} | ||
| 94 | } | ||
| 95 | if {$omem > 100000} { | ||
| 96 | if {$start_time == 0} {set start_time $last_under_limit_time} | ||
| 97 | if {!$wait_for_timeout && $time_elapsed >= [expr $soft_limit_time-1000]} break | ||
| 98 | # Slow down loop when omem has reached the limit. | ||
| 99 | after 10 | ||
| 100 | } else { | ||
| 101 | # if the OS socket buffers swallowed what we previously filled, reset the start timer. | ||
| 102 | set start_time 0 | ||
| 103 | set last_under_limit_time [clock milliseconds] | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | if {!$wait_for_timeout} { | ||
| 108 | # After we completely stopped the traffic, wait for soft limit to time out | ||
| 109 | set timeout [expr {$soft_limit_time+1500 - ([clock milliseconds]-$start_time)}] | ||
| 110 | wait_for_condition [expr $timeout/10] 10 { | ||
| 111 | [lsearch [split [r client list] "\r\n"] *name=test_client*] == -1 | ||
| 112 | } else { | ||
| 113 | fail "Soft limit timed out but client still connected" | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | $rd1 close | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | test {No response for single command if client output buffer hard limit is enforced} { | ||
| 122 | r config set latency-tracking no | ||
| 123 | r config set client-output-buffer-limit {normal 100000 0 0} | ||
| 124 | # Total size of all items must be more than 100k | ||
| 125 | set item [string repeat "x" 1000] | ||
| 126 | for {set i 0} {$i < 150} {incr i} { | ||
| 127 | r lpush mylist $item | ||
| 128 | } | ||
| 129 | set orig_mem [s used_memory] | ||
| 130 | # Set client name and get all items | ||
| 131 | set rd [redis_deferring_client] | ||
| 132 | $rd client setname mybiglist | ||
| 133 | assert {[$rd read] eq "OK"} | ||
| 134 | $rd lrange mylist 0 -1 | ||
| 135 | $rd flush | ||
| 136 | after 100 | ||
| 137 | |||
| 138 | # Before we read reply, redis will close this client. | ||
| 139 | set clients [r client list] | ||
| 140 | assert_no_match "*name=mybiglist*" $clients | ||
| 141 | set cur_mem [s used_memory] | ||
| 142 | # 10k just is a deviation threshold | ||
| 143 | assert {$cur_mem < 10000 + $orig_mem} | ||
| 144 | |||
| 145 | # Read nothing | ||
| 146 | set fd [$rd channel] | ||
| 147 | assert_equal {} [$rd rawread] | ||
| 148 | } | ||
| 149 | |||
| 150 | # Note: This test assumes that what's written with one write, will be read by redis in one read. | ||
| 151 | # this assumption is wrong, but seem to work empirically (for now) | ||
| 152 | test {No response for multi commands in pipeline if client output buffer limit is enforced} { | ||
| 153 | r config set client-output-buffer-limit {normal 100000 0 0} | ||
| 154 | set value [string repeat "x" 10000] | ||
| 155 | r set bigkey $value | ||
| 156 | set rd [redis_deferring_client] | ||
| 157 | $rd client setname multicommands | ||
| 158 | assert_equal "OK" [$rd read] | ||
| 159 | |||
| 160 | set server_pid [s process_id] | ||
| 161 | # Pause the server, so that the client's write will be buffered | ||
| 162 | pause_process $server_pid | ||
| 163 | |||
| 164 | # Create a pipeline of commands that will be processed in one socket read. | ||
| 165 | # It is important to use one write, in TLS mode independent writes seem | ||
| 166 | # to wait for response from the server. | ||
| 167 | # Total size should be less than OS socket buffer, redis can | ||
| 168 | # execute all commands in this pipeline when it wakes up. | ||
| 169 | set buf "" | ||
| 170 | for {set i 0} {$i < 15} {incr i} { | ||
| 171 | append buf "set $i $i\r\n" | ||
| 172 | append buf "get $i\r\n" | ||
| 173 | append buf "del $i\r\n" | ||
| 174 | # One bigkey is 10k, total response size must be more than 100k | ||
| 175 | append buf "get bigkey\r\n" | ||
| 176 | } | ||
| 177 | $rd write $buf | ||
| 178 | $rd flush | ||
| 179 | |||
| 180 | # Resume the server to process the pipeline in one go | ||
| 181 | resume_process $server_pid | ||
| 182 | # Make sure the pipeline of commands is processed | ||
| 183 | wait_for_condition 100 10 { | ||
| 184 | [expr {[regexp {calls=(\d+)} [cmdrstat get r] -> calls] ? $calls : 0}] >= 5 | ||
| 185 | } else { | ||
| 186 | fail "the pipeline of commands commands is not processed" | ||
| 187 | } | ||
| 188 | |||
| 189 | # Redis must wake up if it can send reply | ||
| 190 | assert_equal "PONG" [r ping] | ||
| 191 | set clients [r client list] | ||
| 192 | assert_no_match "*name=multicommands*" $clients | ||
| 193 | assert_equal {} [$rd rawread] | ||
| 194 | } | ||
| 195 | |||
| 196 | test {Execute transactions completely even if client output buffer limit is enforced} { | ||
| 197 | r config set client-output-buffer-limit {normal 100000 0 0} | ||
| 198 | # Total size of all items must be more than 100k | ||
| 199 | set item [string repeat "x" 1000] | ||
| 200 | for {set i 0} {$i < 150} {incr i} { | ||
| 201 | r lpush mylist2 $item | ||
| 202 | } | ||
| 203 | |||
| 204 | # Output buffer limit is enforced during executing transaction | ||
| 205 | r client setname transactionclient | ||
| 206 | r set k1 v1 | ||
| 207 | r multi | ||
| 208 | r set k2 v2 | ||
| 209 | r get k2 | ||
| 210 | r lrange mylist2 0 -1 | ||
| 211 | r set k3 v3 | ||
| 212 | r del k1 | ||
| 213 | catch {[r exec]} e | ||
| 214 | assert_match "*I/O error*" $e | ||
| 215 | reconnect | ||
| 216 | set clients [r client list] | ||
| 217 | assert_no_match "*name=transactionclient*" $clients | ||
| 218 | |||
| 219 | # Transactions should be executed completely | ||
| 220 | assert_equal {} [r get k1] | ||
| 221 | assert_equal "v2" [r get k2] | ||
| 222 | assert_equal "v3" [r get k3] | ||
| 223 | } | ||
| 224 | |||
| 225 | test "Obuf limit, HRANDFIELD with huge count stopped mid-run" { | ||
| 226 | r config set client-output-buffer-limit {normal 1000000 0 0} | ||
| 227 | r hset myhash a b | ||
| 228 | catch {r hrandfield myhash -999999999} e | ||
| 229 | assert_match "*I/O error*" $e | ||
| 230 | reconnect | ||
| 231 | } | ||
| 232 | |||
| 233 | test "Obuf limit, KEYS stopped mid-run" { | ||
| 234 | r config set client-output-buffer-limit {normal 100000 0 0} | ||
| 235 | populate 1000 "long-key-name-prefix-of-100-chars-------------------------------------------------------------------" | ||
| 236 | catch {r keys *} e | ||
| 237 | assert_match "*I/O error*" $e | ||
| 238 | reconnect | ||
| 239 | } | ||
| 240 | } | ||
