Skip to content

Commit

Permalink
server: fix potential goroutine leak when kill connection (#13051) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
SunRunAway authored and sre-bot committed Nov 8, 2019
1 parent cb2b715 commit f89feef
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
18 changes: 10 additions & 8 deletions server/conn.go
Expand Up @@ -1192,21 +1192,23 @@ func (cc *clientConn) handleLoadStats(ctx context.Context, loadStatsInfo *execut
// There is a special query `load data` that does not return result, which is handled differently.
// Query `load stats` does not return result either.
func (cc *clientConn) handleQuery(ctx context.Context, sql string) (err error) {
rs, err := cc.ctx.Execute(ctx, sql)
rss, err := cc.ctx.Execute(ctx, sql)
if err != nil {
metrics.ExecuteErrorCounter.WithLabelValues(metrics.ExecuteErrorToLabel(err)).Inc()
return err
}
status := atomic.LoadInt32(&cc.status)
if status == connStatusShutdown || status == connStatusWaitShutdown {
killConn(cc)
return errors.New("killed by another connection")
if rss != nil && (status == connStatusShutdown || status == connStatusWaitShutdown) {
for _, rs := range rss {
terror.Call(rs.Close)
}
return executor.ErrQueryInterrupted
}
if rs != nil {
if len(rs) == 1 {
err = cc.writeResultset(ctx, rs[0], false, 0, 0)
if rss != nil {
if len(rss) == 1 {
err = cc.writeResultset(ctx, rss[0], false, 0, 0)
} else {
err = cc.writeMultiResultset(ctx, rs, false)
err = cc.writeMultiResultset(ctx, rss, false)
}
} else {
loadDataInfo := cc.ctx.Value(executor.LoadDataVarKey)
Expand Down
39 changes: 39 additions & 0 deletions server/conn_test.go
Expand Up @@ -23,12 +23,16 @@ import (

. "github.com/pingcap/check"
"github.com/pingcap/failpoint"
"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/executor"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/store/mockstore"
"github.com/pingcap/tidb/util/arena"
"github.com/pingcap/tidb/util/chunk"
)

type ConnTestSuite struct {
Expand Down Expand Up @@ -284,3 +288,38 @@ func (ts ConnTestSuite) TestConnExecutionTimeout(c *C) {

c.Assert(failpoint.Disable("github.com/pingcap/tidb/server/FakeClientConn"), IsNil)
}

type mockTiDBCtx struct {
TiDBContext
rs []ResultSet
err error
}

func (c *mockTiDBCtx) Execute(ctx context.Context, sql string) ([]ResultSet, error) {
return c.rs, c.err
}

func (c *mockTiDBCtx) GetSessionVars() *variable.SessionVars {
return &variable.SessionVars{}
}

type mockRecordSet struct{}

func (m mockRecordSet) Fields() []*ast.ResultField { return nil }
func (m mockRecordSet) Next(ctx context.Context, req *chunk.Chunk) error { return nil }
func (m mockRecordSet) NewChunk() *chunk.Chunk { return nil }
func (m mockRecordSet) Close() error { return nil }

func (ts *ConnTestSuite) TestShutDown(c *C) {
cc := &clientConn{}

rs := &tidbResultSet{recordSet: mockRecordSet{}}
// mock delay response
cc.ctx = &mockTiDBCtx{rs: []ResultSet{rs}, err: nil}
// set killed flag
cc.status = connStatusShutdown
// assert ErrQueryInterrupted
err := cc.handleQuery(context.Background(), "dummy")
c.Assert(err, Equals, executor.ErrQueryInterrupted)
c.Assert(rs.closed, Equals, int32(1))
}

0 comments on commit f89feef

Please sign in to comment.