summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/replication.c53
-rw-r--r--tests/support/util.tcl4
-rw-r--r--tests/unit/wait.tcl74
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