Skip to content

Commit a8ad696

Browse files
authored
infoschema: fix information_schema.tikv_region_status for nextgen (pingcap#67444) (pingcap#67509)
close pingcap#67441, close pingcap#67442
1 parent 3d92e8c commit a8ad696

7 files changed

Lines changed: 150 additions & 55 deletions

File tree

pkg/executor/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ go_test(
413413
"//pkg/config",
414414
"//pkg/config/kerneltype",
415415
"//pkg/ddl",
416+
"//pkg/ddl/placement",
416417
"//pkg/ddl/util",
417418
"//pkg/distsql",
418419
"//pkg/distsql/context",

pkg/executor/infoschema_cluster_table_test.go

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ package executor_test
1616

1717
import (
1818
"crypto/tls"
19+
"encoding/hex"
20+
"encoding/json"
1921
"fmt"
22+
"hash/crc32"
2023
"net"
24+
"net/http"
2125
"net/http/httptest"
2226
"strconv"
2327
"strings"
@@ -28,6 +32,7 @@ import (
2832
"github.com/pingcap/failpoint"
2933
"github.com/pingcap/fn"
3034
"github.com/pingcap/tidb/pkg/config"
35+
"github.com/pingcap/tidb/pkg/ddl/placement"
3136
"github.com/pingcap/tidb/pkg/domain"
3237
"github.com/pingcap/tidb/pkg/kv"
3338
"github.com/pingcap/tidb/pkg/parser/auth"
@@ -129,14 +134,14 @@ func (s *infosSchemaClusterTableSuite) setUpMockPDHTTPServer() (*httptest.Server
129134
}, nil
130135
}))
131136
// mock regions
132-
router.Handle(pd.Regions, fn.Wrap(func() (*pd.RegionsInfo, error) {
137+
regionsResp := func(regionID int64, startKey, endKey string) *pd.RegionsInfo {
133138
return &pd.RegionsInfo{
134139
Count: 1,
135140
Regions: []pd.RegionInfo{
136141
{
137-
ID: 1,
138-
StartKey: "",
139-
EndKey: "",
142+
ID: regionID,
143+
StartKey: startKey,
144+
EndKey: endKey,
140145
Epoch: pd.RegionEpoch{
141146
ConfVer: 1,
142147
Version: 2,
@@ -147,8 +152,31 @@ func (s *infosSchemaClusterTableSuite) setUpMockPDHTTPServer() (*httptest.Server
147152
ApproximateKeys: 1000,
148153
},
149154
},
150-
}, nil
155+
}
156+
}
157+
router.Handle(pd.Regions, fn.Wrap(func() (*pd.RegionsInfo, error) {
158+
return regionsResp(1, "", ""), nil
151159
}))
160+
router.HandleFunc("/pd/api/v1/regions/key", func(w http.ResponseWriter, r *http.Request) {
161+
startKey := strings.ToUpper(hex.EncodeToString([]byte(r.URL.Query().Get("key"))))
162+
endKey := strings.ToUpper(hex.EncodeToString([]byte(r.URL.Query().Get("end_key"))))
163+
regionID := int64(crc32.ChecksumIEEE([]byte(startKey+"|"+endKey))) + 1
164+
w.Header().Set("Content-Type", "application/json")
165+
if err := json.NewEncoder(w).Encode(regionsResp(regionID, startKey, endKey)); err != nil {
166+
http.Error(w, err.Error(), http.StatusInternalServerError)
167+
}
168+
})
169+
router.HandleFunc(pd.MinResolvedTSPrefix, func(w http.ResponseWriter, _ *http.Request) {
170+
w.Header().Set("Content-Type", "application/json")
171+
_, _ = w.Write([]byte(`{"min_resolved_ts":1,"is_real_time":true}`))
172+
})
173+
router.HandleFunc(pd.PlacementRuleGroupByID(placement.TiFlashRuleGroupID), func(w http.ResponseWriter, _ *http.Request) {
174+
w.Header().Set("Content-Type", "application/json")
175+
_, _ = w.Write([]byte(fmt.Sprintf(`{"id":"%s","index":%d,"override":false}`, placement.TiFlashRuleGroupID, placement.RuleIndexTiFlash)))
176+
})
177+
router.HandleFunc("/pd/api/v1/config/rule_group", func(w http.ResponseWriter, _ *http.Request) {
178+
w.WriteHeader(http.StatusOK)
179+
})
152180
// mock PD API
153181
router.Handle(pd.Status, fn.Wrap(func() (any, error) {
154182
return struct {
@@ -322,48 +350,61 @@ func TestTikvRegionStatus(t *testing.T) {
322350
tk.MustExec("use test")
323351
tk.MustExec("drop table if exists test_t1")
324352
tk.MustExec(`CREATE TABLE test_t1 ( a int(11) DEFAULT NULL, b int(11) DEFAULT NULL, c int(11) DEFAULT NULL)`)
325-
tk.MustQuery("select REGION_ID, DB_NAME, TABLE_NAME, IS_INDEX, INDEX_ID, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t1'").Check(testkit.Rows(
326-
"1 test test_t1 0 <nil> <nil> 0 <nil>",
353+
tk.MustQuery("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_ID, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t1'").Check(testkit.Rows(
354+
"test test_t1 0 <nil> <nil> 0 <nil>",
327355
))
328356

329357
tk.MustExec("alter table test_t1 add index p_a (a)")
330-
tk.MustQuery("select REGION_ID, DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t1' order by IS_INDEX").Check(testkit.Rows(
331-
"1 test test_t1 0 <nil> 0 <nil>",
332-
"1 test test_t1 1 p_a 0 <nil>",
358+
tk.MustQuery("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t1' order by IS_INDEX").Check(testkit.Rows(
359+
"test test_t1 0 <nil> 0 <nil>",
360+
"test test_t1 1 p_a 0 <nil>",
361+
))
362+
tableID := tk.MustQuery("select TIDB_TABLE_ID from information_schema.tables where TABLE_SCHEMA = 'test' and TABLE_NAME = 'test_t1'").Rows()[0][0]
363+
tk.MustQuery(fmt.Sprintf("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where TABLE_ID = %v order by IS_INDEX", tableID)).Check(testkit.Rows(
364+
"test test_t1 0 <nil> 0 <nil>",
365+
"test test_t1 1 p_a 0 <nil>",
333366
))
334367

335368
tk.MustExec("alter table test_t1 add unique p_b (b);")
336-
tk.MustQuery("select REGION_ID, DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t1' order by IS_INDEX, INDEX_NAME").Check(testkit.Rows(
337-
"1 test test_t1 0 <nil> 0 <nil>",
338-
"1 test test_t1 1 p_a 0 <nil>",
339-
"1 test test_t1 1 p_b 0 <nil>",
369+
tk.MustQuery("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t1' order by IS_INDEX, INDEX_NAME").Check(testkit.Rows(
370+
"test test_t1 0 <nil> 0 <nil>",
371+
"test test_t1 1 p_a 0 <nil>",
372+
"test test_t1 1 p_b 0 <nil>",
340373
))
341374

342375
tk.MustExec("drop table if exists test_t2")
343376
tk.MustExec(`CREATE TABLE test_t2 ( a int(11) DEFAULT NULL, b int(11) DEFAULT NULL, c int(11) DEFAULT NULL)
344377
PARTITION BY RANGE (c) (
345378
PARTITION p0 VALUES LESS THAN (10),
346379
PARTITION p1 VALUES LESS THAN (MAXVALUE))`)
347-
tk.MustQuery("select REGION_ID, DB_NAME, TABLE_NAME, IS_INDEX, INDEX_ID, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t2' order by PARTITION_NAME").Check(testkit.Rows(
348-
"1 test test_t2 0 <nil> <nil> 1 p0",
349-
"1 test test_t2 0 <nil> <nil> 1 p1",
380+
tk.MustQuery("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_ID, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t2' order by PARTITION_NAME").Check(testkit.Rows(
381+
"test test_t2 0 <nil> <nil> 1 p0",
382+
"test test_t2 0 <nil> <nil> 1 p1",
350383
))
351384

352385
tk.MustExec("alter table test_t2 add index p_a (a)")
353-
tk.MustQuery("select REGION_ID, DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t2' order by IS_INDEX, PARTITION_NAME").Check(testkit.Rows(
354-
"1 test test_t2 0 <nil> 1 p0",
355-
"1 test test_t2 0 <nil> 1 p1",
356-
"1 test test_t2 1 p_a 1 p0",
357-
"1 test test_t2 1 p_a 1 p1",
386+
tk.MustQuery("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t2' order by IS_INDEX, PARTITION_NAME").Check(testkit.Rows(
387+
"test test_t2 0 <nil> 1 p0",
388+
"test test_t2 0 <nil> 1 p1",
389+
"test test_t2 1 p_a 1 p0",
390+
"test test_t2 1 p_a 1 p1",
358391
))
359392

360393
tk.MustExec("alter table test_t2 add unique p_b (b) global")
361-
tk.MustQuery("select REGION_ID, DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t2' order by IS_INDEX, IS_PARTITION desc, PARTITION_NAME").Check(testkit.Rows(
362-
"1 test test_t2 0 <nil> 1 p0",
363-
"1 test test_t2 0 <nil> 1 p1",
364-
"1 test test_t2 1 p_a 1 p0",
365-
"1 test test_t2 1 p_a 1 p1",
366-
"1 test test_t2 1 p_b 0 <nil>",
394+
tk.MustQuery("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where DB_NAME = 'test' and TABLE_NAME = 'test_t2' order by IS_INDEX, IS_PARTITION desc, PARTITION_NAME").Check(testkit.Rows(
395+
"test test_t2 0 <nil> 1 p0",
396+
"test test_t2 0 <nil> 1 p1",
397+
"test test_t2 1 p_a 1 p0",
398+
"test test_t2 1 p_a 1 p1",
399+
"test test_t2 1 p_b 0 <nil>",
400+
))
401+
tableID = tk.MustQuery("select TIDB_TABLE_ID from information_schema.tables where TABLE_SCHEMA = 'test' and TABLE_NAME = 'test_t2'").Rows()[0][0]
402+
tk.MustQuery(fmt.Sprintf("select DB_NAME, TABLE_NAME, IS_INDEX, INDEX_NAME, IS_PARTITION, PARTITION_NAME from information_schema.TIKV_REGION_STATUS where TABLE_ID = %v order by IS_INDEX, IS_PARTITION desc, PARTITION_NAME", tableID)).Check(testkit.Rows(
403+
"test test_t2 0 <nil> 1 p0",
404+
"test test_t2 0 <nil> 1 p1",
405+
"test test_t2 1 p_a 1 p0",
406+
"test test_t2 1 p_a 1 p1",
407+
"test test_t2 1 p_b 0 <nil>",
367408
))
368409

369410
// Run the query to ensure virtual schemas are excluded and expect no rows to be returned

pkg/executor/infoschema_reader.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,11 +2079,7 @@ func (e *memtableRetriever) setDataForTiKVRegionStatus(ctx context.Context, sctx
20792079
}
20802080
}
20812081
if !requestByTableRange {
2082-
pdCli, err := tikvHelper.TryGetPDHTTPClient()
2083-
if err != nil {
2084-
return err
2085-
}
2086-
allRegionsInfo, err = pdCli.GetRegions(ctx)
2082+
allRegionsInfo, err = tikvHelper.GetRegions(ctx)
20872083
if err != nil {
20882084
return err
20892085
}
@@ -2123,16 +2119,16 @@ func (e *memtableRetriever) getRegionsInfoForTable(ctx context.Context, h *helpe
21232119
return nil, infoschema.ErrTableNotExists.GenWithStackByArgs(tableID)
21242120
}
21252121

2122+
allRegionsInfo, err := e.getRegionsInfoForSingleTable(ctx, h, tableID)
2123+
if err != nil {
2124+
return nil, err
2125+
}
2126+
21262127
pt := tbl.Meta().GetPartitionInfo()
21272128
if pt == nil {
2128-
regionsInfo, err := e.getRegionsInfoForSingleTable(ctx, h, tableID)
2129-
if err != nil {
2130-
return nil, err
2131-
}
2132-
return regionsInfo, nil
2129+
return allRegionsInfo, nil
21332130
}
21342131

2135-
var allRegionsInfo *pd.RegionsInfo
21362132
for _, def := range pt.Definitions {
21372133
regionsInfo, err := e.getRegionsInfoForSingleTable(ctx, h, def.ID)
21382134
if err != nil {
@@ -2148,7 +2144,9 @@ func (*memtableRetriever) getRegionsInfoForSingleTable(ctx context.Context, help
21482144
if err != nil {
21492145
return nil, err
21502146
}
2151-
sk, ek := tablecodec.GetTableHandleKeyRange(tableID)
2147+
// Query the whole table prefix so both record and index regions are covered.
2148+
sk := tablecodec.EncodeTablePrefix(tableID)
2149+
ek := sk.PrefixNext()
21522150
start, end := helper.Store.GetCodec().EncodeRegionRange(sk, ek)
21532151
return pdCli.GetRegionsByKeyRange(ctx, pd.NewKeyRange(start, end), -1)
21542152
}

pkg/executor/memtable_reader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ func (e *tikvRegionPeersRetriever) retrieve(ctx context.Context, sctx sessionctx
917917
storeMap := make(map[int64]struct{})
918918

919919
if len(e.extractor.StoreIDs) == 0 && len(e.extractor.RegionIDs) == 0 {
920-
regionsInfo, err := pdCli.GetRegions(ctx)
920+
regionsInfo, err := tikvHelper.GetRegions(ctx)
921921
if err != nil {
922922
return nil, err
923923
}

pkg/store/helper/helper.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ func (h *Helper) TryGetPDHTTPClient() (pd.Client, error) {
114114
return h.pdHTTPCli, nil
115115
}
116116

117+
// GetRegions fetches regions for the current store. In keyspace-aware mode, it
118+
// restricts the scan to the current keyspace to avoid mixing regions from other keyspaces.
119+
func (h *Helper) GetRegions(ctx context.Context) (*pd.RegionsInfo, error) {
120+
pdCli, err := h.TryGetPDHTTPClient()
121+
if err != nil {
122+
return nil, err
123+
}
124+
startKey, endKey := h.Store.GetCodec().EncodeRegionRange(nil, nil)
125+
return pdCli.GetRegionsByKeyRange(ctx, pd.NewKeyRange(startKey, endKey), -1)
126+
}
127+
117128
// MaxBackoffTimeoutForMvccGet is a derived value from previous implementation possible experiencing value 5000ms.
118129
const MaxBackoffTimeoutForMvccGet = 5000
119130

tests/realtikvtest/sessiontest/BUILD.bazel

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ go_test(
1212
],
1313
flaky = True,
1414
race = "on",
15-
shard_count = 16,
15+
shard_count = 17,
1616
deps = [
1717
"//pkg/config",
18+
"//pkg/config/kerneltype",
1819
"//pkg/infoschema",
20+
"//pkg/keyspace",
1921
"//pkg/meta",
2022
"//pkg/parser/ast",
2123
"//pkg/session",

tests/realtikvtest/sessiontest/infoschema_test.go

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,59 @@
1515
package sessiontest
1616

1717
import (
18-
"context"
1918
"fmt"
19+
"slices"
20+
"strings"
2021
"testing"
2122

22-
"github.com/pingcap/tidb/pkg/parser/ast"
23+
"github.com/pingcap/tidb/pkg/config/kerneltype"
24+
"github.com/pingcap/tidb/pkg/keyspace"
2325
"github.com/pingcap/tidb/pkg/testkit"
2426
"github.com/pingcap/tidb/tests/realtikvtest"
2527
"github.com/stretchr/testify/require"
2628
)
2729

2830
func TestNextGenTiKVRegionStatus(t *testing.T) {
29-
store, dom := realtikvtest.CreateMockStoreAndDomainAndSetup(t)
31+
store := realtikvtest.CreateMockStoreAndSetup(t)
3032
tk := testkit.NewTestKit(t, store)
3133
tk.MustExec("use test")
32-
tk.MustExec("create table t (a int);")
33-
tbl, err := dom.InfoSchema().TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t"))
34-
require.NoError(t, err)
34+
tk.MustExec("drop table if exists t")
35+
tk.MustExec("create table t (a int, key idx(a));")
36+
tk.MustExec("split table t between (0) and (10000) regions 4")
37+
tk.MustExec("split table t index idx between (0) and (10000) regions 4")
3538

36-
showRegions := tk.MustQuery("show table t regions").Rows()
37-
t.Log(showRegions)
38-
require.Equal(t, 1, len(showRegions), showRegions)
39+
tableID := tk.MustQuery(`select tidb_table_id from information_schema.tables where table_schema = 'test' and table_name = 't'`).Rows()[0][0]
40+
showRegions := uniqueSortedRegionIDs(tk.MustQuery("show table t regions").Rows())
41+
showIndexRegions := uniqueSortedRegionIDs(tk.MustQuery("show table t index idx regions").Rows())
3942
tikvRegions := tk.MustQuery(fmt.Sprintf(
40-
"select region_id from information_schema.tikv_region_status where table_id = %d", tbl.Meta().ID)).Rows()
41-
require.Equal(t, 1, len(tikvRegions), tikvRegions)
42-
t.Log(tikvRegions)
43-
require.Equal(t, showRegions[0][0], tikvRegions[0][0])
43+
"select region_id from information_schema.tikv_region_status where table_id = %v", tableID)).Rows()
44+
tikvIndexRegions := tk.MustQuery(fmt.Sprintf(
45+
"select region_id from information_schema.tikv_region_status where table_id = %v and is_index = 1", tableID)).Rows()
46+
require.Equal(t, showRegions, uniqueSortedRegionIDs(tikvRegions))
47+
require.Equal(t, showIndexRegions, uniqueSortedRegionIDs(tikvIndexRegions))
48+
}
49+
50+
func TestNextGenTiKVRegionStatusDoesNotMixOtherKeyspaces(t *testing.T) {
51+
if kerneltype.IsClassic() {
52+
t.Skip("only runs in nextgen kernel")
53+
}
54+
55+
runtimes := realtikvtest.PrepareForCrossKSTest(t, "keyspace1")
56+
sysTK := testkit.NewTestKit(t, runtimes[keyspace.System].Store)
57+
sysTK.MustExec("create database if not exists sys_region_status")
58+
sysTK.MustExec("use sys_region_status")
59+
sysTK.MustExec("drop table if exists t")
60+
sysTK.MustExec("create table t (a int, key idx(a))")
61+
sysTK.MustExec("split table t between (0) and (10000) regions 4")
62+
sysTK.MustExec("split table t index idx between (0) and (10000) regions 4")
63+
64+
systemRegionIDs := uniqueSortedRegionIDs(sysTK.MustQuery("show table t regions").Rows())
65+
require.NotEmpty(t, systemRegionIDs)
66+
67+
userTK := testkit.NewTestKit(t, runtimes["keyspace1"].Store)
68+
userTK.MustQuery(fmt.Sprintf(
69+
"select count(*) from information_schema.tikv_region_status where region_id in (%s)",
70+
strings.Join(systemRegionIDs, ","))).Check(testkit.Rows("0"))
4471
}
4572

4673
func TestTableReaderWithSnapshot(t *testing.T) {
@@ -59,3 +86,18 @@ func TestTableReaderWithSnapshot(t *testing.T) {
5986
tk.MustExec("set @@tidb_snapshot=@ts;")
6087
tk.MustQuery("SELECT TABLE_NAME,TABLE_TYPE,AVG_ROW_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test' AND (TABLE_TYPE='BASE TABLE')").Check(testkit.Rows("t BASE TABLE 0"))
6188
}
89+
90+
func uniqueSortedRegionIDs(rows [][]any) []string {
91+
seen := make(map[string]struct{}, len(rows))
92+
ids := make([]string, 0, len(rows))
93+
for _, row := range rows {
94+
id := row[0].(string)
95+
if _, ok := seen[id]; ok {
96+
continue
97+
}
98+
seen[id] = struct{}{}
99+
ids = append(ids, id)
100+
}
101+
slices.Sort(ids)
102+
return ids
103+
}

0 commit comments

Comments
 (0)