Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add real tables for global/session status in performance schema #4523

Merged
merged 8 commits into from
Sep 18, 2017
17 changes: 8 additions & 9 deletions executor/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ package executor

import (
"math"
"strings"
"time"

"github.com/juju/errors"
Expand Down Expand Up @@ -632,15 +631,15 @@ func (b *executorBuilder) getStartTS() uint64 {
}

func (b *executorBuilder) buildMemTable(v *plan.PhysicalMemTable) Executor {
table, _ := b.is.TableByID(v.Table.ID)
tb, _ := b.is.TableByID(v.Table.ID)
ts := &TableScanExec{
t: table,
ctx: b.ctx,
columns: v.Columns,
schema: v.Schema(),
seekHandle: math.MinInt64,
ranges: v.Ranges,
isInfoSchema: strings.EqualFold(v.DBName.L, infoschema.Name),
t: tb,
ctx: b.ctx,
columns: v.Columns,
schema: v.Schema(),
seekHandle: math.MinInt64,
ranges: v.Ranges,
isVirtualTable: tb.Type() == table.VirtualTable,
}
return ts
}
Expand Down
18 changes: 9 additions & 9 deletions executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,9 @@ type TableScanExec struct {
schema *expression.Schema
columns []*model.ColumnInfo

isInfoSchema bool
infoSchemaRows [][]types.Datum
infoSchemaCursor int
isVirtualTable bool
virtualTableRows [][]types.Datum
virtualTableCursor int
}

// Schema implements the Executor Schema interface.
Expand All @@ -533,7 +533,7 @@ func (e *TableScanExec) Schema() *expression.Schema {

// Next implements the Executor interface.
func (e *TableScanExec) Next() (Row, error) {
if e.isInfoSchema {
if e.isVirtualTable {
return e.nextForInfoSchema()
}
for {
Expand Down Expand Up @@ -576,24 +576,24 @@ func (e *TableScanExec) Next() (Row, error) {
}

func (e *TableScanExec) nextForInfoSchema() (Row, error) {
if e.infoSchemaRows == nil {
if e.virtualTableRows == nil {
columns := make([]*table.Column, e.schema.Len())
for i, v := range e.columns {
columns[i] = table.ToColumn(v)
}
err := e.t.IterRecords(e.ctx, nil, columns, func(h int64, rec []types.Datum, cols []*table.Column) (bool, error) {
e.infoSchemaRows = append(e.infoSchemaRows, rec)
e.virtualTableRows = append(e.virtualTableRows, rec)
return true, nil
})
if err != nil {
return nil, errors.Trace(err)
}
}
if e.infoSchemaCursor >= len(e.infoSchemaRows) {
if e.virtualTableCursor >= len(e.virtualTableRows) {
return nil, nil
}
row := e.infoSchemaRows[e.infoSchemaCursor]
e.infoSchemaCursor++
row := e.virtualTableRows[e.virtualTableCursor]
e.virtualTableCursor++
return row, nil
}

Expand Down
4 changes: 4 additions & 0 deletions infoschema/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -1168,3 +1168,7 @@ func (it *infoschemaTable) Meta() *model.TableInfo {
func (it *infoschemaTable) Seek(ctx context.Context, h int64) (int64, bool, error) {
return 0, false, table.ErrUnsupportedOp
}

func (it *infoschemaTable) Type() table.Type {
return table.VirtualTable
}
10 changes: 9 additions & 1 deletion perfschema/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,15 @@ func (ps *perfSchema) buildTables() {
c.ID = autoid.GenLocalSchemaID()
}
alloc := autoid.NewMemoryAllocator(dbID)
ps.mTables[name] = tables.MemoryTableFromMeta(alloc, meta)
var tbl table.Table
switch name {
//@TODO in the future, we need to add many VirtualTable, we may need to add new type for these tables.
case TableSessionStatus, TableGlobalStatus:
tbl = createVirtualTable(meta, name)
default:
tbl = tables.MemoryTableFromMeta(alloc, meta)
}
ps.mTables[name] = tbl
}
ps.dbInfo = &model.DBInfo{
ID: dbID,
Expand Down
99 changes: 99 additions & 0 deletions perfschema/virtual_tables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2017 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 perfschema

import (
"fmt"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a blank line between system packages and custom packages like other files do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


log "github.com/Sirupsen/logrus"
"github.com/juju/errors"
"github.com/pingcap/tidb/context"
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/table"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/util/types"
)

// session/global status decided by scope.
type statusDataSource struct {
meta *model.TableInfo
cols []*table.Column
globalScope bool
}

// GetRows implements the interface of VirtualDataSource.
func (ds *statusDataSource) GetRows(ctx context.Context) (fullRows [][]types.Datum,
err error) {
sessionVars := ctx.GetSessionVars()
statusVars, err := variable.GetStatusVars(sessionVars)
if err != nil {
return nil, errors.Trace(err)
}

rows := [][]types.Datum{}
for status, v := range statusVars {
if ds.globalScope && v.Scope == variable.ScopeSession {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if data source is session scope and v.Scop == variable.ScopeGlobal ?
And NoneScope seems should not be added too, I'm not sure about it.

Copy link
Contributor Author

@wentaoxu wentaoxu Sep 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

session status will show all status, including global andl local, global status will show global status only.
this detail is from mysql document
so the code is like this, as same as the command "show status"

continue
}

switch v.Value.(type) {
case []interface{}, nil:
v.Value = fmt.Sprintf("%v", v.Value)
}
value, err := types.ToString(v.Value)
if err != nil {
return nil, errors.Trace(err)
}
row := types.MakeDatums(status, value)
rows = append(rows, row)
}

return rows, nil
}

// Meta implements the interface of VirtualDataSource.
func (ds *statusDataSource) Meta() *model.TableInfo {
return ds.meta
}

// Cols implements the interface of VirtualDataSource.
func (ds *statusDataSource) Cols() []*table.Column {
return ds.cols
}

func createVirtualDataSource(tableName string, meta *model.TableInfo) (tables.VirtualDataSource, error) {
columns := make([]*table.Column, 0, len(meta.Columns))
for _, colInfo := range meta.Columns {
col := table.ToColumn(colInfo)
columns = append(columns, col)
}

switch tableName {
case TableSessionStatus:
return &statusDataSource{meta: meta, cols: columns, globalScope: false}, nil
case TableGlobalStatus:
return &statusDataSource{meta: meta, cols: columns, globalScope: true}, nil
default:
return nil, errors.New("can't find table named by " + tableName)
}
}

func createVirtualTable(meta *model.TableInfo, tableName string) table.Table {
dataSource, err := createVirtualDataSource(tableName, meta)
if err != nil {
log.Fatal(err.Error())
}
return tables.CreateVirtualTable(dataSource)
}
71 changes: 71 additions & 0 deletions perfschema/virtual_tables_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2017 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 perfschema

import (
"testing"

"github.com/juju/errors"
. "github.com/pingcap/check"
"github.com/pingcap/tidb/store/localstore"
"github.com/pingcap/tidb/store/localstore/goleveldb"
"github.com/pingcap/tidb/util/mock"
"github.com/pingcap/tidb/util/types"
)

func TestT(t *testing.T) {
CustomVerboseFlag = true
TestingT(t)
}

var _ = Suite(&testSuite{})

type testSuite struct {
}

func (*testSuite) TestSessionStatus(c *C) {
driver := localstore.Driver{Driver: goleveldb.MemoryDriver{}}
store, err := driver.Open("memory")
c.Assert(err, IsNil)

ctx := mock.NewContext()
ctx.Store = store
ps := newPerfHandle()

testTableName := []string{TableSessionStatus, TableGlobalStatus}
for _, tableName := range testTableName {
tb, _ := ps.GetTable(tableName)
meta := ps.tables[tableName]
c.Assert(tb, NotNil)

sessionStatusHandle, _ := createVirtualDataSource(tableName, meta)
rows, err := sessionStatusHandle.GetRows(ctx)
c.Assert(err, IsNil)

c.Assert(findSpecialStatus(rows, "Ssl_cipher"), IsNil)
}
}

func findSpecialStatus(rows [][]types.Datum, name string) error {
err := errors.New("cant find the status " + name)
for _, row := range rows {
statusNames, _ := row[0].ToString()
if statusNames == name {
err = nil
break
}
}

return err
}
15 changes: 15 additions & 0 deletions table/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ import (
"github.com/pingcap/tidb/util/types"
)

// Type , the type of table, store data in different ways.
Copy link
Contributor

@alivxxx alivxxx Sep 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add a space between Type and ,?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the rule of golint, otherwise it will report like this, "comment on exported type Type should be of the form "Type ..." (with optional leading article)"

type Type int16

const (
// NormalTable , store data in tikv, mocktikv and so on.
NormalTable Type = iota
// VirtualTable , store no data, just extract data from the memory struct.
VirtualTable
// MemoryTable , store data only in local memory.
MemoryTable
)

var (
// errNoDefaultValue is used when insert a row, the column value is not given, and the column has not null flag
// and it doesn't have a default value.
Expand Down Expand Up @@ -124,6 +136,9 @@ type Table interface {

// Seek returns the handle greater or equal to h.
Seek(ctx context.Context, h int64) (handle int64, found bool, err error)

// Type returns the type of table
Type() Type
}

// TableFromMeta builds a table.Table from *model.TableInfo.
Expand Down
5 changes: 5 additions & 0 deletions table/tables/memory_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,8 @@ func (t *MemoryTable) IterRecords(ctx context.Context, startKey kv.Key, cols []*
fn table.RecordIterFunc) error {
return nil
}

// Type implements table.Table Type interface.
func (t *MemoryTable) Type() table.Type {
return table.MemoryTable
}
5 changes: 5 additions & 0 deletions table/tables/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,11 @@ func (t *Table) Seek(ctx context.Context, h int64) (int64, bool, error) {
return handle, true, nil
}

// Type implements table.Table Type interface.
func (t *Table) Type() table.Type {
return table.NormalTable
}

func shouldWriteBinlog(ctx context.Context) bool {
if ctx.GetSessionVars().BinlogClient == nil {
return false
Expand Down
Loading