-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
*: implement the INSPECTION_SCHEMA to provide snapshot of inspection …
…tables (#14147) Signed-off-by: Lonng <heng@lonng.org>
- Loading branch information
Showing
9 changed files
with
260 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// Copyright 2019 PingCAP, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package infoschema | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/pingcap/errors" | ||
"github.com/pingcap/parser/model" | ||
"github.com/pingcap/parser/mysql" | ||
"github.com/pingcap/tidb/kv" | ||
"github.com/pingcap/tidb/meta/autoid" | ||
"github.com/pingcap/tidb/sessionctx" | ||
"github.com/pingcap/tidb/sessionctx/variable" | ||
"github.com/pingcap/tidb/table" | ||
"github.com/pingcap/tidb/util" | ||
) | ||
|
||
// The `inspection_schema` is used to provide a consistent view of `information_schema` tables, | ||
// so the related table should have the same table name within `information_schema`. | ||
// The data will be obtained lazily from `information_schema` and cache in `SessionVars`, and | ||
// the cached data will be cleared at `InspectionExec` closing. | ||
var inspectionTables = map[string][]columnInfo{ | ||
tableClusterInfo: tableClusterInfoCols, | ||
TableClusterConfig: tableClusterConfigCols, | ||
TableClusterLoad: tableClusterLoadCols, | ||
TableClusterHardware: tableClusterHardwareCols, | ||
TableClusterSystemInfo: tableClusterSystemInfoCols, | ||
} | ||
|
||
type inspectionSchemaTable struct { | ||
infoschemaTable | ||
} | ||
|
||
// IterRecords implements table.Table IterRecords interface. | ||
func (it *inspectionSchemaTable) IterRecords(ctx sessionctx.Context, startKey kv.Key, cols []*table.Column, | ||
fn table.RecordIterFunc) error { | ||
sessionVars := ctx.GetSessionVars() | ||
// The `InspectionTableCache` will be assigned in `InspectionExec.Open` and be | ||
// cleaned at `InspectionExec.Close`, so nil represents currently in non-inspection mode. | ||
if sessionVars.InspectionTableCache == nil { | ||
return errors.New("not currently in inspection mode") | ||
} | ||
|
||
if len(startKey) != 0 { | ||
return table.ErrUnsupportedOp | ||
} | ||
|
||
// Obtain data from cache first. | ||
cached, found := sessionVars.InspectionTableCache[it.meta.Name.L] | ||
if !found { | ||
// We retrieve data from `information_schema` if can found in cache. | ||
rows, err := it.getRows(ctx, cols) | ||
cached = variable.TableSnapshot{ | ||
Rows: rows, | ||
Err: err, | ||
} | ||
sessionVars.InspectionTableCache[it.meta.Name.L] = cached | ||
} | ||
if cached.Err != nil { | ||
return cached.Err | ||
} | ||
|
||
for i, row := range cached.Rows { | ||
more, err := fn(int64(i), row, cols) | ||
if err != nil { | ||
return err | ||
} | ||
if !more { | ||
break | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func init() { | ||
// Initialize the inspection schema database and register the driver to `drivers`. | ||
dbID := autoid.InspectionSchemaDBID | ||
tables := make([]*model.TableInfo, 0, len(inspectionTables)) | ||
for name, cols := range inspectionTables { | ||
tableInfo := buildTableMeta(name, cols) | ||
tables = append(tables, tableInfo) | ||
var ok bool | ||
tid, ok := tableIDMap[tableInfo.Name.O] | ||
if !ok { | ||
panic(fmt.Sprintf("get inspection_schema table id failed, unknown system table `%v`", tableInfo.Name.O)) | ||
} | ||
// Reuse information_schema table id serial number. | ||
tableInfo.ID = tid - autoid.InformationSchemaDBID + autoid.InspectionSchemaDBID | ||
for i, c := range tableInfo.Columns { | ||
c.ID = int64(i) + 1 | ||
} | ||
} | ||
inspectionSchema := &model.DBInfo{ | ||
ID: dbID, | ||
Name: util.InspectionSchemaName, | ||
Charset: mysql.DefaultCharset, | ||
Collate: mysql.DefaultCollationName, | ||
Tables: tables, | ||
} | ||
builder := func(_ autoid.Allocators, meta *model.TableInfo) (table.Table, error) { | ||
columns := make([]*table.Column, len(meta.Columns)) | ||
for i, col := range meta.Columns { | ||
columns[i] = table.ToColumn(col) | ||
} | ||
tbl := &inspectionSchemaTable{ | ||
infoschemaTable{ | ||
meta: meta, | ||
cols: columns, | ||
tp: table.VirtualTable, | ||
}, | ||
} | ||
return tbl, nil | ||
} | ||
RegisterVirtualTable(inspectionSchema, builder) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// Copyright 2019 PingCAP, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package infoschema_test | ||
|
||
import ( | ||
"strings" | ||
|
||
. "github.com/pingcap/check" | ||
"github.com/pingcap/failpoint" | ||
"github.com/pingcap/tidb/domain" | ||
"github.com/pingcap/tidb/kv" | ||
"github.com/pingcap/tidb/session" | ||
"github.com/pingcap/tidb/sessionctx/variable" | ||
"github.com/pingcap/tidb/store/mockstore" | ||
"github.com/pingcap/tidb/util/testkit" | ||
"github.com/pingcap/tidb/util/testleak" | ||
) | ||
|
||
type inspectionSuite struct { | ||
store kv.Storage | ||
dom *domain.Domain | ||
} | ||
|
||
var _ = SerialSuites(&inspectionSuite{}) | ||
|
||
func (s *inspectionSuite) SetUpSuite(c *C) { | ||
testleak.BeforeTest() | ||
|
||
var err error | ||
s.store, err = mockstore.NewMockTikvStore() | ||
c.Assert(err, IsNil) | ||
session.DisableStats4Test() | ||
s.dom, err = session.BootstrapSession(s.store) | ||
c.Assert(err, IsNil) | ||
} | ||
|
||
func (s *inspectionSuite) TearDownSuite(c *C) { | ||
s.dom.Close() | ||
s.store.Close() | ||
testleak.AfterTest(c)() | ||
} | ||
|
||
func (s *inspectionSuite) TestInspectionTables(c *C) { | ||
tk := testkit.NewTestKit(c, s.store) | ||
instances := []string{ | ||
"pd,127.0.0.1:11080,127.0.0.1:10080,mock-version,mock-githash", | ||
"tidb,127.0.0.1:11080,127.0.0.1:10080,mock-version,mock-githash", | ||
"tikv,127.0.0.1:11080,127.0.0.1:10080,mock-version,mock-githash", | ||
} | ||
fpName := "github.com/pingcap/tidb/infoschema/mockClusterInfo" | ||
fpExpr := `return("` + strings.Join(instances, ";") + `")` | ||
c.Assert(failpoint.Enable(fpName, fpExpr), IsNil) | ||
defer func() { c.Assert(failpoint.Disable(fpName), IsNil) }() | ||
|
||
tk.MustQuery("select * from information_schema.cluster_info").Check(testkit.Rows( | ||
"pd 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
"tidb 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
"tikv 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
)) | ||
|
||
// enable inspection mode | ||
inspectionTableCache := map[string]variable.TableSnapshot{} | ||
tk.Se.GetSessionVars().InspectionTableCache = inspectionTableCache | ||
tk.MustQuery("select * from inspection_schema.cluster_info").Check(testkit.Rows( | ||
"pd 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
"tidb 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
"tikv 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
)) | ||
c.Assert(inspectionTableCache["cluster_info"].Err, IsNil) | ||
c.Assert(len(inspectionTableCache["cluster_info"].Rows), DeepEquals, 3) | ||
|
||
// should invisible to other sessions | ||
tk2 := testkit.NewTestKitWithInit(c, s.store) | ||
err := tk2.QueryToErr("select * from inspection_schema.cluster_info") | ||
c.Assert(err, ErrorMatches, "not currently in inspection mode") | ||
|
||
// check whether is obtain data from cache at the next time | ||
inspectionTableCache["cluster_info"].Rows[0][0].SetString("modified-pd") | ||
tk.MustQuery("select * from inspection_schema.cluster_info").Check(testkit.Rows( | ||
"modified-pd 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
"tidb 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
"tikv 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash", | ||
)) | ||
tk.Se.GetSessionVars().InspectionTableCache = nil | ||
|
||
// disable inspection mode | ||
err = tk.QueryToErr("select * from inspection_schema.cluster_info") | ||
c.Assert(err, ErrorMatches, "not currently in inspection mode") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters