From f5408355094d55f2dc71838707a67bb30783981f Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Tue, 24 Aug 2021 12:27:22 +0800 Subject: [PATCH 1/7] *: Support `SHOW PLACEMENT` for placement policies --- executor/show.go | 2 + executor/show_placement.go | 21 ++++++++ infoschema/infoschema.go | 9 ++++ planner/core/planbuilder.go | 3 ++ util/placementpolicy/policy.go | 79 ++++++++++++++++++++++++----- util/placementpolicy/policy_test.go | 50 ++++++++++++++++++ 6 files changed, 151 insertions(+), 13 deletions(-) create mode 100644 util/placementpolicy/policy_test.go diff --git a/executor/show.go b/executor/show.go index 5fa6484ec9678..9fd69784d17b0 100644 --- a/executor/show.go +++ b/executor/show.go @@ -215,6 +215,8 @@ func (e *ShowExec) fetchAll(ctx context.Context) error { return e.fetchShowBRIE(ast.BRIEKindRestore) case ast.ShowPlacementLabels: return e.fetchShowPlacementLabels(ctx) + case ast.ShowPlacement: + return e.fetchShowPlacement(ctx) } return nil } diff --git a/executor/show_placement.go b/executor/show_placement.go index d074deca6e7e4..9408aafc995b9 100644 --- a/executor/show_placement.go +++ b/executor/show_placement.go @@ -127,3 +127,24 @@ func (e *ShowExec) fetchShowPlacementLabels(ctx context.Context) error { return nil } + +func (e *ShowExec) fetchShowPlacement(_ context.Context) error { + err := e.fetchAllPlacementPolicies() + if err != nil { + return err + } + + return nil +} + +func (e *ShowExec) fetchAllPlacementPolicies() error { + policies := e.is.AllPlacementPolicies() + sort.Slice(policies, func(i, j int) bool { return policies[i].Name.O < policies[j].Name.O }) + for _, policy := range policies { + name := policy.Name + settings := policy.PlacementSettings + e.appendRow([]interface{}{name.String(), settings.String(), "SCHEDULED"}) + } + + return nil +} diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index b13d0ede1fdbe..120d593dffaca 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -57,6 +57,8 @@ type InfoSchema interface { SetBundle(*placement.Bundle) // RuleBundles will return a copy of all rule bundles. RuleBundles() []*placement.Bundle + // AllPlacementPolicies returns all placement policies + AllPlacementPolicies() []*placementpolicy.PolicyInfo } type sortedTables []table.Table @@ -395,6 +397,13 @@ func (is *infoSchema) SetBundle(bundle *placement.Bundle) { is.ruleBundleMap[bundle.ID] = bundle } +func (is *infoSchema) AllPlacementPolicies() (policies []*placementpolicy.PolicyInfo) { + for _, p := range is.policyMap { + policies = append(policies, p) + } + return +} + func (is *infoSchema) deleteBundle(id string) { is.ruleBundleMutex.Lock() defer is.ruleBundleMutex.Unlock() diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 23eb31fd586f7..d7b627b367b13 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -4127,6 +4127,9 @@ func buildShowSchema(s *ast.ShowStmt, isView bool, isSequence bool) (schema *exp case ast.ShowPlacementLabels: names = []string{"Key", "Values"} ftypes = []byte{mysql.TypeVarchar, mysql.TypeJSON} + case ast.ShowPlacement: + names = []string{"Target", "Placement", "Scheduling_state"} + ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar} } schema = expression.NewSchema(make([]*expression.Column, 0, len(names))...) diff --git a/util/placementpolicy/policy.go b/util/placementpolicy/policy.go index 4768e76ed43aa..d313182cc1779 100644 --- a/util/placementpolicy/policy.go +++ b/util/placementpolicy/policy.go @@ -15,22 +15,75 @@ package placementpolicy import ( + "fmt" + "strings" + "github.com/pingcap/parser/model" ) +// PlacementSettings is the settings of the placement +type PlacementSettings struct { + PrimaryRegion string `json:"primary_region"` + Regions string `json:"regions"` + Learners uint64 `json:"learners"` + Followers uint64 `json:"followers"` + Voters uint64 `json:"voters"` + Schedule string `json:"schedule"` + Constraints string `json:"constraints"` + LearnerConstraints string `json:"learner_constraints"` + FollowerConstraints string `json:"follower_constraints"` + VoterConstraints string `json:"voter_constraints"` +} + +func (p *PlacementSettings) String() string { + settings := make([]string, 0) + if len(p.PrimaryRegion) > 0 { + settings = append(settings, fmt.Sprintf("PRIMARY_REGION=\"%s\"", p.PrimaryRegion)) + } + + if len(p.Regions) > 0 { + settings = append(settings, fmt.Sprintf("REGIONS=\"%s\"", p.Regions)) + } + + if p.Voters > 0 { + settings = append(settings, fmt.Sprintf("VOTERS=%d", p.Voters)) + } + + if len(p.VoterConstraints) > 0 { + settings = append(settings, fmt.Sprintf("VOTER_CONSTRAINTS=\"%s\"", p.VoterConstraints)) + } + + if p.Followers > 0 { + settings = append(settings, fmt.Sprintf("FOLLOWERS=%d", p.Followers)) + } + + if len(p.FollowerConstraints) > 0 { + settings = append(settings, fmt.Sprintf("FOLLOWER_CONSTRAINTS=\"%s\"", p.FollowerConstraints)) + } + + if p.Learners > 0 { + settings = append(settings, fmt.Sprintf("LEARNERS=%d", p.Learners)) + } + + if len(p.LearnerConstraints) > 0 { + settings = append(settings, fmt.Sprintf("LEARNER_CONSTRAINTS=\"%s\"", p.LearnerConstraints)) + } + + if len(p.Constraints) > 0 { + settings = append(settings, fmt.Sprintf("CONSTRAINTS=\"%s\"", p.Constraints)) + } + + if len(p.Schedule) > 0 { + settings = append(settings, fmt.Sprintf("SCHEDULE=\"%s\"", p.Schedule)) + } + + return strings.Join(settings, " ") +} + // PolicyInfo is the struct to store the placement policy. type PolicyInfo struct { - ID int64 `json:"id"` - Name model.CIStr `json:"name"` - PrimaryRegion string `json:"primary_region"` - Regions string `json:"regions"` - Learners uint64 `json:"learners"` - Followers uint64 `json:"followers"` - Voters uint64 `json:"voters"` - Schedule string `json:"schedule"` - Constraints string `json:"constraints"` - LearnerConstraints string `json:"learner_constraints"` - FollowerConstraints string `json:"follower_constraints"` - VoterConstraints string `json:"voter_constraints"` - State model.SchemaState `json:"state"` + PlacementSettings + ID int64 `json:"id"` + Name model.CIStr `json:"name"` + State model.SchemaState `json:"state"` } diff --git a/util/placementpolicy/policy_test.go b/util/placementpolicy/policy_test.go new file mode 100644 index 0000000000000..f4e02430a6a14 --- /dev/null +++ b/util/placementpolicy/policy_test.go @@ -0,0 +1,50 @@ +// Copyright 2021 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 placementpolicy + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPlacementSettingsString(t *testing.T) { + assert := assert.New(t) + + settings := &PlacementSettings{ + PrimaryRegion: "us-east-1", + Regions: "us-east-1,us-east-2", + Voters: 2, + } + assert.Equal("PRIMARY_REGION=\"us-east-1\" REGIONS=\"us-east-1,us-east-2\" VOTERS=2", settings.String()) + + settings = &PlacementSettings{ + Voters: 1, + VoterConstraints: "[+region=us-east-1]", + Followers: 2, + FollowerConstraints: "[+disk=ssd]", + Learners: 3, + LearnerConstraints: "[+region=us-east-2]", + Schedule: "EVEN", + } + assert.Equal("VOTERS=1 VOTER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2 FOLLOWER_CONSTRAINTS=\"[+disk=ssd]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULE=\"EVEN\"", settings.String()) + + settings = &PlacementSettings{ + Voters: 3, + Followers: 2, + Learners: 1, + Constraints: "{+us-east-1:1,+us-east-2:1}", + } + assert.Equal("VOTERS=3 FOLLOWERS=2 LEARNERS=1 CONSTRAINTS=\"{+us-east-1:1,+us-east-2:1}\"", settings.String()) +} From 5a40396b28cb909b5e8dd7bec2d8d58fed91947d Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Tue, 24 Aug 2021 13:59:03 +0800 Subject: [PATCH 2/7] fix test --- meta/meta_test.go | 20 +++++++++++--------- util/placementpolicy/policy_test.go | 1 + 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/meta/meta_test.go b/meta/meta_test.go index d5512a1145ced..13146351ccc6d 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -52,15 +52,17 @@ func TestPlacementPolicy(t *testing.T) { // test the meta storage of placemnt policy. policy := &placementpolicy.PolicyInfo{ - Name: model.NewCIStr("aa"), - PrimaryRegion: "my primary", - Regions: "my regions", - Learners: 1, - Followers: 2, - Voters: 3, - Schedule: "even", - Constraints: "+disk=ssd", - LearnerConstraints: "+zone=shanghai", + Name: model.NewCIStr("aa"), + PlacementSettings: placementpolicy.PlacementSettings{ + PrimaryRegion: "my primary", + Regions: "my regions", + Learners: 1, + Followers: 2, + Voters: 3, + Schedule: "even", + Constraints: "+disk=ssd", + LearnerConstraints: "+zone=shanghai", + }, } err = m.CreatePolicy(policy) require.NoError(t, err) diff --git a/util/placementpolicy/policy_test.go b/util/placementpolicy/policy_test.go index f4e02430a6a14..f159719e7e34f 100644 --- a/util/placementpolicy/policy_test.go +++ b/util/placementpolicy/policy_test.go @@ -8,6 +8,7 @@ // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. From 949a53981da24df1e1f41ccf4b40e94640c3c989 Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Mon, 30 Aug 2021 13:52:00 +0800 Subject: [PATCH 3/7] add some tests --- executor/show_placement.go | 2 +- executor/show_placement_labels_test.go | 85 ++++++++++++++++++++++ executor/show_placement_test.go | 99 +++++++++++--------------- util/placementpolicy/policy.go | 16 ++--- 4 files changed, 134 insertions(+), 68 deletions(-) create mode 100644 executor/show_placement_labels_test.go diff --git a/executor/show_placement.go b/executor/show_placement.go index 9408aafc995b9..32da7f6d8827d 100644 --- a/executor/show_placement.go +++ b/executor/show_placement.go @@ -143,7 +143,7 @@ func (e *ShowExec) fetchAllPlacementPolicies() error { for _, policy := range policies { name := policy.Name settings := policy.PlacementSettings - e.appendRow([]interface{}{name.String(), settings.String(), "SCHEDULED"}) + e.appendRow([]interface{}{"POLICY " + name.String(), settings.String(), "SCHEDULED"}) } return nil diff --git a/executor/show_placement_labels_test.go b/executor/show_placement_labels_test.go new file mode 100644 index 0000000000000..3e3efcd865738 --- /dev/null +++ b/executor/show_placement_labels_test.go @@ -0,0 +1,85 @@ +// Copyright 2021 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, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package executor + +import ( + gjson "encoding/json" + + . "github.com/pingcap/check" + "github.com/pingcap/tidb/store/helper" + "github.com/pingcap/tidb/types/json" +) + +var _ = SerialSuites(&testShowPlacementLabelSuit{}) + +type testShowPlacementLabelSuit struct { +} + +func (s *testShowPlacementLabelSuit) TestShowPlacementLabelsBuilder(c *C) { + cases := []struct { + stores [][]*helper.StoreLabel + expects [][]interface{} + }{ + { + stores: nil, + expects: nil, + }, + { + stores: [][]*helper.StoreLabel{ + {{Key: "zone", Value: "z1"}, {Key: "rack", Value: "r3"}, {Key: "host", Value: "h1"}}, + {{Key: "zone", Value: "z1"}, {Key: "rack", Value: "r1"}, {Key: "host", Value: "h2"}}, + {{Key: "zone", Value: "z1"}, {Key: "rack", Value: "r2"}, {Key: "host", Value: "h2"}}, + {{Key: "zone", Value: "z2"}, {Key: "rack", Value: "r1"}, {Key: "host", Value: "h2"}}, + nil, + {{Key: "k1", Value: "v1"}}, + }, + expects: [][]interface{}{ + {"host", []string{"h1", "h2"}}, + {"k1", []string{"v1"}}, + {"rack", []string{"r1", "r2", "r3"}}, + {"zone", []string{"z1", "z2"}}, + }, + }, + } + + b := &showPlacementLabelsResultBuilder{} + toBinaryJSON := func(obj interface{}) (bj json.BinaryJSON) { + d, err := gjson.Marshal(obj) + c.Assert(err, IsNil) + err = bj.UnmarshalJSON(d) + c.Assert(err, IsNil) + return + } + + for _, ca := range cases { + for _, store := range ca.stores { + bj := toBinaryJSON(store) + err := b.AppendStoreLabels(bj) + c.Assert(err, IsNil) + } + + rows, err := b.BuildRows() + c.Assert(err, IsNil) + c.Assert(len(rows), Equals, len(ca.expects)) + for idx, expect := range ca.expects { + row := rows[idx] + bj := toBinaryJSON(expect[1]) + + c.Assert(row[0].(string), Equals, expect[0].(string)) + c.Assert(row[1].(json.BinaryJSON).TypeCode, Equals, bj.TypeCode) + c.Assert(row[1].(json.BinaryJSON).Value, BytesEquals, bj.Value) + } + } +} diff --git a/executor/show_placement_test.go b/executor/show_placement_test.go index 6b9303d59d37f..c51a1292ea396 100644 --- a/executor/show_placement_test.go +++ b/executor/show_placement_test.go @@ -12,74 +12,55 @@ // See the License for the specific language governing permissions and // limitations under the License. -package executor +package executor_test import ( - gjson "encoding/json" - . "github.com/pingcap/check" - "github.com/pingcap/tidb/store/helper" - "github.com/pingcap/tidb/types/json" + "github.com/pingcap/tidb/util/testkit" ) -var _ = SerialSuites(&testShowPlacementSuit{}) +func (s *testSuite5) TestShowPlacement(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("drop placement policy if exists p1") -type testShowPlacementSuit struct { -} + tk.MustExec("create placement policy pa1 " + + "PRIMARY_REGION=\"cn-east-1\" " + + "REGIONS=\"cn-east-1,cn-east-2\"" + + "SCHEDULE=\"EVEN\"") + defer tk.MustExec("drop placement policy pa1") + + tk.MustExec("create placement policy pa2 " + + "LEADER_CONSTRAINTS=\"[+region=us-east-1]\" " + + "FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" " + + "FOLLOWERS=3") + defer tk.MustExec("drop placement policy pa2") -func (s *testPartitionSuite) TestShowPlacementLabelsBuilder(c *C) { - cases := []struct { - stores [][]*helper.StoreLabel - expects [][]interface{} - }{ - { - stores: nil, - expects: nil, - }, - { - stores: [][]*helper.StoreLabel{ - {{Key: "zone", Value: "z1"}, {Key: "rack", Value: "r3"}, {Key: "host", Value: "h1"}}, - {{Key: "zone", Value: "z1"}, {Key: "rack", Value: "r1"}, {Key: "host", Value: "h2"}}, - {{Key: "zone", Value: "z1"}, {Key: "rack", Value: "r2"}, {Key: "host", Value: "h2"}}, - {{Key: "zone", Value: "z2"}, {Key: "rack", Value: "r1"}, {Key: "host", Value: "h2"}}, - nil, - {{Key: "k1", Value: "v1"}}, - }, - expects: [][]interface{}{ - {"host", []string{"h1", "h2"}}, - {"k1", []string{"v1"}}, - {"rack", []string{"r1", "r2", "r3"}}, - {"zone", []string{"z1", "z2"}}, - }, - }, - } + tk.MustExec("create placement policy pb1 " + + "VOTER_CONSTRAINTS=\"[+region=bj]\" " + + "LEARNER_CONSTRAINTS=\"[+region=sh]\" " + + "CONSTRAINTS=\"[+disk=ssd]\"" + + "VOTERS=5 " + + "LEARNERS=3") + defer tk.MustExec("drop placement policy pb1") - b := &showPlacementLabelsResultBuilder{} - toBinaryJSON := func(obj interface{}) (bj json.BinaryJSON) { - d, err := gjson.Marshal(obj) - c.Assert(err, IsNil) - err = bj.UnmarshalJSON(d) - c.Assert(err, IsNil) - return - } + tk.MustQuery("show placement").Check(testkit.Rows( + "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\" SCHEDULED", + "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULED", + "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\" SCHEDULED", + )) - for _, ca := range cases { - for _, store := range ca.stores { - bj := toBinaryJSON(store) - err := b.AppendStoreLabels(bj) - c.Assert(err, IsNil) - } + tk.MustQuery("show placement like 'POLICY%'").Check(testkit.Rows( + "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\" SCHEDULED", + "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULED", + "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\" SCHEDULED", + )) - rows, err := b.BuildRows() - c.Assert(err, IsNil) - c.Assert(len(rows), Equals, len(ca.expects)) - for idx, expect := range ca.expects { - row := rows[idx] - bj := toBinaryJSON(expect[1]) + tk.MustQuery("show placement like 'POLICY pa%'").Check(testkit.Rows( + "POLICY pa1 PRIMARY_REGION=\"cn-east-1\" REGIONS=\"cn-east-1,cn-east-2\" SCHEDULE=\"EVEN\" SCHEDULED", + "POLICY pa2 LEADER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=3 FOLLOWER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULED", + )) - c.Assert(row[0].(string), Equals, expect[0].(string)) - c.Assert(row[1].(json.BinaryJSON).TypeCode, Equals, bj.TypeCode) - c.Assert(row[1].(json.BinaryJSON).Value, BytesEquals, bj.Value) - } - } + tk.MustQuery("show placement where Target='POLICY pb1'").Check(testkit.Rows( + "POLICY pb1 CONSTRAINTS=\"[+disk=ssd]\" VOTERS=5 VOTER_CONSTRAINTS=\"[+region=bj]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=sh]\" SCHEDULED", + )) } diff --git a/util/placementpolicy/policy.go b/util/placementpolicy/policy.go index 245792e929433..518e22e3aa18c 100644 --- a/util/placementpolicy/policy.go +++ b/util/placementpolicy/policy.go @@ -46,6 +46,14 @@ func (p *PlacementSettings) String() string { settings = append(settings, fmt.Sprintf("REGIONS=\"%s\"", p.Regions)) } + if len(p.Schedule) > 0 { + settings = append(settings, fmt.Sprintf("SCHEDULE=\"%s\"", p.Schedule)) + } + + if len(p.Constraints) > 0 { + settings = append(settings, fmt.Sprintf("CONSTRAINTS=\"%s\"", p.Constraints)) + } + if len(p.LeaderConstraints) > 0 { settings = append(settings, fmt.Sprintf("LEADER_CONSTRAINTS=\"%s\"", p.LeaderConstraints)) } @@ -74,14 +82,6 @@ func (p *PlacementSettings) String() string { settings = append(settings, fmt.Sprintf("LEARNER_CONSTRAINTS=\"%s\"", p.LearnerConstraints)) } - if len(p.Constraints) > 0 { - settings = append(settings, fmt.Sprintf("CONSTRAINTS=\"%s\"", p.Constraints)) - } - - if len(p.Schedule) > 0 { - settings = append(settings, fmt.Sprintf("SCHEDULE=\"%s\"", p.Schedule)) - } - return strings.Join(settings, " ") } From 2834dd43bf8a9d8e17fad338f78476da026b4a5c Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Mon, 30 Aug 2021 17:07:43 +0800 Subject: [PATCH 4/7] modify some tests --- util/placementpolicy/policy_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/util/placementpolicy/policy_test.go b/util/placementpolicy/policy_test.go index f159719e7e34f..c4e07ec7c186b 100644 --- a/util/placementpolicy/policy_test.go +++ b/util/placementpolicy/policy_test.go @@ -26,9 +26,14 @@ func TestPlacementSettingsString(t *testing.T) { settings := &PlacementSettings{ PrimaryRegion: "us-east-1", Regions: "us-east-1,us-east-2", - Voters: 2, + Schedule: "EVEN", } - assert.Equal("PRIMARY_REGION=\"us-east-1\" REGIONS=\"us-east-1,us-east-2\" VOTERS=2", settings.String()) + assert.Equal("PRIMARY_REGION=\"us-east-1\" REGIONS=\"us-east-1,us-east-2\" SCHEDULE=\"EVEN\"", settings.String()) + + settings = &PlacementSettings{ + LeaderConstraints: "[+region=bj]", + } + assert.Equal("LEADER_CONSTRAINTS=\"[+region=bj]\"", settings.String()) settings = &PlacementSettings{ Voters: 1, @@ -37,9 +42,8 @@ func TestPlacementSettingsString(t *testing.T) { FollowerConstraints: "[+disk=ssd]", Learners: 3, LearnerConstraints: "[+region=us-east-2]", - Schedule: "EVEN", } - assert.Equal("VOTERS=1 VOTER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2 FOLLOWER_CONSTRAINTS=\"[+disk=ssd]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=us-east-2]\" SCHEDULE=\"EVEN\"", settings.String()) + assert.Equal("VOTERS=1 VOTER_CONSTRAINTS=\"[+region=us-east-1]\" FOLLOWERS=2 FOLLOWER_CONSTRAINTS=\"[+disk=ssd]\" LEARNERS=3 LEARNER_CONSTRAINTS=\"[+region=us-east-2]\"", settings.String()) settings = &PlacementSettings{ Voters: 3, @@ -47,5 +51,5 @@ func TestPlacementSettingsString(t *testing.T) { Learners: 1, Constraints: "{+us-east-1:1,+us-east-2:1}", } - assert.Equal("VOTERS=3 FOLLOWERS=2 LEARNERS=1 CONSTRAINTS=\"{+us-east-1:1,+us-east-2:1}\"", settings.String()) + assert.Equal("CONSTRAINTS=\"{+us-east-1:1,+us-east-2:1}\" VOTERS=3 FOLLOWERS=2 LEARNERS=1", settings.String()) } From b70a76a72fc98d13122f59397523d362de49760b Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Mon, 30 Aug 2021 17:54:30 +0800 Subject: [PATCH 5/7] rename --- .../{policy_test.go => placement_settings_test.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename util/placementpolicy/{policy_test.go => placement_settings_test.go} (100%) diff --git a/util/placementpolicy/policy_test.go b/util/placementpolicy/placement_settings_test.go similarity index 100% rename from util/placementpolicy/policy_test.go rename to util/placementpolicy/placement_settings_test.go From 6987274dd191a68f7e88744ce521866c1901c1a9 Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Mon, 30 Aug 2021 17:56:38 +0800 Subject: [PATCH 6/7] add test main --- .../{placement_settings_test.go => policy_test.go} | 7 +++++++ 1 file changed, 7 insertions(+) rename util/placementpolicy/{placement_settings_test.go => policy_test.go} (91%) diff --git a/util/placementpolicy/placement_settings_test.go b/util/placementpolicy/policy_test.go similarity index 91% rename from util/placementpolicy/placement_settings_test.go rename to util/placementpolicy/policy_test.go index c4e07ec7c186b..aa6e305c56486 100644 --- a/util/placementpolicy/placement_settings_test.go +++ b/util/placementpolicy/policy_test.go @@ -17,9 +17,16 @@ package placementpolicy import ( "testing" + "github.com/pingcap/tidb/util/testbridge" "github.com/stretchr/testify/assert" + "go.uber.org/goleak" ) +func TestMain(m *testing.M) { + testbridge.WorkaroundGoCheckFlags() + goleak.VerifyTestMain(m) +} + func TestPlacementSettingsString(t *testing.T) { assert := assert.New(t) From 7ade5ddc476433e667d5077cf6aacbb47e5d2a53 Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Tue, 31 Aug 2021 17:17:45 +0800 Subject: [PATCH 7/7] some modifies --- infoschema/builder.go | 2 +- infoschema/infoschema.go | 10 ++-------- util/placementpolicy/policy.go | 33 ++++++++++++++++++++------------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/infoschema/builder.go b/infoschema/builder.go index 4277356c999e5..c2919c661e97a 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -537,7 +537,7 @@ func (b *Builder) copyPoliciesMap(oldIS *infoSchema) { is := b.is is.policyMutex.Lock() defer is.policyMutex.Unlock() - for _, v := range oldIS.PlacementPolicies() { + for _, v := range oldIS.AllPlacementPolicies() { is.policyMap[v.Name.L] = v } } diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index 2d81615189284..bf7ef8dcce578 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -375,7 +375,8 @@ func (is *infoSchema) PolicyByName(name model.CIStr) (*placementpolicy.PolicyInf return t, r } -func (is *infoSchema) PlacementPolicies() []*placementpolicy.PolicyInfo { +// AllPlacementPolicies returns all placement policies +func (is *infoSchema) AllPlacementPolicies() []*placementpolicy.PolicyInfo { is.policyMutex.RLock() defer is.policyMutex.RUnlock() policies := make([]*placementpolicy.PolicyInfo, 0, len(is.policyMap)) @@ -408,13 +409,6 @@ func (is *infoSchema) SetBundle(bundle *placement.Bundle) { is.ruleBundleMap[bundle.ID] = bundle } -func (is *infoSchema) AllPlacementPolicies() (policies []*placementpolicy.PolicyInfo) { - for _, p := range is.policyMap { - policies = append(policies, p) - } - return -} - func (is *infoSchema) deleteBundle(id string) { is.ruleBundleMutex.Lock() defer is.ruleBundleMutex.Unlock() diff --git a/util/placementpolicy/policy.go b/util/placementpolicy/policy.go index 518e22e3aa18c..6e485a1852ba4 100644 --- a/util/placementpolicy/policy.go +++ b/util/placementpolicy/policy.go @@ -36,53 +36,60 @@ type PlacementSettings struct { VoterConstraints string `json:"voter_constraints"` } +func writeSettingItemToBuilder(sb *strings.Builder, item string) { + if sb.Len() != 0 { + sb.WriteString(" ") + } + sb.WriteString(item) +} + func (p *PlacementSettings) String() string { - settings := make([]string, 0) + sb := new(strings.Builder) if len(p.PrimaryRegion) > 0 { - settings = append(settings, fmt.Sprintf("PRIMARY_REGION=\"%s\"", p.PrimaryRegion)) + writeSettingItemToBuilder(sb, fmt.Sprintf("PRIMARY_REGION=\"%s\"", p.PrimaryRegion)) } if len(p.Regions) > 0 { - settings = append(settings, fmt.Sprintf("REGIONS=\"%s\"", p.Regions)) + writeSettingItemToBuilder(sb, fmt.Sprintf("REGIONS=\"%s\"", p.Regions)) } if len(p.Schedule) > 0 { - settings = append(settings, fmt.Sprintf("SCHEDULE=\"%s\"", p.Schedule)) + writeSettingItemToBuilder(sb, fmt.Sprintf("SCHEDULE=\"%s\"", p.Schedule)) } if len(p.Constraints) > 0 { - settings = append(settings, fmt.Sprintf("CONSTRAINTS=\"%s\"", p.Constraints)) + writeSettingItemToBuilder(sb, fmt.Sprintf("CONSTRAINTS=\"%s\"", p.Constraints)) } if len(p.LeaderConstraints) > 0 { - settings = append(settings, fmt.Sprintf("LEADER_CONSTRAINTS=\"%s\"", p.LeaderConstraints)) + writeSettingItemToBuilder(sb, fmt.Sprintf("LEADER_CONSTRAINTS=\"%s\"", p.LeaderConstraints)) } if p.Voters > 0 { - settings = append(settings, fmt.Sprintf("VOTERS=%d", p.Voters)) + writeSettingItemToBuilder(sb, fmt.Sprintf("VOTERS=%d", p.Voters)) } if len(p.VoterConstraints) > 0 { - settings = append(settings, fmt.Sprintf("VOTER_CONSTRAINTS=\"%s\"", p.VoterConstraints)) + writeSettingItemToBuilder(sb, fmt.Sprintf("VOTER_CONSTRAINTS=\"%s\"", p.VoterConstraints)) } if p.Followers > 0 { - settings = append(settings, fmt.Sprintf("FOLLOWERS=%d", p.Followers)) + writeSettingItemToBuilder(sb, fmt.Sprintf("FOLLOWERS=%d", p.Followers)) } if len(p.FollowerConstraints) > 0 { - settings = append(settings, fmt.Sprintf("FOLLOWER_CONSTRAINTS=\"%s\"", p.FollowerConstraints)) + writeSettingItemToBuilder(sb, fmt.Sprintf("FOLLOWER_CONSTRAINTS=\"%s\"", p.FollowerConstraints)) } if p.Learners > 0 { - settings = append(settings, fmt.Sprintf("LEARNERS=%d", p.Learners)) + writeSettingItemToBuilder(sb, fmt.Sprintf("LEARNERS=%d", p.Learners)) } if len(p.LearnerConstraints) > 0 { - settings = append(settings, fmt.Sprintf("LEARNER_CONSTRAINTS=\"%s\"", p.LearnerConstraints)) + writeSettingItemToBuilder(sb, fmt.Sprintf("LEARNER_CONSTRAINTS=\"%s\"", p.LearnerConstraints)) } - return strings.Join(settings, " ") + return sb.String() } // PolicyInfo is the struct to store the placement policy.