Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#58108
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <[email protected]>
  • Loading branch information
winoros authored and ti-chi-bot committed Dec 12, 2024
1 parent 4df9aa8 commit 12954bd
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 10 deletions.
5 changes: 5 additions & 0 deletions pkg/statistics/handle/storage/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ go_test(
"stats_read_writer_test.go",
],
flaky = True,
<<<<<<< HEAD
shard_count = 22,
=======
shard_count = 24,
>>>>>>> d5b6b699c84 (statistics: GCStats should not wrongly remove record of an existing table (#58108))
deps = [
":storage",
"//pkg/domain",
Expand All @@ -67,6 +71,7 @@ go_test(
"//pkg/testkit",
"//pkg/types",
"//pkg/util",
"@com_github_pingcap_failpoint//:failpoint",
"@com_github_stretchr_testify//require",
],
)
32 changes: 22 additions & 10 deletions pkg/statistics/handle/storage/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

"github.com/pingcap/errors"
"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/pkg/infoschema"
"github.com/pingcap/tidb/pkg/parser/terror"
"github.com/pingcap/tidb/pkg/sessionctx"
Expand Down Expand Up @@ -87,6 +88,10 @@ func GCStats(sctx sessionctx.Context,
return nil
}

failpoint.Inject("injectGCStatsLastTSOffset", func(val failpoint.Value) {
offset = uint64(val.(int))
})

// Get the last gc time.
gcVer := now - offset
lastGC, err := getLastGCTimestamp(sctx)
Expand Down Expand Up @@ -262,29 +267,36 @@ func removeDeletedExtendedStats(sctx sessionctx.Context, version uint64) (err er
}

// gcTableStats GC this table's stats.
// The GC of a table will be a two-phase process:
// 1. Delete the column/index's stats from storage. Then other TiDB nodes will be aware that those stats are deleted.
// 2. Then delete the record in stats_meta.
func gcTableStats(sctx sessionctx.Context,
statsHandler util.StatsHandle,
is infoschema.InfoSchema, physicalID int64) error {
tbl, ok := statsHandler.TableInfoByID(is, physicalID)
rows, _, err := util.ExecRows(sctx, "select is_index, hist_id from mysql.stats_histograms where table_id = %?", physicalID)
if err != nil {
return errors.Trace(err)
}
// The table has already been deleted in stats and acknowledged to all tidb,
// we can safely remove the meta info now.
if len(rows) == 0 {
if !ok {
if len(rows) > 0 {
// It's the first time to run into it. Delete column/index stats to notify other TiDB nodes.
logutil.BgLogger().Info("remove stats in GC due to dropped table", zap.Int64("tableID", physicalID))
return util.WrapTxn(sctx, func(sctx sessionctx.Context) error {
return errors.Trace(DeleteTableStatsFromKV(sctx, []int64{physicalID}))
})
}
// len(rows) == 0 => The table's stats is empty.
// The table has already been deleted in stats and acknowledged to all tidb,
// We can safely remove the meta info now.
_, _, err = util.ExecRows(sctx, "delete from mysql.stats_meta where table_id = %?", physicalID)
if err != nil {
return errors.Trace(err)
}
cache.TableRowStatsCache.Invalidate(physicalID)
return nil
}
tbl, ok := statsHandler.TableInfoByID(is, physicalID)
if !ok {
logutil.BgLogger().Info("remove stats in GC due to dropped table", zap.Int64("table_id", physicalID))
return util.WrapTxn(sctx, func(sctx sessionctx.Context) error {
return errors.Trace(DeleteTableStatsFromKV(sctx, []int64{physicalID}))
})
}

tblInfo := tbl.Meta()
for _, row := range rows {
isIndex, histID := row.GetInt64(0), row.GetInt64(1)
Expand Down
27 changes: 27 additions & 0 deletions pkg/statistics/handle/storage/gc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
package storage_test

import (
"context"
"testing"
"time"

"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/pkg/parser/model"
"github.com/pingcap/tidb/pkg/sessionctx/variable"
"github.com/pingcap/tidb/pkg/testkit"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -173,3 +176,27 @@ func TestDeleteAnalyzeJobs(t *testing.T) {
rows = testKit.MustQuery("show analyze status").Rows()
require.Equal(t, 0, len(rows))
}

func TestExtremCaseOfGC(t *testing.T) {
// This case tests that there's no records in mysql.stats_histograms but this table is not deleted in fact.
// We should not delete the record in mysql.stats_meta.
store, dom := testkit.CreateMockStoreAndDomain(t)
testKit := testkit.NewTestKit(t, store)
testKit.MustExec("use test")
testKit.MustExec("create table t(a int, b int)")
testKit.MustExec("insert into t values (1,2),(3,4)")
testKit.MustExec("analyze table t")
tbl, err := dom.InfoSchema().TableByName(context.TODO(), model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tid := tbl.Meta().ID
rs := testKit.MustQuery("select * from mysql.stats_meta where table_id = ?", tid)
require.Len(t, rs.Rows(), 1)
rs = testKit.MustQuery("select * from mysql.stats_histograms where table_id = ?", tid)
require.Len(t, rs.Rows(), 0)
h := dom.StatsHandle()
failpoint.Enable("github.com/pingcap/tidb/pkg/statistics/handle/storage/injectGCStatsLastTSOffset", `return(0)`)
h.GCStats(dom.InfoSchema(), time.Second*3)
rs = testKit.MustQuery("select * from mysql.stats_meta where table_id = ?", tid)
require.Len(t, rs.Rows(), 1)
failpoint.Disable("github.com/pingcap/tidb/pkg/statistics/handle/storage/injectGCStatsLastTSOffset")
}

0 comments on commit 12954bd

Please sign in to comment.