Skip to content

Commit

Permalink
*: add a new I_S table and support show create for resource groups (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
BornChanger authored Jan 17, 2023
1 parent 22746c0 commit 971deb6
Show file tree
Hide file tree
Showing 15 changed files with 5,692 additions and 5,561 deletions.
33 changes: 31 additions & 2 deletions ddl/resource_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ddl_test

import (
"context"
"strconv"
"testing"

"github.com/pingcap/tidb/ddl"
Expand All @@ -29,7 +30,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestResourceGroupBaisc(t *testing.T) {
func TestResourceGroupBasic(t *testing.T) {
store, dom := testkit.CreateMockStoreAndDomain(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
Expand Down Expand Up @@ -90,6 +91,8 @@ func TestResourceGroupBaisc(t *testing.T) {
re.Equal(uint64(2000), g.RRURate)
re.Equal(uint64(3000), g.WRURate)

tk.MustQuery("select * from information_schema.resource_groups where group_name = 'x'").Check(testkit.Rows(strconv.FormatInt(g.ID, 10) + " x 2000 3000"))

tk.MustExec("drop resource group x")
g = testResourceGroupNameFromIS(t, tk.Session(), "x")
re.Nil(g)
Expand Down Expand Up @@ -129,7 +132,33 @@ func TestResourceGroupBaisc(t *testing.T) {
groups, err := infosync.GetAllResourceGroups(context.TODO())
require.Equal(t, 0, len(groups))
require.NoError(t, err)
// TODO: privilege check & constraint syntax check.

// Check information schema table information_schema.resource_groups
tk.MustExec("create resource group x " +
"RRU_PER_SEC=1000 " +
"WRU_PER_SEC=2000")
g1 := testResourceGroupNameFromIS(t, tk.Session(), "x")
tk.MustQuery("select * from information_schema.resource_groups where group_name = 'x'").Check(testkit.Rows(strconv.FormatInt(g1.ID, 10) + " x 1000 2000"))
tk.MustQuery("show create resource group x").Check(testkit.Rows("x CREATE RESOURCE GROUP `x` RRU_PER_SEC=1000 WRU_PER_SEC=2000"))

tk.MustExec("create resource group y " +
"RRU_PER_SEC=2000 " +
"WRU_PER_SEC=3000")
g2 := testResourceGroupNameFromIS(t, tk.Session(), "y")
tk.MustQuery("select * from information_schema.resource_groups where group_name = 'y'").Check(testkit.Rows(strconv.FormatInt(g2.ID, 10) + " y 2000 3000"))
tk.MustQuery("show create resource group y").Check(testkit.Rows("y CREATE RESOURCE GROUP `y` RRU_PER_SEC=2000 WRU_PER_SEC=3000"))

tk.MustExec("alter resource group y " +
"RRU_PER_SEC=4000 " +
"WRU_PER_SEC=2000")

g2 = testResourceGroupNameFromIS(t, tk.Session(), "y")
tk.MustQuery("select * from information_schema.resource_groups where group_name = 'y'").Check(testkit.Rows(strconv.FormatInt(g2.ID, 10) + " y 4000 2000"))
tk.MustQuery("show create resource group y").Check(testkit.Rows("y CREATE RESOURCE GROUP `y` RRU_PER_SEC=4000 WRU_PER_SEC=2000"))

tk.MustGetErrCode("create user usr_fail resource group nil_group", mysql.ErrResourceGroupNotExists)
tk.MustExec("create user user2")
tk.MustGetErrCode("alter user user2 resource group nil_group", mysql.ErrResourceGroupNotExists)
}

func testResourceGroupNameFromIS(t *testing.T, ctx sessionctx.Context, name string) *model.ResourceGroupInfo {
Expand Down
4 changes: 3 additions & 1 deletion executor/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ func (b *executorBuilder) buildShow(v *plannercore.PhysicalShow) Executor {
Partition: v.Partition,
Column: v.Column,
IndexName: v.IndexName,
ResourceGroupName: model.NewCIStr(v.ResourceGroupName),
Flag: v.Flag,
Roles: v.Roles,
User: v.User,
Expand Down Expand Up @@ -1930,7 +1931,8 @@ func (b *executorBuilder) buildMemTable(v *plannercore.PhysicalMemTable) Executo
strings.ToLower(infoschema.TableMemoryUsage),
strings.ToLower(infoschema.TableMemoryUsageOpsHistory),
strings.ToLower(infoschema.ClusterTableMemoryUsage),
strings.ToLower(infoschema.ClusterTableMemoryUsageOpsHistory):
strings.ToLower(infoschema.ClusterTableMemoryUsageOpsHistory),
strings.ToLower(infoschema.TableResourceGroups):
return &MemTableReaderExec{
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ID()),
table: v.Table,
Expand Down
19 changes: 19 additions & 0 deletions executor/infoschema_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ func (e *memtableRetriever) retrieve(ctx context.Context, sctx sessionctx.Contex
err = e.setDataForMemoryUsageOpsHistory(sctx)
case infoschema.ClusterTableMemoryUsageOpsHistory:
err = e.setDataForClusterMemoryUsageOpsHistory(sctx)
case infoschema.TableResourceGroups:
err = e.setDataFromResourceGroups(sctx)
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -3386,6 +3388,23 @@ func (e *memtableRetriever) setDataFromPlacementPolicies(sctx sessionctx.Context
return nil
}

func (e *memtableRetriever) setDataFromResourceGroups(sctx sessionctx.Context) error {
is := sessiontxn.GetTxnManager(sctx).GetTxnInfoSchema()
resourceGroups := is.AllResourceGroups()
rows := make([][]types.Datum, 0, len(resourceGroups))
for _, group := range resourceGroups {
row := types.MakeDatums(
group.ID,
group.Name.O,
group.RRURate,
group.WRURate,
)
rows = append(rows, row)
}
e.rows = rows
return nil
}

func checkRule(rule *label.Rule) (dbName, tableName string, partitionName string, err error) {
s := strings.Split(rule.ID, "/")
if len(s) < 3 {
Expand Down
39 changes: 29 additions & 10 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,17 @@ var etcdDialTimeout = 5 * time.Second
type ShowExec struct {
baseExecutor

Tp ast.ShowStmtType // Databases/Tables/Columns/....
DBName model.CIStr
Table *ast.TableName // Used for showing columns.
Partition model.CIStr // Used for showing partition
Column *ast.ColumnName // Used for `desc table column`.
IndexName model.CIStr // Used for show table regions.
Flag int // Some flag parsed from sql, such as FULL.
Roles []*auth.RoleIdentity // Used for show grants.
User *auth.UserIdentity // Used by show grants, show create user.
Extractor plannercore.ShowPredicateExtractor
Tp ast.ShowStmtType // Databases/Tables/Columns/....
DBName model.CIStr
Table *ast.TableName // Used for showing columns.
Partition model.CIStr // Used for showing partition
Column *ast.ColumnName // Used for `desc table column`.
IndexName model.CIStr // Used for show table regions.
ResourceGroupName model.CIStr // Used for showing resource group
Flag int // Some flag parsed from sql, such as FULL.
Roles []*auth.RoleIdentity // Used for show grants.
User *auth.UserIdentity // Used by show grants, show create user.
Extractor plannercore.ShowPredicateExtractor

is infoschema.InfoSchema

Expand Down Expand Up @@ -182,6 +183,8 @@ func (e *ShowExec) fetchAll(ctx context.Context) error {
return e.fetchShowCreateDatabase()
case ast.ShowCreatePlacementPolicy:
return e.fetchShowCreatePlacementPolicy()
case ast.ShowCreateResourceGroup:
return e.fetchShowCreateResourceGroup()
case ast.ShowDatabases:
return e.fetchShowDatabases()
case ast.ShowDrainerStatus:
Expand Down Expand Up @@ -1452,6 +1455,11 @@ func ConstructResultOfShowCreatePlacementPolicy(policyInfo *model.PolicyInfo) st
return fmt.Sprintf("CREATE PLACEMENT POLICY `%s` %s", policyInfo.Name.O, policyInfo.PlacementSettings.String())
}

// constructResultOfShowCreateResourceGroup constructs the result for show create resource group.
func constructResultOfShowCreateResourceGroup(resourceGroup *model.ResourceGroupInfo) string {
return fmt.Sprintf("CREATE RESOURCE GROUP `%s` %s", resourceGroup.Name.O, resourceGroup.ResourceGroupSettings.String())
}

// fetchShowCreateDatabase composes show create database result.
func (e *ShowExec) fetchShowCreateDatabase() error {
checker := privilege.GetPrivilegeManager(e.ctx)
Expand Down Expand Up @@ -1485,6 +1493,17 @@ func (e *ShowExec) fetchShowCreatePlacementPolicy() error {
return nil
}

// fetchShowCreateResourceGroup composes show create resource group result.
func (e *ShowExec) fetchShowCreateResourceGroup() error {
group, found := e.is.ResourceGroupByName(e.ResourceGroupName)
if !found {
return infoschema.ErrResourceGroupNotExists.GenWithStackByArgs(e.ResourceGroupName.O)
}
showCreate := constructResultOfShowCreateResourceGroup(group)
e.appendRow([]interface{}{e.ResourceGroupName.O, showCreate})
return nil
}

func (e *ShowExec) fetchShowCollation() error {
var (
fieldPatternsLike collate.WildcardPattern
Expand Down
17 changes: 17 additions & 0 deletions executor/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,14 @@ func (e *SimpleExec) executeCreateUser(ctx context.Context, s *ast.CreateUserStm
if s.ResourceGroupNameOption.Type == ast.UserResourceGroupName {
resourceGroupName = s.ResourceGroupNameOption.Value
}

// check if specified resource group exists
if resourceGroupName != "default" && resourceGroupName != "" {
_, exists := e.is.ResourceGroupByName(model.NewCIStr(resourceGroupName))
if !exists {
return infoschema.ErrResourceGroupNotExists
}
}
}
userAttributes = append(userAttributes, fmt.Sprintf("\"resource_group\": \"%s\"", resourceGroupName))
// If FAILED_LOGIN_ATTEMPTS and PASSWORD_LOCK_TIME are both specified to 0, a string of 0 length is generated.
Expand Down Expand Up @@ -1900,6 +1908,15 @@ func (e *SimpleExec) executeAlterUser(ctx context.Context, s *ast.AlterUserStmt)
if !variable.EnableResourceControl.Load() {
return infoschema.ErrResourceGroupSupportDisabled
}

// check if specified resource group exists
if s.ResourceGroupNameOption.Value != "default" && s.ResourceGroupNameOption.Value != "" {
_, exists := e.is.ResourceGroupByName(model.NewCIStr(s.ResourceGroupNameOption.Value))
if !exists {
return infoschema.ErrResourceGroupNotExists
}
}

newAttributes = append(newAttributes, fmt.Sprintf(`"resource_group": "%s"`, s.ResourceGroupNameOption.Value))
}
if passwordLockingStr != "" {
Expand Down
1 change: 1 addition & 0 deletions executor/simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ func TestUserAttributes(t *testing.T) {
rootTK.MustExec("alter user usr1 comment 'comment1'")
rootTK.MustQuery("select user_attributes from mysql.user where user = 'usr1'").Check(testkit.Rows(`{"metadata": {"comment": "comment1"}, "resource_group": "default"}`))
rootTK.MustExec("set global tidb_enable_resource_control = 'on'")
rootTK.MustExec("CREATE RESOURCE GROUP rg1 rru_per_sec = 100 wru_per_sec = 200")
rootTK.MustExec("alter user usr1 resource group rg1")
rootTK.MustQuery("select user_attributes from mysql.user where user = 'usr1'").Check(testkit.Rows(`{"metadata": {"comment": "comment1"}, "resource_group": "rg1"}`))
}
1 change: 1 addition & 0 deletions infoschema/infoschema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ func TestInfoTables(t *testing.T) {
"DEADLOCKS",
"PLACEMENT_POLICIES",
"TRX_SUMMARY",
"RESOURCE_GROUPS",
}
for _, tbl := range infoTables {
tb, err1 := is.TableByName(util.InformationSchemaName, model.NewCIStr(tbl))
Expand Down
12 changes: 12 additions & 0 deletions infoschema/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ const (
TableMemoryUsage = "MEMORY_USAGE"
// TableMemoryUsageOpsHistory is the memory control operators history.
TableMemoryUsageOpsHistory = "MEMORY_USAGE_OPS_HISTORY"
// TableResourceGroups is the metadata of resource groups.
TableResourceGroups = "RESOURCE_GROUPS"
)

const (
Expand Down Expand Up @@ -304,6 +306,7 @@ var tableIDMap = map[string]int64{
TableMemoryUsageOpsHistory: autoid.InformationSchemaDBID + 85,
ClusterTableMemoryUsage: autoid.InformationSchemaDBID + 86,
ClusterTableMemoryUsageOpsHistory: autoid.InformationSchemaDBID + 87,
TableResourceGroups: autoid.InformationSchemaDBID + 88,
}

// columnInfo represents the basic column information of all kinds of INFORMATION_SCHEMA tables
Expand Down Expand Up @@ -1586,6 +1589,14 @@ var tableMemoryUsageOpsHistoryCols = []columnInfo{
{name: "SQL_TEXT", tp: mysql.TypeVarchar, size: 256},
}

var tableResourceGroupsCols = []columnInfo{
{name: "GROUP_ID", tp: mysql.TypeLonglong, size: 64, flag: mysql.NotNullFlag},
{name: "GROUP_NAME", tp: mysql.TypeVarchar, size: 512, flag: mysql.NotNullFlag},
{name: "RRU_PER_SECOND", tp: mysql.TypeLonglong, size: 64},
{name: "WRU_PER_SECOND", tp: mysql.TypeLonglong, size: 64},
// {name: "BURSTABLE", tp: mysql.TypeVarchar, size: 10},
}

// GetShardingInfo returns a nil or description string for the sharding information of given TableInfo.
// The returned description string may be:
// - "NOT_SHARDED": for tables that SHARD_ROW_ID_BITS is not specified.
Expand Down Expand Up @@ -2048,6 +2059,7 @@ var tableNameToColumns = map[string][]columnInfo{
TableUserAttributes: tableUserAttributesCols,
TableMemoryUsage: tableMemoryUsageCols,
TableMemoryUsageOpsHistory: tableMemoryUsageOpsHistoryCols,
TableResourceGroups: tableResourceGroupsCols,
}

func createInfoSchemaTable(_ autoid.Allocators, meta *model.TableInfo) (table.Table, error) {
Expand Down
31 changes: 18 additions & 13 deletions parser/ast/dml.go
Original file line number Diff line number Diff line change
Expand Up @@ -2771,6 +2771,7 @@ const (
ShowPlacementForPartition
ShowPlacementLabels
ShowSessionStates
ShowCreateResourceGroup
)

const (
Expand All @@ -2791,19 +2792,20 @@ const (
type ShowStmt struct {
dmlNode

Tp ShowStmtType // Databases/Tables/Columns/....
DBName string
Table *TableName // Used for showing columns.
Partition model.CIStr // Used for showing partition.
Column *ColumnName // Used for `desc table column`.
IndexName model.CIStr
Flag int // Some flag parsed from sql, such as FULL.
Full bool
User *auth.UserIdentity // Used for show grants/create user.
Roles []*auth.RoleIdentity // Used for show grants .. using
IfNotExists bool // Used for `show create database if not exists`
Extended bool // Used for `show extended columns from ...`
Limit *Limit // Used for partial Show STMTs to limit Result Set row numbers.
Tp ShowStmtType // Databases/Tables/Columns/....
DBName string
Table *TableName // Used for showing columns.
Partition model.CIStr // Used for showing partition.
Column *ColumnName // Used for `desc table column`.
IndexName model.CIStr
ResourceGroupName string // used for showing resource group
Flag int // Some flag parsed from sql, such as FULL.
Full bool
User *auth.UserIdentity // Used for show grants/create user.
Roles []*auth.RoleIdentity // Used for show grants .. using
IfNotExists bool // Used for `show create database if not exists`
Extended bool // Used for `show extended columns from ...`
Limit *Limit // Used for partial Show STMTs to limit Result Set row numbers.

CountWarningsOrErrors bool // Used for showing count(*) warnings | errors

Expand Down Expand Up @@ -2879,6 +2881,9 @@ func (n *ShowStmt) Restore(ctx *format.RestoreCtx) error {
case ShowCreatePlacementPolicy:
ctx.WriteKeyWord("CREATE PLACEMENT POLICY ")
ctx.WriteName(n.DBName)
case ShowCreateResourceGroup:
ctx.WriteKeyWord("CREATE RESOURCE GROUP ")
ctx.WriteName(n.ResourceGroupName)
case ShowCreateUser:
ctx.WriteKeyWord("CREATE USER ")
if err := n.User.Restore(ctx); err != nil {
Expand Down
Loading

0 comments on commit 971deb6

Please sign in to comment.