From 12b611b374ef5f9ee2472b560a2fc3e5cc6c2dba Mon Sep 17 00:00:00 2001 From: guybe7 Date: Thu, 28 Dec 2023 16:27:58 +0700 Subject: [PATCH] WAITAOF: Try to wake blocked clients ASAP in the next beforeSleep (#12627) In case server.fsynced_reploff changed (e.g. flushAppendOnly set it to server.master_repl_offset in case there was nothing to fsync) we want to avoid sleeping before the next beforeSleep so we can call blockedBeforeSleep ASAP. without that, in case there's no incoming traffic, we could be waiting for the next cron timer event to wake us up. --- src/server.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/server.c b/src/server.c index 0b45616c3..5a17446dc 100644 --- a/src/server.c +++ b/src/server.c @@ -1724,7 +1724,7 @@ void beforeSleep(struct aeEventLoop *eventLoop) { connTypeProcessPendingData(); /* If any connection type(typical TLS) still has pending unread data don't sleep at all. */ - aeSetDontWait(server.el, connTypeHasPendingData()); + int dont_sleep = connTypeHasPendingData(); /* Call the Redis Cluster before sleep function. Note that this function * may change the state of Redis Cluster (from ok to fail or vice versa), @@ -1786,6 +1786,8 @@ void beforeSleep(struct aeEventLoop *eventLoop) { monotime aof_start_time = getMonotonicUs(); /* Record cron time in beforeSleep. This does not include the time consumed by AOF writing and IO writing below. */ monotime duration_before_aof = aof_start_time - cron_start_time_before_aof; + /* Record the fsync'd offset before flushAppendOnly */ + long long prev_fsynced_reploff = server.fsynced_reploff; /* Write the AOF buffer on disk, * must be done before handleClientsWithPendingWritesUsingThreads, @@ -1803,6 +1805,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) { long long fsynced_reploff_pending; atomicGet(server.fsynced_reploff_pending, fsynced_reploff_pending); server.fsynced_reploff = fsynced_reploff_pending; + + /* If we have blocked [WAIT]AOF clients, and fsynced_reploff changed, we want to try to + * wake them up ASAP. */ + if (listLength(server.clients_waiting_acks) && prev_fsynced_reploff != server.fsynced_reploff) + dont_sleep = 1; } /* Handle writes with pending output buffers. */ @@ -1841,6 +1848,10 @@ void beforeSleep(struct aeEventLoop *eventLoop) { } } + /* Don't sleep at all before the next beforeSleep() if needed (e.g. a + * connection has pending data) */ + aeSetDontWait(server.el, dont_sleep); + /* Before we are going to sleep, let the threads access the dataset by * releasing the GIL. Redis main thread will not touch anything at this * time. */