Skip to content

Commit 410d3ef

Browse files
committed
statistics: release session met error to avoid possible leak
1 parent 27f8ff3 commit 410d3ef

File tree

7 files changed

+58
-0
lines changed

7 files changed

+58
-0
lines changed

pkg/domain/infosync/info.go

+13
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,19 @@ func DeleteInternalSession(se any) {
13391339
sm.DeleteInternalSession(se)
13401340
}
13411341

1342+
// HasInternalSessionForTest is the entry function for check whether an internal session is stored in SessionManager.
1343+
func HasInternalSessionForTest(se any) bool {
1344+
is, err := getGlobalInfoSyncer()
1345+
if err != nil {
1346+
return false
1347+
}
1348+
sm := is.GetSessionManager()
1349+
if sm == nil {
1350+
return false
1351+
}
1352+
return sm.HasInternalSessionForTest(se)
1353+
}
1354+
13421355
// SetEtcdClient is only used for test.
13431356
func SetEtcdClient(etcdCli *clientv3.Client) {
13441357
is, err := getGlobalInfoSyncer()

pkg/server/server.go

+8
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,14 @@ func (s *Server) StoreInternalSession(se any) {
10641064
s.sessionMapMutex.Unlock()
10651065
}
10661066

1067+
// HasInternalSessionForTest implements SessionManager interface.
1068+
func (s *Server) HasInternalSessionForTest(se any) bool {
1069+
s.sessionMapMutex.Lock()
1070+
_, ok := s.internalSessions[se]
1071+
s.sessionMapMutex.Unlock()
1072+
return ok
1073+
}
1074+
10671075
// DeleteInternalSession implements SessionManager interface.
10681076
// @param addr The address of a session.session struct variable
10691077
func (s *Server) DeleteInternalSession(se any) {

pkg/statistics/handle/util/BUILD.bazel

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ go_library(
1212
importpath = "github.com/pingcap/tidb/pkg/statistics/handle/util",
1313
visibility = ["//visibility:public"],
1414
deps = [
15+
"//pkg/domain/infosync",
1516
"//pkg/infoschema",
1617
"//pkg/kv",
1718
"//pkg/meta/model",
@@ -45,7 +46,10 @@ go_test(
4546
flaky = True,
4647
deps = [
4748
":util",
49+
"//pkg/domain/infosync",
50+
"//pkg/sessionctx",
4851
"//pkg/testkit",
52+
"@com_github_pingcap_errors//:errors",
4953
"@com_github_stretchr_testify//require",
5054
],
5155
)

pkg/statistics/handle/util/util.go

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/pingcap/errors"
2323
"github.com/pingcap/failpoint"
24+
"github.com/pingcap/tidb/pkg/domain/infosync"
2425
"github.com/pingcap/tidb/pkg/kv"
2526
"github.com/pingcap/tidb/pkg/meta/model"
2627
"github.com/pingcap/tidb/pkg/metrics"
@@ -85,6 +86,8 @@ func CallWithSCtx(pool util.SessionPool, f func(sctx sessionctx.Context) error,
8586
defer func() {
8687
if err == nil { // only recycle when no error
8788
pool.Put(se)
89+
} else {
90+
infosync.DeleteInternalSession(se)
8891
}
8992
}()
9093
sctx := se.(sessionctx.Context)

pkg/statistics/handle/util/util_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ package util_test
1717
import (
1818
"testing"
1919

20+
"github.com/pingcap/errors"
21+
"github.com/pingcap/tidb/pkg/domain/infosync"
22+
"github.com/pingcap/tidb/pkg/sessionctx"
2023
"github.com/pingcap/tidb/pkg/statistics/handle/util"
2124
"github.com/pingcap/tidb/pkg/testkit"
2225
"github.com/stretchr/testify/require"
@@ -55,3 +58,17 @@ func TestIsSpecialGlobalIndex(t *testing.T) {
5558
}
5659
require.Equal(t, cnt, len(tblInfo.Indices))
5760
}
61+
62+
func TestCallSCtxFailed(t *testing.T) {
63+
_, dom := testkit.CreateMockStoreAndDomain(t)
64+
65+
var sctxWithFailure sessionctx.Context
66+
err := util.CallWithSCtx(dom.StatsHandle().SPool(), func(sctx sessionctx.Context) error {
67+
sctxWithFailure = sctx
68+
return errors.New("simulated error")
69+
})
70+
notReleased := infosync.HasInternalSessionForTest(sctxWithFailure)
71+
require.Error(t, err)
72+
require.Equal(t, "simulated error", err.Error())
73+
require.False(t, notReleased)
74+
}

pkg/testkit/mocksessionmanager.go

+11
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,17 @@ func (msm *MockSessionManager) StoreInternalSession(s any) {
137137
msm.mu.Unlock()
138138
}
139139

140+
// HasInternalSessionForTest is to check whether the internal session is stored in the SessionManager
141+
func (msm *MockSessionManager) HasInternalSessionForTest(se any) bool {
142+
msm.mu.Lock()
143+
defer msm.mu.Unlock()
144+
if msm.internalSessions == nil {
145+
return false
146+
}
147+
_, ok := msm.internalSessions[se]
148+
return ok
149+
}
150+
140151
// DeleteInternalSession is to delete the internal session pointer from the map in the SessionManager
141152
func (msm *MockSessionManager) DeleteInternalSession(s any) {
142153
msm.mu.Lock()

pkg/util/processinfo.go

+2
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ type SessionManager interface {
218218
ServerID() uint64
219219
// StoreInternalSession puts the internal session pointer to the map in the SessionManager.
220220
StoreInternalSession(se any)
221+
// HasInternalSessionForTest checks whether the internal session is stored in the SessionManager.
222+
HasInternalSessionForTest(se any) bool
221223
// DeleteInternalSession deletes the internal session pointer from the map in the SessionManager.
222224
DeleteInternalSession(se any)
223225
// GetInternalSessionStartTSList gets all startTS of every transactions running in the current internal sessions.

0 commit comments

Comments
 (0)