diff options
-rw-r--r-- | src/replication.c | 53 | ||||
-rw-r--r-- | tests/support/util.tcl | 4 | ||||
-rw-r--r-- | tests/unit/wait.tcl | 74 |
3 files changed, 98 insertions, 33 deletions
diff --git a/src/replication.c b/src/replication.c index 0e575111b..152980dc0 100644 --- a/src/replication.c +++ b/src/replication.c @@ -3575,7 +3575,7 @@ void waitaofCommand(client *c) { return; } if (numlocal && !server.aof_enabled) { - addReplyError(c,"WAITAOF cannot be used when appendonly is disabled"); + addReplyError(c, "WAITAOF cannot be used when numlocal is set but appendonly is disabled."); return; } @@ -3619,51 +3619,56 @@ void processClientsWaitingReplicas(void) { listRewind(server.clients_waiting_acks,&li); while((ln = listNext(&li))) { + int numlocal = 0; + int numreplicas = 0; + client *c = ln->value; int is_wait_aof = c->bstate.btype == BLOCKED_WAITAOF; if (is_wait_aof && c->bstate.numlocal && !server.aof_enabled) { + addReplyError(c, "WAITAOF cannot be used when numlocal is set but appendonly is disabled."); unblockClient(c); - addReplyError(c,"WAITAOF cannot be used when appendonly is disabled"); return; } /* Every time we find a client that is satisfied for a given * offset and number of replicas, we remember it so the next client * may be unblocked without calling replicationCountAcksByOffset() + * or calling replicationCountAOFAcksByOffset() * if the requested offset / replicas were equal or less. */ if (last_offset && last_offset >= c->bstate.reploffset && last_numreplicas >= c->bstate.numreplicas) { - /* Reply before unblocking, because unblock client calls reqresAppendResponse */ - addReplyLongLong(c,last_numreplicas); - unblockClient(c); + numreplicas = last_numreplicas; } else { - int numreplicas = is_wait_aof ? + numreplicas = is_wait_aof ? replicationCountAOFAcksByOffset(c->bstate.reploffset) : replicationCountAcksByOffset(c->bstate.reploffset); - if (numreplicas >= c->bstate.numreplicas) { - last_offset = c->bstate.reploffset; - last_numreplicas = numreplicas; + /* Check if the number of replicas is satisfied. */ + if (numreplicas < c->bstate.numreplicas) continue; - /* Check if the local constraint of WAITAOF is served */ - int numlocal = server.fsynced_reploff >= c->bstate.reploffset; - if (is_wait_aof && numlocal < c->bstate.numlocal) - continue; + last_offset = c->bstate.reploffset; + last_numreplicas = numreplicas; + } - if (is_wait_aof) { - /* WAITAOF has an array reply*/ - addReplyArrayLen(c,2); - addReplyLongLong(c,numlocal); - addReplyLongLong(c,numreplicas); - } else { - addReplyLongLong(c,numreplicas); - } - /* Reply before unblocking, because unblock client calls reqresAppendResponse */ - unblockClient(c); - } + /* Check if the local constraint of WAITAOF is served */ + if (is_wait_aof) { + numlocal = server.fsynced_reploff >= c->bstate.reploffset; + if (numlocal < c->bstate.numlocal) continue; } + + /* Reply before unblocking, because unblock client calls reqresAppendResponse */ + if (is_wait_aof) { + /* WAITAOF has an array reply */ + addReplyArrayLen(c, 2); + addReplyLongLong(c, numlocal); + addReplyLongLong(c, numreplicas); + } else { + addReplyLongLong(c, numreplicas); + } + + unblockClient(c); } } diff --git a/tests/support/util.tcl b/tests/support/util.tcl index 062f33a14..236fad314 100644 --- a/tests/support/util.tcl +++ b/tests/support/util.tcl @@ -886,9 +886,9 @@ proc wait_for_blocked_client {{idx 0}} { } } -proc wait_for_blocked_clients_count {count {maxtries 100} {delay 10}} { +proc wait_for_blocked_clients_count {count {maxtries 100} {delay 10} {idx 0}} { wait_for_condition $maxtries $delay { - [s blocked_clients] == $count + [s $idx blocked_clients] == $count } else { fail "Timeout waiting for blocked clients" } diff --git a/tests/unit/wait.tcl b/tests/unit/wait.tcl index 7e040fbc0..8990965d5 100644 --- a/tests/unit/wait.tcl +++ b/tests/unit/wait.tcl @@ -18,20 +18,20 @@ start_server {} { fail "Replication not started." } } - + test {WAIT out of range timeout (milliseconds)} { # Timeout is parsed as milliseconds by getLongLongFromObjectOrReply(). # Verify we get out of range message if value is behind LLONG_MAX # (decimal value equals to 0x8000000000000000) assert_error "*or out of range*" {$master wait 2 9223372036854775808} - + # expected to fail by later overflow condition after addition # of mstime(). (decimal value equals to 0x7FFFFFFFFFFFFFFF) assert_error "*timeout is out of range*" {$master wait 2 9223372036854775807} - - assert_error "*timeout is negative*" {$master wait 2 -1} + + assert_error "*timeout is negative*" {$master wait 2 -1} } - + test {WAIT should acknowledge 1 additional copy of the data} { $master set foo 0 $master incr foo @@ -68,6 +68,36 @@ start_server {} { exec kill -SIGCONT $slave_pid assert {[$master wait 1 1000] == 1} } + + test {WAIT replica multiple clients unblock - reuse last result} { + set rd [redis_deferring_client -1] + set rd2 [redis_deferring_client -1] + + exec kill -SIGSTOP $slave_pid + + $rd incr foo + $rd read + + $rd2 incr foo + $rd2 read + + $rd wait 1 0 + $rd2 wait 1 0 + wait_for_blocked_clients_count 2 100 10 -1 + + exec kill -SIGCONT $slave_pid + + assert_equal [$rd read] {1} + assert_equal [$rd2 read] {1} + + $rd ping + assert_equal [$rd read] {PONG} + $rd2 ping + assert_equal [$rd2 read] {PONG} + + $rd close + $rd2 close + } }} @@ -101,13 +131,13 @@ tags {"wait aof network external:skip"} { $rd waitaof 1 0 0 wait_for_blocked_client r config set appendonly no ;# this should release the blocked client as an error - assert_error {ERR WAITAOF cannot be used when appendonly is disabled} {$rd read} + assert_error {ERR WAITAOF cannot be used when numlocal is set but appendonly is disabled.} {$rd read} $rd close } test {WAITAOF local on server with aof disabled} { $master incr foo - assert_error {ERR WAITAOF cannot be used when appendonly is disabled} {$master waitaof 1 0 0} + assert_error {ERR WAITAOF cannot be used when numlocal is set but appendonly is disabled.} {$master waitaof 1 0 0} } $master config set appendonly yes @@ -164,6 +194,36 @@ tags {"wait aof network external:skip"} { assert_equal [$master waitaof 0 1 0] {1 1} } + test {WAITAOF replica multiple clients unblock - reuse last result} { + set rd [redis_deferring_client -1] + set rd2 [redis_deferring_client -1] + + exec kill -SIGSTOP $replica_pid + + $rd incr foo + $rd read + + $rd2 incr foo + $rd2 read + + $rd waitaof 0 1 0 + $rd2 waitaof 0 1 0 + wait_for_blocked_clients_count 2 100 10 -1 + + exec kill -SIGCONT $replica_pid + + assert_equal [$rd read] {1 1} + assert_equal [$rd2 read] {1 1} + + $rd ping + assert_equal [$rd read] {PONG} + $rd2 ping + assert_equal [$rd2 read] {PONG} + + $rd close + $rd2 close + } + test {WAITAOF on promoted replica} { $replica replicaof no one $replica incr foo |