From 1521bf723dd023da655add0f883acaab5ee69683 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Fri, 6 Dec 2024 17:40:44 +0800 Subject: [PATCH] statistics: right deal with error for reading stats from storage (#58048) ref pingcap/tidb#57901 --- pkg/statistics/handle/handletest/BUILD.bazel | 2 +- .../handle/handletest/handle_test.go | 28 +++++++++++++++++++ pkg/statistics/handle/storage/read.go | 5 +++- pkg/statistics/handle/util/BUILD.bazel | 1 + pkg/statistics/handle/util/util.go | 4 +++ 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/pkg/statistics/handle/handletest/BUILD.bazel b/pkg/statistics/handle/handletest/BUILD.bazel index 886357c5f6500..2884f52b182f1 100644 --- a/pkg/statistics/handle/handletest/BUILD.bazel +++ b/pkg/statistics/handle/handletest/BUILD.bazel @@ -9,7 +9,7 @@ go_test( ], flaky = True, race = "on", - shard_count = 33, + shard_count = 34, deps = [ "//pkg/config", "//pkg/domain", diff --git a/pkg/statistics/handle/handletest/handle_test.go b/pkg/statistics/handle/handletest/handle_test.go index ad07df8879ab6..2fea656d8ae92 100644 --- a/pkg/statistics/handle/handletest/handle_test.go +++ b/pkg/statistics/handle/handletest/handle_test.go @@ -1490,3 +1490,31 @@ func TestSkipMissingPartitionStats(t *testing.T) { return false }) } + +func TestStatsCacheUpdateTimeout(t *testing.T) { + store, dom := testkit.CreateMockStoreAndDomain(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("set @@tidb_partition_prune_mode = 'dynamic'") + tk.MustExec("set @@tidb_skip_missing_partition_stats = 1") + tk.MustExec("create table t (a int, b int, c int, index idx_b(b)) partition by range (a) (partition p0 values less than (100), partition p1 values less than (200), partition p2 values less than (300))") + tk.MustExec("insert into t values (1,1,1), (2,2,2), (101,101,101), (102,102,102), (201,201,201), (202,202,202)") + analyzehelper.TriggerPredicateColumnsCollection(t, tk, store, "t", "a", "b", "c") + h := dom.StatsHandle() + require.NoError(t, h.DumpStatsDeltaToKV(true)) + tk.MustExec("analyze table t partition p0, p1") + tbl, err := dom.InfoSchema().TableByName(context.Background(), model.NewCIStr("test"), model.NewCIStr("t")) + require.NoError(t, err) + tblInfo := tbl.Meta() + globalStats := h.GetTableStats(tblInfo) + require.Equal(t, 6, int(globalStats.RealtimeCount)) + require.Equal(t, 2, int(globalStats.ModifyCount)) + require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/pkg/statistics/handle/util/ExecRowsTimeout", "return()")) + defer func() { + require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/pkg/statistics/handle/util/ExecRowsTimeout")) + }() + require.Error(t, h.Update(context.Background(), dom.InfoSchema())) + globalStats2 := h.GetTableStats(tblInfo) + require.Equal(t, 6, int(globalStats2.RealtimeCount)) + require.Equal(t, 2, int(globalStats2.ModifyCount)) +} diff --git a/pkg/statistics/handle/storage/read.go b/pkg/statistics/handle/storage/read.go index d33336fa3fe06..7f42d144250a7 100644 --- a/pkg/statistics/handle/storage/read.go +++ b/pkg/statistics/handle/storage/read.go @@ -539,8 +539,11 @@ func TableStatsFromStorage(sctx sessionctx.Context, snapshot uint64, tableInfo * table.RealtimeCount = realtimeCount rows, _, err := util.ExecRows(sctx, "select table_id, is_index, hist_id, distinct_count, version, null_count, tot_col_size, stats_ver, flag, correlation, last_analyze_pos from mysql.stats_histograms where table_id = %?", tableID) + if err != nil { + return nil, err + } // Check deleted table. - if err != nil || len(rows) == 0 { + if len(rows) == 0 { return nil, nil } for _, row := range rows { diff --git a/pkg/statistics/handle/util/BUILD.bazel b/pkg/statistics/handle/util/BUILD.bazel index 88c059b417312..a40c702ffb6b6 100644 --- a/pkg/statistics/handle/util/BUILD.bazel +++ b/pkg/statistics/handle/util/BUILD.bazel @@ -28,6 +28,7 @@ go_library( "//pkg/util/sqlexec", "//pkg/util/sqlexec/mock", "@com_github_pingcap_errors//:errors", + "@com_github_pingcap_failpoint//:failpoint", "@com_github_tiancaiamao_gp//:gp", "@com_github_tikv_client_go_v2//oracle", "@org_golang_x_exp//maps", diff --git a/pkg/statistics/handle/util/util.go b/pkg/statistics/handle/util/util.go index c6e82c15a2c92..e01ed16ca52a1 100644 --- a/pkg/statistics/handle/util/util.go +++ b/pkg/statistics/handle/util/util.go @@ -20,6 +20,7 @@ import ( "time" "github.com/pingcap/errors" + "github.com/pingcap/failpoint" "github.com/pingcap/tidb/pkg/kv" "github.com/pingcap/tidb/pkg/meta/model" "github.com/pingcap/tidb/pkg/parser/terror" @@ -229,6 +230,9 @@ func ExecWithCtx( // ExecRows is a helper function to execute sql and return rows and fields. func ExecRows(sctx sessionctx.Context, sql string, args ...any) (rows []chunk.Row, fields []*resolve.ResultField, err error) { + failpoint.Inject("ExecRowsTimeout", func() { + failpoint.Return(nil, nil, errors.New("inject timeout error")) + }) return ExecRowsWithCtx(StatsCtx, sctx, sql, args...) }