1proc log_file_matches {log pattern} { 2 set fp [open $log r] 3 set content [read $fp] 4 close $fp 5 string match $pattern $content 6} 7 8start_server {tags {"repl"}} { 9 set slave [srv 0 client] 10 set slave_host [srv 0 host] 11 set slave_port [srv 0 port] 12 set slave_log [srv 0 stdout] 13 start_server {} { 14 set master [srv 0 client] 15 set master_host [srv 0 host] 16 set master_port [srv 0 port] 17 18 # Configure the master in order to hang waiting for the BGSAVE 19 # operation, so that the slave remains in the handshake state. 20 $master config set repl-diskless-sync yes 21 $master config set repl-diskless-sync-delay 1000 22 23 # Use a short replication timeout on the slave, so that if there 24 # are no bugs the timeout is triggered in a reasonable amount 25 # of time. 26 $slave config set repl-timeout 5 27 28 # Start the replication process... 29 $slave slaveof $master_host $master_port 30 31 test {Slave enters handshake} { 32 wait_for_condition 50 1000 { 33 [string match *handshake* [$slave role]] 34 } else { 35 fail "Slave does not enter handshake state" 36 } 37 } 38 39 # But make the master unable to send 40 # the periodic newlines to refresh the connection. The slave 41 # should detect the timeout. 42 $master debug sleep 10 43 44 test {Slave is able to detect timeout during handshake} { 45 wait_for_condition 50 1000 { 46 [log_file_matches $slave_log "*Timeout connecting to the MASTER*"] 47 } else { 48 fail "Slave is not able to detect timeout" 49 } 50 } 51 } 52} 53 54start_server {tags {"repl"}} { 55 set A [srv 0 client] 56 set A_host [srv 0 host] 57 set A_port [srv 0 port] 58 start_server {} { 59 set B [srv 0 client] 60 set B_host [srv 0 host] 61 set B_port [srv 0 port] 62 63 test {Set instance A as slave of B} { 64 $A slaveof $B_host $B_port 65 wait_for_condition 50 100 { 66 [lindex [$A role] 0] eq {slave} && 67 [string match {*master_link_status:up*} [$A info replication]] 68 } else { 69 fail "Can't turn the instance into a slave" 70 } 71 } 72 73 test {BRPOPLPUSH replication, when blocking against empty list} { 74 set rd [redis_deferring_client] 75 $rd brpoplpush a b 5 76 r lpush a foo 77 wait_for_condition 50 100 { 78 [$A debug digest] eq [$B debug digest] 79 } else { 80 fail "Master and slave have different digest: [$A debug digest] VS [$B debug digest]" 81 } 82 } 83 84 test {BRPOPLPUSH replication, list exists} { 85 set rd [redis_deferring_client] 86 r lpush c 1 87 r lpush c 2 88 r lpush c 3 89 $rd brpoplpush c d 5 90 after 1000 91 assert_equal [$A debug digest] [$B debug digest] 92 } 93 94 test {BLPOP followed by role change, issue #2473} { 95 set rd [redis_deferring_client] 96 $rd blpop foo 0 ; # Block while B is a master 97 98 # Turn B into master of A 99 $A slaveof no one 100 $B slaveof $A_host $A_port 101 wait_for_condition 50 100 { 102 [lindex [$B role] 0] eq {slave} && 103 [string match {*master_link_status:up*} [$B info replication]] 104 } else { 105 fail "Can't turn the instance into a slave" 106 } 107 108 # Push elements into the "foo" list of the new slave. 109 # If the client is still attached to the instance, we'll get 110 # a desync between the two instances. 111 $A rpush foo a b c 112 after 100 113 114 wait_for_condition 50 100 { 115 [$A debug digest] eq [$B debug digest] && 116 [$A lrange foo 0 -1] eq {a b c} && 117 [$B lrange foo 0 -1] eq {a b c} 118 } else { 119 fail "Master and slave have different digest: [$A debug digest] VS [$B debug digest]" 120 } 121 } 122 } 123} 124 125start_server {tags {"repl"}} { 126 r set mykey foo 127 128 start_server {} { 129 test {Second server should have role master at first} { 130 s role 131 } {master} 132 133 test {SLAVEOF should start with link status "down"} { 134 r slaveof [srv -1 host] [srv -1 port] 135 s master_link_status 136 } {down} 137 138 test {The role should immediately be changed to "slave"} { 139 s role 140 } {slave} 141 142 wait_for_sync r 143 test {Sync should have transferred keys from master} { 144 r get mykey 145 } {foo} 146 147 test {The link status should be up} { 148 s master_link_status 149 } {up} 150 151 test {SET on the master should immediately propagate} { 152 r -1 set mykey bar 153 154 wait_for_condition 500 100 { 155 [r 0 get mykey] eq {bar} 156 } else { 157 fail "SET on master did not propagated on slave" 158 } 159 } 160 161 test {FLUSHALL should replicate} { 162 r -1 flushall 163 if {$::valgrind} {after 2000} 164 list [r -1 dbsize] [r 0 dbsize] 165 } {0 0} 166 167 test {ROLE in master reports master with a slave} { 168 set res [r -1 role] 169 lassign $res role offset slaves 170 assert {$role eq {master}} 171 assert {$offset > 0} 172 assert {[llength $slaves] == 1} 173 lassign [lindex $slaves 0] master_host master_port slave_offset 174 assert {$slave_offset <= $offset} 175 } 176 177 test {ROLE in slave reports slave in connected state} { 178 set res [r role] 179 lassign $res role master_host master_port slave_state slave_offset 180 assert {$role eq {slave}} 181 assert {$slave_state eq {connected}} 182 } 183 } 184} 185 186foreach dl {no yes} { 187 start_server {tags {"repl"}} { 188 set master [srv 0 client] 189 $master config set repl-diskless-sync $dl 190 set master_host [srv 0 host] 191 set master_port [srv 0 port] 192 set slaves {} 193 set load_handle0 [start_write_load $master_host $master_port 3] 194 set load_handle1 [start_write_load $master_host $master_port 5] 195 set load_handle2 [start_write_load $master_host $master_port 20] 196 set load_handle3 [start_write_load $master_host $master_port 8] 197 set load_handle4 [start_write_load $master_host $master_port 4] 198 start_server {} { 199 lappend slaves [srv 0 client] 200 start_server {} { 201 lappend slaves [srv 0 client] 202 start_server {} { 203 lappend slaves [srv 0 client] 204 test "Connect multiple slaves at the same time (issue #141), diskless=$dl" { 205 # Send SLAVEOF commands to slaves 206 [lindex $slaves 0] slaveof $master_host $master_port 207 [lindex $slaves 1] slaveof $master_host $master_port 208 [lindex $slaves 2] slaveof $master_host $master_port 209 210 # Wait for all the three slaves to reach the "online" 211 # state from the POV of the master. 212 set retry 500 213 while {$retry} { 214 set info [r -3 info] 215 if {[string match {*slave0:*state=online*slave1:*state=online*slave2:*state=online*} $info]} { 216 break 217 } else { 218 incr retry -1 219 after 100 220 } 221 } 222 if {$retry == 0} { 223 error "assertion:Slaves not correctly synchronized" 224 } 225 226 # Wait that slaves acknowledge they are online so 227 # we are sure that DBSIZE and DEBUG DIGEST will not 228 # fail because of timing issues. 229 wait_for_condition 500 100 { 230 [lindex [[lindex $slaves 0] role] 3] eq {connected} && 231 [lindex [[lindex $slaves 1] role] 3] eq {connected} && 232 [lindex [[lindex $slaves 2] role] 3] eq {connected} 233 } else { 234 fail "Slaves still not connected after some time" 235 } 236 237 # Stop the write load 238 stop_write_load $load_handle0 239 stop_write_load $load_handle1 240 stop_write_load $load_handle2 241 stop_write_load $load_handle3 242 stop_write_load $load_handle4 243 244 # Make sure that slaves and master have same 245 # number of keys 246 wait_for_condition 500 100 { 247 [$master dbsize] == [[lindex $slaves 0] dbsize] && 248 [$master dbsize] == [[lindex $slaves 1] dbsize] && 249 [$master dbsize] == [[lindex $slaves 2] dbsize] 250 } else { 251 fail "Different number of keys between masted and slave after too long time." 252 } 253 254 # Check digests 255 set digest [$master debug digest] 256 set digest0 [[lindex $slaves 0] debug digest] 257 set digest1 [[lindex $slaves 1] debug digest] 258 set digest2 [[lindex $slaves 2] debug digest] 259 assert {$digest ne 0000000000000000000000000000000000000000} 260 assert {$digest eq $digest0} 261 assert {$digest eq $digest1} 262 assert {$digest eq $digest2} 263 } 264 } 265 } 266 } 267 } 268} 269