From 17c3e3d8a23543d5e9375f2584faf17cb24b05f2 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Thu, 11 Jan 2018 22:46:58 +0800 Subject: [PATCH] store/tikv: call Next() after copIterator Closed lead to goroutine leak After Close(), worker groutine receive from copIterator.finished and exit directly, without writing any thing to taskCh. Next() receives from taskCh and may hang forever, cause the caller goroutine leak. --- store/tikv/coprocessor.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/store/tikv/coprocessor.go b/store/tikv/coprocessor.go index b828c5c1d00da..bfa6406972cd1 100644 --- a/store/tikv/coprocessor.go +++ b/store/tikv/coprocessor.go @@ -393,6 +393,15 @@ func (it *copIterator) run(ctx goctx.Context) { }) } +func recvFromRespCh(respCh <-chan copResponse, finished <-chan struct{}) (resp copResponse, ok bool, exit bool) { + select { + case resp, ok = <-respCh: + case <-finished: + exit = true + } + return +} + func (it *copIterator) sendToTaskCh(ctx goctx.Context, t *copTask, taskCh chan<- *copTask) (finished bool, canceled bool) { select { case taskCh <- t: @@ -421,13 +430,18 @@ func (it *copIterator) Next() ([]byte, error) { return nil, nil } } else { + var closed bool for { if it.curr >= len(it.tasks) { // Resp will be nil if iterator is finished. return nil, nil } task := it.tasks[it.curr] - resp, ok = <-task.respChan + resp, ok, closed = recvFromRespCh(task.respChan, it.finished) + if closed { + // Close() is already called, so Next() is invalid. + return nil, nil + } if ok { break }