diff --git a/pkg/statistics/handle/bootstrap.go b/pkg/statistics/handle/bootstrap.go index 1006fbce5a85f..41e1abd97a5a1 100644 --- a/pkg/statistics/handle/bootstrap.go +++ b/pkg/statistics/handle/bootstrap.go @@ -164,6 +164,12 @@ func (*Handle) initStatsHistograms4ChunkLite(cache statstypes.StatsCache, iter * } func (h *Handle) initStatsHistograms4Chunk(is infoschema.InfoSchema, cache statstypes.StatsCache, iter *chunk.Iterator4Chunk, isCacheFull bool) { + defer func() { + if r := recover(); r != nil { + logutil.BgLogger().Error("panic when initStatsHistograms4Chunk", zap.Any("r", r), + zap.Stack("stack")) + } + }() var table *statistics.Table for row := iter.Begin(); row != iter.End(); row = iter.Next() { tblID, statsVer := row.GetInt64(0), row.GetInt64(8) @@ -185,7 +191,12 @@ func (h *Handle) initStatsHistograms4Chunk(is infoschema.InfoSchema, cache stats } id, ndv, nullCount, version, totColSize := row.GetInt64(2), row.GetInt64(3), row.GetInt64(5), row.GetUint64(4), row.GetInt64(7) lastAnalyzePos := row.GetDatum(11, types.NewFieldType(mysql.TypeBlob)) - tbl, _ := h.TableInfoByID(is, table.PhysicalID) + tbl, ok := h.TableInfoByID(is, table.PhysicalID) + if !ok { + // this table has been dropped. but stats meta still exists and wait for being deleted. + logutil.BgLogger().Warn("cannot find this table when to init stats", zap.Int64("tableID", table.PhysicalID)) + continue + } if row.GetInt64(1) > 0 { var idxInfo *model.IndexInfo for _, idx := range tbl.Meta().Indices { diff --git a/pkg/statistics/handle/handletest/initstats/BUILD.bazel b/pkg/statistics/handle/handletest/initstats/BUILD.bazel index c5c3b99b15a86..1b7e6262b46dd 100644 --- a/pkg/statistics/handle/handletest/initstats/BUILD.bazel +++ b/pkg/statistics/handle/handletest/initstats/BUILD.bazel @@ -8,6 +8,7 @@ go_test( "main_test.go", ], flaky = True, + shard_count = 4, deps = [ "//pkg/config", "//pkg/parser/model", diff --git a/pkg/statistics/handle/handletest/initstats/load_stats_test.go b/pkg/statistics/handle/handletest/initstats/load_stats_test.go index 37d0c45a9d030..af39654e63de6 100644 --- a/pkg/statistics/handle/handletest/initstats/load_stats_test.go +++ b/pkg/statistics/handle/handletest/initstats/load_stats_test.go @@ -102,3 +102,40 @@ func testConcurrentlyInitStats(t *testing.T) { } require.Equal(t, int64(126), handle.GetMaxTidRecordForTest()) } + +func TestDropTableBeforeConcurrentlyInitStats(t *testing.T) { + restore := config.RestoreFunc() + defer restore() + config.UpdateGlobal(func(conf *config.Config) { + conf.Performance.LiteInitStats = false + conf.Performance.ConcurrentlyInitStats = true + }) + testDropTableBeforeInitStats(t) +} + +func TestDropTableBeforeNonLiteInitStats(t *testing.T) { + restore := config.RestoreFunc() + defer restore() + config.UpdateGlobal(func(conf *config.Config) { + conf.Performance.LiteInitStats = false + conf.Performance.ConcurrentlyInitStats = false + }) + testDropTableBeforeInitStats(t) +} + +func testDropTableBeforeInitStats(t *testing.T) { + store, dom := testkit.CreateMockStoreAndDomain(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test;") + tk.MustExec("create table t( id int, a int, b int, index idx(id, a));") + tk.MustExec("insert into t values (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5);") + tk.MustExec("insert into t select * from t where id<>2;") + tk.MustExec("insert into t select * from t where id<>2;") + tk.MustExec("insert into t select * from t where id<>2;") + tk.MustExec("insert into t select * from t where id<>2;") + tk.MustExec("analyze table t all columns;") + tk.MustExec("drop table t") + h := dom.StatsHandle() + is := dom.InfoSchema() + require.NoError(t, h.InitStats(context.Background(), is)) +}