To reduce memory churn during client list transfer (#14068)
CI / test-ubuntu-latest (push) Waiting to run Details
CI / test-sanitizer-address (push) Waiting to run Details
CI / build-debian-old (push) Waiting to run Details
CI / build-macos-latest (push) Waiting to run Details
CI / build-32bit (push) Waiting to run Details
CI / build-libc-malloc (push) Waiting to run Details
CI / build-centos-jemalloc (push) Waiting to run Details
CI / build-old-chain-jemalloc (push) Waiting to run Details
Codecov / code-coverage (push) Waiting to run Details
External Server Tests / test-external-standalone (push) Waiting to run Details
External Server Tests / test-external-cluster (push) Waiting to run Details
External Server Tests / test-external-nodebug (push) Waiting to run Details
Spellcheck / Spellcheck (push) Waiting to run Details

When we transfer clients between IO thread and main thread, the creation
and destruction of list nodes also consume some CPU. In this commit, we
reuse list nodes to avoid this issue.
This commit is contained in:
Yuan Wang 2025-05-23 19:21:29 +08:00 committed by GitHub
parent 645858d518
commit 7998a2a05f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 10 additions and 7 deletions

View File

@ -51,17 +51,18 @@ void enqueuePendingClientsToMainThread(client *c, int unbind) {
if (unbind) connUnbindEventLoop(c->conn);
/* Just skip if it already is transferred. */
if (c->io_thread_client_list_node) {
IOThread *t = &IOThreads[c->tid];
/* If there are several clients to process, let the main thread handle them ASAP.
* Since the client being added to the queue may still need to be processed by
* the IO thread, we must call this before adding it to the queue to avoid
* races with the main thread. */
sendPendingClientsToMainThreadIfNeeded(&IOThreads[c->tid], 1);
/* Remove the client from clients list of IO thread. */
listDelNode(IOThreads[c->tid].clients, c->io_thread_client_list_node);
c->io_thread_client_list_node = NULL;
sendPendingClientsToMainThreadIfNeeded(t, 1);
/* Disable read and write to avoid race when main thread processes. */
c->io_flags &= ~(CLIENT_IO_READ_ENABLED | CLIENT_IO_WRITE_ENABLED);
listAddNodeTail(IOThreads[c->tid].pending_clients_to_main_thread, c);
/* Remove the client from IO thread, add it to main thread's pending list. */
listUnlinkNode(t->clients, c->io_thread_client_list_node);
listLinkNodeTail(t->pending_clients_to_main_thread, c->io_thread_client_list_node);
c->io_thread_client_list_node = NULL;
}
}
@ -544,7 +545,8 @@ int processClientsFromMainThread(IOThread *t) {
/* Link client in IO thread clients list first. */
serverAssert(c->io_thread_client_list_node == NULL);
listAddNodeTail(t->clients, c);
listUnlinkNode(t->processing_clients, ln);
listLinkNodeTail(t->clients, ln);
c->io_thread_client_list_node = listLast(t->clients);
/* The client now is in the IO thread, let's free deferred objects. */
@ -575,7 +577,8 @@ int processClientsFromMainThread(IOThread *t) {
}
}
}
listEmpty(t->processing_clients);
/* All clients must are processed. */
serverAssert(listLength(t->processing_clients) == 0);
return processed;
}