diff options
Diffstat (limited to 'examples/redis-unstable/tests/unit/moduleapi/testrdb.tcl')
| -rw-r--r-- | examples/redis-unstable/tests/unit/moduleapi/testrdb.tcl | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/examples/redis-unstable/tests/unit/moduleapi/testrdb.tcl b/examples/redis-unstable/tests/unit/moduleapi/testrdb.tcl new file mode 100644 index 0000000..e44cf42 --- /dev/null +++ b/examples/redis-unstable/tests/unit/moduleapi/testrdb.tcl | |||
| @@ -0,0 +1,311 @@ | |||
| 1 | # This module can be configure with multiple options given as flags on module load time | ||
| 2 | # 0 - not aux fields will be declared (this is the default) | ||
| 3 | # 1 << 0 - use aux_save2 api | ||
| 4 | # 1 << 1 - call aux callback before key space | ||
| 5 | # 1 << 2 - call aux callback after key space | ||
| 6 | # 1 << 3 - do not save data on aux callback | ||
| 7 | set testmodule [file normalize tests/modules/testrdb.so] | ||
| 8 | |||
| 9 | tags "modules external:skip" { | ||
| 10 | test {modules are able to persist types} { | ||
| 11 | start_server [list overrides [list loadmodule "$testmodule"]] { | ||
| 12 | r testrdb.set.key key1 value1 | ||
| 13 | assert_equal "value1" [r testrdb.get.key key1] | ||
| 14 | r debug reload | ||
| 15 | assert_equal "value1" [r testrdb.get.key key1] | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | test {modules global are lost without aux} { | ||
| 20 | set server_path [tmpdir "server.module-testrdb"] | ||
| 21 | start_server [list overrides [list loadmodule "$testmodule" "dir" $server_path] keep_persistence true] { | ||
| 22 | r testrdb.set.before global1 | ||
| 23 | assert_equal "global1" [r testrdb.get.before] | ||
| 24 | } | ||
| 25 | start_server [list overrides [list loadmodule "$testmodule" "dir" $server_path]] { | ||
| 26 | assert_equal "" [r testrdb.get.before] | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | test {aux that saves no data are not saved to the rdb when aux_save2 is used} { | ||
| 31 | set server_path [tmpdir "server.module-testrdb"] | ||
| 32 | puts $server_path | ||
| 33 | # 15 == 1111 - use aux_save2 before and after key space without data | ||
| 34 | start_server [list overrides [list loadmodule "$testmodule 15" "dir" $server_path] keep_persistence true] { | ||
| 35 | r set x 1 | ||
| 36 | r save | ||
| 37 | } | ||
| 38 | start_server [list overrides [list "dir" $server_path] keep_persistence true] { | ||
| 39 | # make sure server started successfully without the module. | ||
| 40 | assert_equal {1} [r get x] | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | test {aux that saves no data are saved to the rdb when aux_save is used} { | ||
| 45 | set server_path [tmpdir "server.module-testrdb"] | ||
| 46 | puts $server_path | ||
| 47 | # 14 == 1110 - use aux_save before and after key space without data | ||
| 48 | start_server [list overrides [list loadmodule "$testmodule 14" "dir" $server_path] keep_persistence true] { | ||
| 49 | r set x 1 | ||
| 50 | r save | ||
| 51 | } | ||
| 52 | start_server [list overrides [list loadmodule "$testmodule 14" "dir" $server_path] keep_persistence true] { | ||
| 53 | # make sure server started successfully and aux_save was called twice. | ||
| 54 | assert_equal {1} [r get x] | ||
| 55 | assert_equal {2} [r testrdb.get.n_aux_load_called] | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | foreach test_case {6 7} { | ||
| 60 | # 6 == 0110 - use aux_save before and after key space with data | ||
| 61 | # 7 == 0111 - use aux_save2 before and after key space with data | ||
| 62 | test {modules are able to persist globals before and after} { | ||
| 63 | set server_path [tmpdir "server.module-testrdb"] | ||
| 64 | start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"] keep_persistence true] { | ||
| 65 | r testrdb.set.before global1 | ||
| 66 | r testrdb.set.after global2 | ||
| 67 | assert_equal "global1" [r testrdb.get.before] | ||
| 68 | assert_equal "global2" [r testrdb.get.after] | ||
| 69 | } | ||
| 70 | start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"]] { | ||
| 71 | assert_equal "global1" [r testrdb.get.before] | ||
| 72 | assert_equal "global2" [r testrdb.get.after] | ||
| 73 | } | ||
| 74 | |||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | foreach test_case {4 5} { | ||
| 79 | # 4 == 0100 - use aux_save after key space with data | ||
| 80 | # 5 == 0101 - use aux_save2 after key space with data | ||
| 81 | test {modules are able to persist globals just after} { | ||
| 82 | set server_path [tmpdir "server.module-testrdb"] | ||
| 83 | start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"] keep_persistence true] { | ||
| 84 | r testrdb.set.after global2 | ||
| 85 | assert_equal "global2" [r testrdb.get.after] | ||
| 86 | } | ||
| 87 | start_server [list overrides [list loadmodule "$testmodule $test_case" "dir" $server_path "save" "900 1"]] { | ||
| 88 | assert_equal "global2" [r testrdb.get.after] | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | test {Verify module options info} { | ||
| 94 | start_server [list overrides [list loadmodule "$testmodule"]] { | ||
| 95 | assert_match "*\[handle-io-errors|handle-repl-async-load\]*" [r info modules] | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | tags {repl} { | ||
| 100 | test {diskless loading short read with module} { | ||
| 101 | start_server [list overrides [list loadmodule "$testmodule"]] { | ||
| 102 | set replica [srv 0 client] | ||
| 103 | set replica_host [srv 0 host] | ||
| 104 | set replica_port [srv 0 port] | ||
| 105 | start_server [list overrides [list loadmodule "$testmodule"]] { | ||
| 106 | set master [srv 0 client] | ||
| 107 | set master_host [srv 0 host] | ||
| 108 | set master_port [srv 0 port] | ||
| 109 | |||
| 110 | # Set master and replica to use diskless replication | ||
| 111 | $master config set repl-diskless-sync yes | ||
| 112 | $master config set rdbcompression no | ||
| 113 | $replica config set repl-diskless-load swapdb | ||
| 114 | $master config set hz 500 | ||
| 115 | $replica config set hz 500 | ||
| 116 | $master config set dynamic-hz no | ||
| 117 | $replica config set dynamic-hz no | ||
| 118 | set start [clock clicks -milliseconds] | ||
| 119 | # Generate small keys | ||
| 120 | for {set k 0} {$k < 20000} {incr k} { | ||
| 121 | r testrdb.set.key keysmall$k [string repeat A [expr {int(rand()*100)}]] | ||
| 122 | } | ||
| 123 | # Generate larger keys | ||
| 124 | for {set k 0} {$k < 30} {incr k} { | ||
| 125 | r testrdb.set.key key$k [string repeat A [expr {int(rand()*1000000)}]] | ||
| 126 | } | ||
| 127 | |||
| 128 | if {$::verbose} { | ||
| 129 | set end [clock clicks -milliseconds] | ||
| 130 | set duration [expr $end - $start] | ||
| 131 | puts "filling took $duration ms (TODO: use pipeline)" | ||
| 132 | set start [clock clicks -milliseconds] | ||
| 133 | } | ||
| 134 | |||
| 135 | # Start the replication process... | ||
| 136 | set loglines [count_log_lines -1] | ||
| 137 | $master config set repl-diskless-sync-delay 0 | ||
| 138 | $replica replicaof $master_host $master_port | ||
| 139 | |||
| 140 | # kill the replication at various points | ||
| 141 | set attempts 100 | ||
| 142 | if {$::accurate} { set attempts 500 } | ||
| 143 | for {set i 0} {$i < $attempts} {incr i} { | ||
| 144 | # wait for the replica to start reading the rdb | ||
| 145 | # using the log file since the replica only responds to INFO once in 2mb | ||
| 146 | set res [wait_for_log_messages -1 {"*Loading DB in memory*"} $loglines 2000 1] | ||
| 147 | set loglines [lindex $res 1] | ||
| 148 | |||
| 149 | # add some additional random sleep so that we kill the master on a different place each time | ||
| 150 | after [expr {int(rand()*50)}] | ||
| 151 | |||
| 152 | # kill the replica connection on the master | ||
| 153 | set killed [$master client kill type replica] | ||
| 154 | |||
| 155 | set res [wait_for_log_messages -1 {"*Internal error in RDB*" "*Finished with success*" "*Successful partial resynchronization*"} $loglines 500 10] | ||
| 156 | if {$::verbose} { puts $res } | ||
| 157 | set log_text [lindex $res 0] | ||
| 158 | set loglines [lindex $res 1] | ||
| 159 | if {![string match "*Internal error in RDB*" $log_text]} { | ||
| 160 | # force the replica to try another full sync | ||
| 161 | $master multi | ||
| 162 | $master client kill type replica | ||
| 163 | $master set asdf asdf | ||
| 164 | # fill replication backlog with new content | ||
| 165 | $master config set repl-backlog-size 16384 | ||
| 166 | for {set keyid 0} {$keyid < 10} {incr keyid} { | ||
| 167 | $master set "$keyid string_$keyid" [string repeat A 16384] | ||
| 168 | } | ||
| 169 | $master exec | ||
| 170 | } | ||
| 171 | |||
| 172 | # wait for loading to stop (fail) | ||
| 173 | # After a loading successfully, next loop will enter `async_loading` | ||
| 174 | wait_for_condition 1000 1 { | ||
| 175 | [s -1 async_loading] eq 0 && | ||
| 176 | [s -1 loading] eq 0 | ||
| 177 | } else { | ||
| 178 | fail "Replica didn't disconnect" | ||
| 179 | } | ||
| 180 | } | ||
| 181 | if {$::verbose} { | ||
| 182 | set end [clock clicks -milliseconds] | ||
| 183 | set duration [expr $end - $start] | ||
| 184 | puts "test took $duration ms" | ||
| 185 | } | ||
| 186 | # enable fast shutdown | ||
| 187 | $master config set rdb-key-save-delay 0 | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | # Module events for diskless load swapdb when async_loading (matching master replid) | ||
| 193 | foreach test_case {6 7} { | ||
| 194 | # 6 == 0110 - use aux_save before and after key space with data | ||
| 195 | # 7 == 0111 - use aux_save2 before and after key space with data | ||
| 196 | foreach testType {Successful Aborted} { | ||
| 197 | start_server [list overrides [list loadmodule "$testmodule $test_case"] tags [list external:skip]] { | ||
| 198 | set replica [srv 0 client] | ||
| 199 | set replica_host [srv 0 host] | ||
| 200 | set replica_port [srv 0 port] | ||
| 201 | set replica_log [srv 0 stdout] | ||
| 202 | start_server [list overrides [list loadmodule "$testmodule $test_case"]] { | ||
| 203 | set master [srv 0 client] | ||
| 204 | set master_host [srv 0 host] | ||
| 205 | set master_port [srv 0 port] | ||
| 206 | |||
| 207 | set start [clock clicks -milliseconds] | ||
| 208 | |||
| 209 | # Set master and replica to use diskless replication on swapdb mode | ||
| 210 | $master config set repl-diskless-sync yes | ||
| 211 | $master config set repl-diskless-sync-delay 0 | ||
| 212 | $master config set save "" | ||
| 213 | $replica config set repl-diskless-load swapdb | ||
| 214 | $replica config set save "" | ||
| 215 | |||
| 216 | # Initial sync to have matching replids between master and replica | ||
| 217 | $replica replicaof $master_host $master_port | ||
| 218 | |||
| 219 | # Let replica finish initial sync with master | ||
| 220 | wait_for_condition 100 100 { | ||
| 221 | [s -1 master_link_status] eq "up" | ||
| 222 | } else { | ||
| 223 | fail "Master <-> Replica didn't finish sync" | ||
| 224 | } | ||
| 225 | |||
| 226 | # Set global values on module so we can check if module event callbacks will pick it up correctly | ||
| 227 | $master testrdb.set.before value1_master | ||
| 228 | $replica testrdb.set.before value1_replica | ||
| 229 | |||
| 230 | # Put different data sets on the master and replica | ||
| 231 | # We need to put large keys on the master since the replica replies to info only once in 2mb | ||
| 232 | $replica debug populate 200 slave 10 | ||
| 233 | $master debug populate 1000 master 100000 | ||
| 234 | $master config set rdbcompression no | ||
| 235 | |||
| 236 | # Force the replica to try another full sync (this time it will have matching master replid) | ||
| 237 | $master multi | ||
| 238 | $master client kill type replica | ||
| 239 | # Fill replication backlog with new content | ||
| 240 | $master config set repl-backlog-size 16384 | ||
| 241 | for {set keyid 0} {$keyid < 10} {incr keyid} { | ||
| 242 | $master set "$keyid string_$keyid" [string repeat A 16384] | ||
| 243 | } | ||
| 244 | $master exec | ||
| 245 | |||
| 246 | switch $testType { | ||
| 247 | "Aborted" { | ||
| 248 | # Set master with a slow rdb generation, so that we can easily intercept loading | ||
| 249 | # 10ms per key, with 1000 keys is 10 seconds | ||
| 250 | $master config set rdb-key-save-delay 10000 | ||
| 251 | |||
| 252 | test {Diskless load swapdb RedisModuleEvent_ReplAsyncLoad handling: during loading, can keep module variable same as before} { | ||
| 253 | # Wait for the replica to start reading the rdb and module for acknowledgement | ||
| 254 | # We wanna abort only after the temp db was populated by REDISMODULE_AUX_BEFORE_RDB | ||
| 255 | wait_for_condition 100 100 { | ||
| 256 | [s -1 async_loading] eq 1 && [$replica testrdb.async_loading.get.before] eq "value1_master" | ||
| 257 | } else { | ||
| 258 | fail "Module didn't receive or react to REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED" | ||
| 259 | } | ||
| 260 | |||
| 261 | assert_equal [$replica dbsize] 200 | ||
| 262 | assert_equal value1_replica [$replica testrdb.get.before] | ||
| 263 | } | ||
| 264 | |||
| 265 | # Make sure that next sync will not start immediately so that we can catch the replica in between syncs | ||
| 266 | $master config set repl-diskless-sync-delay 5 | ||
| 267 | |||
| 268 | # Kill the replica connection on the master | ||
| 269 | set killed [$master client kill type replica] | ||
| 270 | |||
| 271 | test {Diskless load swapdb RedisModuleEvent_ReplAsyncLoad handling: when loading aborted, can keep module variable same as before} { | ||
| 272 | # Wait for loading to stop (fail) and module for acknowledgement | ||
| 273 | wait_for_condition 100 100 { | ||
| 274 | [s -1 async_loading] eq 0 && [$replica testrdb.async_loading.get.before] eq "" | ||
| 275 | } else { | ||
| 276 | fail "Module didn't receive or react to REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED" | ||
| 277 | } | ||
| 278 | |||
| 279 | assert_equal [$replica dbsize] 200 | ||
| 280 | assert_equal value1_replica [$replica testrdb.get.before] | ||
| 281 | } | ||
| 282 | |||
| 283 | # Speed up shutdown | ||
| 284 | $master config set rdb-key-save-delay 0 | ||
| 285 | } | ||
| 286 | "Successful" { | ||
| 287 | # Let replica finish sync with master | ||
| 288 | wait_for_condition 100 100 { | ||
| 289 | [s -1 master_link_status] eq "up" | ||
| 290 | } else { | ||
| 291 | fail "Master <-> Replica didn't finish sync" | ||
| 292 | } | ||
| 293 | |||
| 294 | test {Diskless load swapdb RedisModuleEvent_ReplAsyncLoad handling: after db loaded, can set module variable with new value} { | ||
| 295 | assert_equal [$replica dbsize] 1010 | ||
| 296 | assert_equal value1_master [$replica testrdb.get.before] | ||
| 297 | } | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | if {$::verbose} { | ||
| 302 | set end [clock clicks -milliseconds] | ||
| 303 | set duration [expr $end - $start] | ||
| 304 | puts "test took $duration ms" | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | } | ||
| 309 | } | ||
| 310 | } | ||
| 311 | } | ||
