From 1fb40192f36f0ef44da23d45dd369dfdb5b7d948 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Tue, 6 Aug 2024 15:56:09 +0800 Subject: [PATCH] infoschema: rewrite SchemaSimpleTableInfos for infoschema v2 to avoid network (#55088) ref pingcap/tidb#50959 --- pkg/infoschema/infoschema_v2.go | 47 +++++++-------- .../test/infoschemav2test/BUILD.bazel | 2 +- .../test/infoschemav2test/v2_test.go | 58 +++++++++++++++++++ 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/pkg/infoschema/infoschema_v2.go b/pkg/infoschema/infoschema_v2.go index 3c590cc6f6774..e8a0f45fa995a 100644 --- a/pkg/infoschema/infoschema_v2.go +++ b/pkg/infoschema/infoschema_v2.go @@ -795,33 +795,34 @@ func (is *infoschemaV2) SchemaSimpleTableInfos(ctx context.Context, schema model return nil, nil // something wrong? } -retry: - dbInfo, ok := is.SchemaByName(schema) - if !ok { + // Ascend is much more difficult than Descend. + // So the data is taken out first and then dedup in Descend order. + var tableItems []tableItem + is.byName.Ascend(tableItem{dbName: schema.L}, func(item tableItem) bool { + if item.dbName != schema.L { + return false + } + if is.infoSchema.schemaMetaVersion >= item.schemaVersion { + tableItems = append(tableItems, item) + } + return true + }) + if len(tableItems) == 0 { return nil, nil } - snapshot := is.r.Store().GetSnapshot(kv.NewVersion(is.ts)) - // Using the KV timeout read feature to address the issue of potential DDL lease expiration when - // the meta region leader is slow. - snapshot.SetOption(kv.TiKVClientReadTimeout, uint64(3000)) // 3000ms. - m := meta.NewSnapshotMeta(snapshot) - tblInfos, err := m.ListSimpleTables(dbInfo.ID) - if err != nil { - if meta.ErrDBNotExists.Equal(err) { - return nil, nil - } - // Flashback statement could cause such kind of error. - // In theory that error should be handled in the lower layer, like client-go. - // But it's not done, so we retry here. - if strings.Contains(err.Error(), "in flashback progress") { - select { - case <-time.After(200 * time.Millisecond): - case <-ctx.Done(): - return nil, ctx.Err() + tblInfos := make([]*model.TableNameInfo, 0, len(tableItems)) + var curr *tableItem + for i := len(tableItems) - 1; i >= 0; i-- { + item := &tableItems[i] + if curr == nil || curr.tableName != tableItems[i].tableName { + curr = item + if !item.tomb { + tblInfos = append(tblInfos, &model.TableNameInfo{ + ID: item.tableID, + Name: model.NewCIStr(item.tableName), + }) } - goto retry } - return nil, errors.Trace(err) } return tblInfos, nil } diff --git a/pkg/infoschema/test/infoschemav2test/BUILD.bazel b/pkg/infoschema/test/infoschemav2test/BUILD.bazel index bed0d2a1aa156..cc786f4485f46 100644 --- a/pkg/infoschema/test/infoschemav2test/BUILD.bazel +++ b/pkg/infoschema/test/infoschemav2test/BUILD.bazel @@ -8,7 +8,7 @@ go_test( "v2_test.go", ], flaky = True, - shard_count = 8, + shard_count = 9, deps = [ "//pkg/domain", "//pkg/domain/infosync", diff --git a/pkg/infoschema/test/infoschemav2test/v2_test.go b/pkg/infoschema/test/infoschemav2test/v2_test.go index 5d89d22134271..b8bf008304752 100644 --- a/pkg/infoschema/test/infoschemav2test/v2_test.go +++ b/pkg/infoschema/test/infoschemav2test/v2_test.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "slices" + "sort" "strconv" "strings" "testing" @@ -428,3 +429,60 @@ func TestIssue54926(t *testing.T) { require.Equal(t, time2TS, tk.Session().GetSessionVars().TxnReadTS.PeakTxnReadTS()) require.Equal(t, schemaVer2, tk.Session().GetInfoSchema().SchemaMetaVersion()) } + +func TestSchemaSimpleTableInfos(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + // For mocktikv, safe point is not initialized, we manually insert it for snapshot to use. + safePointName := "tikv_gc_safe_point" + safePointValue := "20160102-15:04:05 -0700" + safePointComment := "All versions after safe point can be accessed. (DO NOT EDIT)" + updateSafePoint := fmt.Sprintf(`INSERT INTO mysql.tidb VALUES ('%[1]s', '%[2]s', '%[3]s') + ON DUPLICATE KEY + UPDATE variable_value = '%[2]s', comment = '%[3]s'`, safePointName, safePointValue, safePointComment) + tk.MustExec(updateSafePoint) + tk.MustExec("set @@global.tidb_schema_cache_size = '512MB'") + + tk.MustExec("create database aaa") + tk.MustExec("create database zzz") + tk.MustExec("drop database zzz") + + tk.MustExec("create database simple") + tk.MustExec("use simple") + tk.MustExec("create table t1 (id int)") + tk.MustExec("create table t2 (id int)") + + time1 := time.Now() + time.Sleep(50 * time.Millisecond) + + tk.MustExec("rename table simple.t2 to aaa.t2") + tk.MustExec("drop database aaa") + + is := tk.Session().GetInfoSchema() + // Cover special schema + tblInfos, err := is.SchemaSimpleTableInfos(context.Background(), model.NewCIStr("INFORMATION_SCHEMA")) + require.NoError(t, err) + res := make([]string, 0, len(tblInfos)) + for _, tbl := range tblInfos { + res = append(res, tbl.Name.L) + } + sort.Strings(res) + tk.MustQuery("select lower(table_name) from information_schema.tables where table_schema = 'information_schema'"). + Sort().Check(testkit.Rows(res...)) + + // Cover normal schema + tblInfos, err = is.SchemaSimpleTableInfos(context.Background(), model.NewCIStr("simple")) + require.NoError(t, err) + require.Len(t, tblInfos, 1) + require.Equal(t, tblInfos[0].Name.L, "t1") + + // Cover snapshot infoschema + tk.MustExec(fmt.Sprintf(`set @@tidb_snapshot="%s"`, time1.Format("2006-1-2 15:04:05.000"))) + is = tk.Session().GetInfoSchema() + tblInfos, err = is.SchemaSimpleTableInfos(context.Background(), model.NewCIStr("simple")) + require.NoError(t, err) + require.Len(t, tblInfos, 2) + require.Equal(t, tblInfos[0].Name.L, "t2") + require.Equal(t, tblInfos[1].Name.L, "t1") +}