From e9b7c9a5b49972c0c69ecd950b733ce2d8cf9264 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 16 Mar 2024 17:28:05 +0900 Subject: [PATCH 1/2] fix race condition when context is canceled --- connection.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/connection.go b/connection.go index 55e42eb18..83108ef60 100644 --- a/connection.go +++ b/connection.go @@ -439,7 +439,13 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { // finish is called when the query has canceled. func (mc *mysqlConn) cancel(err error) { mc.canceled.Set(err) - mc.cleanup() + nc := mc.netConn + if nc != nil { + _ = nc.SetDeadline(time.Now()) // wake up pending reads/writes + // Ignore error because: + // - If the connection is already closed, thats fine. + // - If the connection return error other reasons, we can not do anything about it. + } } // finish is called when the query has succeeded. From a832658d58a55148eb6c7cbd424039ed64fbe93e Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 16 Mar 2024 09:57:34 +0000 Subject: [PATCH 2/2] fix race, another try --- connection.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/connection.go b/connection.go index 83108ef60..3197eab26 100644 --- a/connection.go +++ b/connection.go @@ -133,7 +133,7 @@ func (mc *mysqlConn) Close() (err error) { } mc.cleanup() - + mc.clearResult() return } @@ -148,13 +148,16 @@ func (mc *mysqlConn) cleanup() { // Makes cleanup idempotent close(mc.closech) - if mc.netConn == nil { + nc := mc.netConn + if nc == nil { return } - if err := mc.netConn.Close(); err != nil { + if err := nc.Close(); err != nil { mc.cfg.Logger.Print(err) } - mc.clearResult() + // This function can be called from multiple goroutines. + // So we can not mc.clearResult() here. + // Caller should do it if they are in safe goroutine. } func (mc *mysqlConn) error() error { @@ -439,13 +442,7 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { // finish is called when the query has canceled. func (mc *mysqlConn) cancel(err error) { mc.canceled.Set(err) - nc := mc.netConn - if nc != nil { - _ = nc.SetDeadline(time.Now()) // wake up pending reads/writes - // Ignore error because: - // - If the connection is already closed, thats fine. - // - If the connection return error other reasons, we can not do anything about it. - } + mc.cleanup() } // finish is called when the query has succeeded.