This is an automated email from the ASF dual-hosted git repository.
git-hulk pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new d56980a82 fix(server): prevent connection migration during OnRead
(#3715)
d56980a82 is described below
commit d56980a8207a2eeda2c12f64b5419ef394d16aad
Author: hulk <[email protected]>
AuthorDate: Fri Oct 23 17:33:02 2026 +0800
fix(server): prevent connection migration during OnRead (#3715)
A discarded scope guard in `Connection::OnRead()` lets worker resizing
migrate a connection while it is still processing requests.
The temporary guard is destroyed at the end of its creation statement,
clearing `is_running_` immediately. The migration check then treats the
connection as idle even though the read callback has not returned.
Keep the guard active until the callback finishes, and cancel cleanup
when closing deletes the connection. Mark `MakeScopeExit()` as
`[[nodiscard]]` so the compiler diagnoses accidentally discarded guards.
Reference: [CI failure in `TestDynamicChangeWorkerThread` (Ubuntu GCC
TSan)](https://github.com/apache/kvrocks/actions/runs/39618363098/job/119287428395).
Assistant-By GPT-6
---
src/common/scope_exit.h | 2 +-
src/server/redis_connection.cc | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h
index 2faeddfb1..0fd47fd4d 100644
--- a/src/common/scope_exit.h
+++ b/src/common/scope_exit.h
@@ -47,6 +47,6 @@ struct ScopeExit {
// use CTAD in C++17 or above
template <typename F>
-ScopeExit<F> MakeScopeExit(F&& f, bool enabled = true) {
+[[nodiscard]] ScopeExit<F> MakeScopeExit(F&& f, bool enabled = true) {
return ScopeExit<F>(std::forward<F>(f), enabled);
}
diff --git a/src/server/redis_connection.cc b/src/server/redis_connection.cc
index f212966d8..9721aafbe 100644
--- a/src/server/redis_connection.cc
+++ b/src/server/redis_connection.cc
@@ -152,7 +152,7 @@ void Connection::Detach() { owner_->DetachConnection(this);
}
void Connection::OnRead([[maybe_unused]] struct bufferevent *bev) {
is_running_ = true;
- MakeScopeExit([this] { is_running_ = false; });
+ auto reset_running = MakeScopeExit([this] { is_running_ = false; });
SetLastInteraction();
auto s = req_.Tokenize(Input());
@@ -165,6 +165,8 @@ void Connection::OnRead([[maybe_unused]] struct bufferevent
*bev) {
ExecuteCommands(req_.GetCommands());
if (IsFlagEnabled(kCloseAsync)) {
+ // Close() deletes this, so the guard must not access it afterward.
+ reset_running.Disable();
Close();
}
}