Skip to content

Commit

Permalink
statistics: fix panic when getStatsReader fail (pingcap#15651)
Browse files Browse the repository at this point in the history
  • Loading branch information
winoros authored and sre-bot committed Mar 26, 2020
1 parent dc1152c commit 3443783
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
19 changes: 13 additions & 6 deletions statistics/handle/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"time"

"github.com/pingcap/errors"
"github.com/pingcap/failpoint"
"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
Expand Down Expand Up @@ -283,15 +284,16 @@ func (sc statsCache) update(tables []*statistics.Table, deletedIDs []int64, newV
func (h *Handle) LoadNeededHistograms() (err error) {
cols := statistics.HistogramNeededColumns.AllCols()
reader, err := h.getStatsReader(nil)
if err != nil {
return err
}

defer func() {
err1 := h.releaseStatsReader(reader)
if err1 != nil && err == nil {
err = err1
}
}()
if err != nil {
return err
}

for _, col := range cols {
statsCache := h.statsCache.Load().(statsCache)
Expand Down Expand Up @@ -498,15 +500,15 @@ func (h *Handle) columnStatsFromStorage(reader *statsReader, row chunk.Row, tabl
// tableStatsFromStorage loads table stats info from storage.
func (h *Handle) tableStatsFromStorage(tableInfo *model.TableInfo, physicalID int64, loadAll bool, historyStatsExec sqlexec.RestrictedSQLExecutor) (_ *statistics.Table, err error) {
reader, err := h.getStatsReader(historyStatsExec)
if err != nil {
return nil, err
}
defer func() {
err1 := h.releaseStatsReader(reader)
if err == nil && err1 != nil {
err = err1
}
}()
if err != nil {
return nil, err
}
table, ok := h.statsCache.Load().(statsCache).tables[physicalID]
// If table stats is pseudo, we also need to copy it, since we will use the column stats when
// the average error rate of it is small.
Expand Down Expand Up @@ -771,6 +773,11 @@ func (sr *statsReader) isHistory() bool {
}

func (h *Handle) getStatsReader(history sqlexec.RestrictedSQLExecutor) (*statsReader, error) {
failpoint.Inject("mockGetStatsReaderFail", func(val failpoint.Value) {
if val.(bool) {
failpoint.Return(nil, errors.New("gofail genStatsReader error"))
}
})
if history != nil {
return &statsReader{history: history}, nil
}
Expand Down
6 changes: 6 additions & 0 deletions statistics/handle/handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

. "github.com/pingcap/check"
"github.com/pingcap/errors"
"github.com/pingcap/failpoint"
"github.com/pingcap/parser/model"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/kv"
Expand Down Expand Up @@ -433,6 +434,11 @@ func (s *testStatsSuite) TestLoadStats(c *C) {
stat = h.GetTableStats(tableInfo)
hg = stat.Columns[tableInfo.Columns[2].ID].Histogram
c.Assert(hg.Len(), Greater, 0)
// Following test tests whether the LoadNeededHistograms would panic.
c.Assert(failpoint.Enable("github.com/pingcap/tidb/statistics/handle/mockGetStatsReaderFail", `return(true)`), IsNil)
err = h.LoadNeededHistograms()
c.Assert(err, NotNil)
c.Assert(failpoint.Disable("github.com/pingcap/tidb/statistics/handle/mockGetStatsReaderFail"), IsNil)
}

func newStoreWithBootstrap() (kv.Storage, *domain.Domain, error) {
Expand Down

0 comments on commit 3443783

Please sign in to comment.