AOF: fix a bug that may prevent proper fsyncing when fsync=always.

In case the write handler is already installed, it could happen that we
serve the reply of a query in the same event loop cycle we received it,
preventing beforeSleep() from guaranteeing that we do the AOF fsync
before sending the reply to the client.

The AE_BARRIER mechanism, introduced in a previous commit, prevents this
problem. This commit makes actual use of this new feature to fix the
bug.
This commit is contained in:
antirez 2018-02-27 10:40:40 +01:00
parent 533d0e0375
commit 75987431f0

View File

@ -1044,15 +1044,27 @@ int handleClientsWithPendingWrites(void) {
/* Try to write buffers to the client socket. */ /* Try to write buffers to the client socket. */
if (writeToClient(c->fd,c,0) == C_ERR) continue; if (writeToClient(c->fd,c,0) == C_ERR) continue;
/* If there is nothing left, do nothing. Otherwise install /* If after the synchronous writes above we still have data to
* the write handler. */ * output to the client, we need to install the writable handler. */
if (clientHasPendingReplies(c) && if (clientHasPendingReplies(c)) {
aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, int ae_flags = AE_WRITABLE;
/* For the fsync=always policy, we want that a given FD is never
* served for reading and writing in the same event loop iteration,
* so that in the middle of receiving the query, and serving it
* to the client, we'll call beforeSleep() that will do the
* actual fsync of AOF to disk. AE_BARRIER ensures that. */
if (server.aof_state == AOF_ON &&
server.aof_fsync == AOF_FSYNC_ALWAYS)
{
ae_flags |= AE_BARRIER;
}
if (aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
sendReplyToClient, c) == AE_ERR) sendReplyToClient, c) == AE_ERR)
{ {
freeClientAsync(c); freeClientAsync(c);
} }
} }
}
return processed; return processed;
} }