From db0349de09fae328ce55a0d8c3b8f32e9e7a9267 Mon Sep 17 00:00:00 2001 From: JmPotato Date: Thu, 23 Nov 2023 22:54:49 +0800 Subject: [PATCH 1/2] Integrate PD HTTP client into the placement manager Signed-off-by: JmPotato --- DEPS.bzl | 12 +- go.mod | 1 + go.sum | 4 +- pkg/ddl/placement/BUILD.bazel | 2 + pkg/ddl/placement/bundle.go | 86 ++-- pkg/ddl/placement/bundle_test.go | 585 ++++++++++++----------- pkg/ddl/placement/constraint.go | 53 +- pkg/ddl/placement/constraint_test.go | 35 +- pkg/ddl/placement/constraints.go | 46 +- pkg/ddl/placement/constraints_test.go | 27 +- pkg/ddl/placement/meta_bundle_test.go | 5 +- pkg/ddl/placement/rule.go | 97 ++-- pkg/ddl/placement/rule_test.go | 61 +-- pkg/domain/infosync/info.go | 8 +- pkg/domain/infosync/placement_manager.go | 44 +- pkg/domain/infosync/tiflash_manager.go | 36 +- 16 files changed, 517 insertions(+), 585 deletions(-) diff --git a/DEPS.bzl b/DEPS.bzl index d0adcb9d90879..fce821be35c63 100644 --- a/DEPS.bzl +++ b/DEPS.bzl @@ -7158,13 +7158,13 @@ def go_deps(): name = "com_github_tikv_pd_client", build_file_proto_mode = "disable_global", importpath = "github.com/tikv/pd/client", - sha256 = "440821579da980d0405695b463da892608a59252a296cd7e52b4f97881c5fdb7", - strip_prefix = "github.com/tikv/pd/client@v0.0.0-20231121080541-8919bc11f770", + sha256 = "38789aba9a8542056f58fa8374e794a7b0c5949531744a9962634385b717134f", + strip_prefix = "github.com/JmPotato/pd/client@v0.0.0-20231123144827-8fc4cf2ee7b0", urls = [ - "http://bazel-cache.pingcap.net:8080/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231121080541-8919bc11f770.zip", - "http://ats.apps.svc/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231121080541-8919bc11f770.zip", - "https://cache.hawkingrei.com/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231121080541-8919bc11f770.zip", - "https://storage.googleapis.com/pingcapmirror/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231121080541-8919bc11f770.zip", + "http://bazel-cache.pingcap.net:8080/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", + "http://ats.apps.svc/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", + "https://cache.hawkingrei.com/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", + "https://storage.googleapis.com/pingcapmirror/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", ], ) go_repository( diff --git a/go.mod b/go.mod index c9942e6ef235e..4b89cb2c77649 100644 --- a/go.mod +++ b/go.mod @@ -314,4 +314,5 @@ replace ( github.com/dgrijalva/jwt-go => github.com/form3tech-oss/jwt-go v3.2.6-0.20210809144907-32ab6a8243d7+incompatible github.com/go-ldap/ldap/v3 => github.com/YangKeao/ldap/v3 v3.4.5-0.20230421065457-369a3bab1117 github.com/pingcap/tidb/pkg/parser => ./pkg/parser + github.com/tikv/pd/client v0.0.0-20231121080541-8919bc11f770 => github.com/JmPotato/pd/client v0.0.0-20231123144827-8fc4cf2ee7b0 ) diff --git a/go.sum b/go.sum index 211a12881ffa8..b8ba77b331e47 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Jeffail/gabs/v2 v2.5.1 h1:ANfZYjpMlfTTKebycu4X1AgkVWumFVDYQl7JwOr4mDk= github.com/Jeffail/gabs/v2 v2.5.1/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI= +github.com/JmPotato/pd/client v0.0.0-20231123144827-8fc4cf2ee7b0 h1:EfoujwJPhwsS0Qe/Tc60nn2e9HfJPM9w5zbspIYNI74= +github.com/JmPotato/pd/client v0.0.0-20231123144827-8fc4cf2ee7b0/go.mod h1:cd6zBqRM9aogxf26K8NnFRPVtq9BnRE59tKEpX8IaWQ= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -992,8 +994,6 @@ github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a h1:J/YdBZ46WKpXsxsW github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a/go.mod h1:h4xBhSNtOeEosLJ4P7JyKXX7Cabg7AVkWCK5gV2vOrM= github.com/tikv/client-go/v2 v2.0.8-0.20231116051730-1c2351c28173 h1:lmJzX0kqrV7kO21wrZPbtjkidzwbDCfXeQrhDWEi5dE= github.com/tikv/client-go/v2 v2.0.8-0.20231116051730-1c2351c28173/go.mod h1:BOGTSZtbMHEnGC4HOpbONdnTQF+E9nb2Io7c3P9sb7g= -github.com/tikv/pd/client v0.0.0-20231121080541-8919bc11f770 h1:YSXDKT9+KngRSAShoSQVKD/CK1kR4X/9hutKkSK9gn0= -github.com/tikv/pd/client v0.0.0-20231121080541-8919bc11f770/go.mod h1:cd6zBqRM9aogxf26K8NnFRPVtq9BnRE59tKEpX8IaWQ= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= diff --git a/pkg/ddl/placement/BUILD.bazel b/pkg/ddl/placement/BUILD.bazel index 894d93ab0a3c8..32914e98ab5a1 100644 --- a/pkg/ddl/placement/BUILD.bazel +++ b/pkg/ddl/placement/BUILD.bazel @@ -17,6 +17,7 @@ go_library( "//pkg/tablecodec", "//pkg/util/codec", "@com_github_pingcap_failpoint//:failpoint", + "@com_github_tikv_pd_client//http", "@in_gopkg_yaml_v2//:yaml_v2", ], ) @@ -45,5 +46,6 @@ go_test( "//pkg/util/codec", "@com_github_pingcap_failpoint//:failpoint", "@com_github_stretchr_testify//require", + "@com_github_tikv_pd_client//http", ], ) diff --git a/pkg/ddl/placement/bundle.go b/pkg/ddl/placement/bundle.go index e9331571c6d2c..891365249b37e 100644 --- a/pkg/ddl/placement/bundle.go +++ b/pkg/ddl/placement/bundle.go @@ -29,21 +29,13 @@ import ( "github.com/pingcap/tidb/pkg/parser/model" "github.com/pingcap/tidb/pkg/tablecodec" "github.com/pingcap/tidb/pkg/util/codec" + pd "github.com/tikv/pd/client/http" "gopkg.in/yaml.v2" ) -// Refer to https://github.com/tikv/pd/issues/2701 . -// IMO, it is indeed not bad to have a copy of definition. -// After all, placement rules are communicated using an HTTP API. Loose -// coupling is a good feature. - // Bundle is a group of all rules and configurations. It is used to support rule cache. -type Bundle struct { - ID string `json:"group_id"` - Index int `json:"group_index"` - Override bool `json:"group_override"` - Rules []*Rule `json:"rules"` -} +// Alias `pd.GroupBundle` is to wrap more methods. +type Bundle pd.GroupBundle // NewBundle will create a bundle with the provided ID. // Note that you should never pass negative id. @@ -70,7 +62,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, explicitFollowerCount := options.Followers explicitLearnerCount := options.Learners - rules := []*Rule{} + rules := []*pd.Rule{} commonConstraints, err := NewConstraintsFromYaml([]byte(constraints)) if err != nil { // If it's not in array format, attempt to parse it as a dictionary for more detailed definitions. @@ -78,7 +70,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, // replicas that should act as voters. // For example: CONSTRAINTS='{ "+region=us-east-1":2, "+region=us-east-2": 2, "+region=us-west-1": 1}' normalReplicasRules, err := NewRuleBuilder(). - SetRole(Voter). + SetRole(pd.Voter). SetConstraintStr(constraints). BuildRulesWithDictConstraintsOnly() if err != nil { @@ -92,7 +84,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, return nil, fmt.Errorf("%w: 'LeaderConstraints' should be [constraint1, ...] or any yaml compatible array representation", err) } for _, cnst := range commonConstraints { - if err := leaderConstraints.Add(cnst); err != nil { + if err := AddConstraint(&leaderConstraints, cnst); err != nil { return nil, fmt.Errorf("%w: LeaderConstraints conflicts with Constraints", err) } } @@ -101,7 +93,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, followerReplicas = explicitFollowerCount } if !needCreateDefault { - if len(leaderConstraints) == 0 { + if len(leaderConst) == 0 { leaderReplicas = 0 } if len(followerConstraints) == 0 { @@ -115,7 +107,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, // create leader rule. // if no constraints, we need create default leader rule. if leaderReplicas > 0 { - leaderRule := NewRule(Leader, leaderReplicas, leaderConstraints) + leaderRule := NewRule(pd.Leader, leaderReplicas, leaderConstraints) rules = append(rules, leaderRule) } @@ -123,7 +115,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, // if no constraints, we need create default follower rules. if followerReplicas > 0 { builder := NewRuleBuilder(). - SetRole(Voter). + SetRole(pd.Voter). SetReplicasNum(followerReplicas). SetSkipCheckReplicasConsistent(needCreateDefault && (explicitFollowerCount == 0)). SetConstraintStr(followerConstraints) @@ -133,7 +125,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, } for _, followerRule := range followerRules { for _, cnst := range commonConstraints { - if err := followerRule.Constraints.Add(cnst); err != nil { + if err := AddConstraint(&followerRule.LabelConstraints, cnst); err != nil { return nil, fmt.Errorf("%w: FollowerConstraints conflicts with Constraints", err) } } @@ -143,7 +135,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, // create learner rules. builder := NewRuleBuilder(). - SetRole(Learner). + SetRole(pd.Learner). SetReplicasNum(explicitLearnerCount). SetConstraintStr(learnerConstraints) learnerRules, err := builder.BuildRules() @@ -152,7 +144,7 @@ func NewBundleFromConstraintsOptions(options *model.PlacementSettings) (*Bundle, } for _, rule := range learnerRules { for _, cnst := range commonConstraints { - if err := rule.Constraints.Add(cnst); err != nil { + if err := AddConstraint(&rule.LabelConstraints, cnst); err != nil { return nil, fmt.Errorf("%w: LearnerConstraints conflicts with Constraints", err) } } @@ -194,7 +186,7 @@ func NewBundleFromSugarOptions(options *model.PlacementSettings) (*Bundle, error } schedule := options.Schedule - var rules []*Rule + var rules []*pd.Rule locationLabels, err := newLocationLabelsFromSurvivalPreferences(options.SurvivalPreferences) if err != nil { @@ -203,7 +195,7 @@ func NewBundleFromSugarOptions(options *model.PlacementSettings) (*Bundle, error // in case empty primaryRegion and regions, just return an empty bundle if primaryRegion == "" && len(regions) == 0 { - rules = append(rules, NewRule(Voter, followers+1, NewConstraintsDirect())) + rules = append(rules, NewRule(pd.Voter, followers+1, NewConstraintsDirect())) for _, rule := range rules { rule.LocationLabels = locationLabels } @@ -230,17 +222,17 @@ func NewBundleFromSugarOptions(options *model.PlacementSettings) (*Bundle, error return nil, fmt.Errorf("%w: unsupported schedule %s", ErrInvalidPlacementOptions, schedule) } - rules = append(rules, NewRule(Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", In, primaryRegion)))) + rules = append(rules, NewRule(pd.Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, primaryRegion)))) if primaryCount > 1 { - rules = append(rules, NewRule(Voter, primaryCount-1, NewConstraintsDirect(NewConstraintDirect("region", In, primaryRegion)))) + rules = append(rules, NewRule(pd.Voter, primaryCount-1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, primaryRegion)))) } if cnt := followers + 1 - primaryCount; cnt > 0 { // delete primary from regions regions = regions[:primaryIndex+copy(regions[primaryIndex:], regions[primaryIndex+1:])] if len(regions) > 0 { - rules = append(rules, NewRule(Voter, cnt, NewConstraintsDirect(NewConstraintDirect("region", In, regions...)))) + rules = append(rules, NewRule(pd.Voter, cnt, NewConstraintsDirect(NewConstraintDirect("region", pd.In, regions...)))) } else { - rules = append(rules, NewRule(Voter, cnt, NewConstraintsDirect())) + rules = append(rules, NewRule(pd.Voter, cnt, NewConstraintsDirect())) } } @@ -332,8 +324,8 @@ func (b *Bundle) Tidy() error { // refer to tidb#22065. // add -engine=tiflash to every rule to avoid schedules to tiflash instances. // placement rules in SQL is not compatible with `set tiflash replica` yet - err := rule.Constraints.Add(Constraint{ - Op: NotIn, + err := AddConstraint(&rule.LabelConstraints, pd.LabelConstraint{ + Op: pd.NotIn, Key: EngineLabelKey, Values: []string{EngineLabelTiFlash}, }) @@ -348,10 +340,10 @@ func (b *Bundle) Tidy() error { groups := make(map[string]*constraintsGroup) finalRules := tempRules[:0] for _, rule := range tempRules { - key := rule.Constraints.FingerPrint() + key := ConstraintsFingerPrint(&rule.LabelConstraints) existing, ok := groups[key] if !ok { - groups[key] = &constraintsGroup{rules: []*Rule{rule}} + groups[key] = &constraintsGroup{rules: []*pd.Rule{rule}} continue } existing.rules = append(existing.rules, rule) @@ -375,7 +367,7 @@ func (b *Bundle) Tidy() error { // constraintsGroup is a group of rules with the same constraints. type constraintsGroup struct { - rules []*Rule + rules []*pd.Rule // canBecameLeader means the group has leader/voter role, // it's valid if it has leader. canBecameLeader bool @@ -411,16 +403,16 @@ func transformableLeaderConstraint(groups map[string]*constraintsGroup) error { // MergeRulesByRole merges the rules with the same role. func (c *constraintsGroup) MergeRulesByRole() { // Create a map to store rules by role - rulesByRole := make(map[PeerRoleType][]*Rule) + rulesByRole := make(map[pd.PeerRoleType][]*pd.Rule) // Iterate through each rule for _, rule := range c.rules { // Add the rule to the map based on its role rulesByRole[rule.Role] = append(rulesByRole[rule.Role], rule) - if rule.Role == Leader || rule.Role == Voter { + if rule.Role == pd.Leader || rule.Role == pd.Voter { c.canBecameLeader = true } - if rule.Role == Leader { + if rule.Role == pd.Leader { c.isLeaderGroup = true } } @@ -449,11 +441,11 @@ func (c *constraintsGroup) MergeTransformableRoles() { if len(c.rules) == 0 || len(c.rules) == 1 { return } - var mergedRule *Rule - newRules := make([]*Rule, 0, len(c.rules)) + var mergedRule *pd.Rule + newRules := make([]*pd.Rule, 0, len(c.rules)) for _, rule := range c.rules { // Learner is not transformable, it should be promote by PD. - if rule.Role == Learner { + if rule.Role == pd.Learner { newRules = append(newRules, rule) continue } @@ -467,7 +459,7 @@ func (c *constraintsGroup) MergeTransformableRoles() { } } if mergedRule != nil { - mergedRule.Role = Voter + mergedRule.Role = pd.Voter newRules = append(newRules, mergedRule) } c.rules = newRules @@ -491,7 +483,7 @@ func (b *Bundle) RebuildForRange(rangeName string, policyName string) *Bundle { } b.Override = true - newRules := make([]*Rule, 0, len(rule)) + newRules := make([]*pd.Rule, 0, len(rule)) for i, r := range b.Rules { cp := r.Clone() cp.ID = fmt.Sprintf("%s_rule_%d", strings.ToLower(policyName), i) @@ -508,7 +500,7 @@ func (b *Bundle) RebuildForRange(rangeName string, policyName string) *Bundle { // Reset resets the bundle ID and keyrange of all rules. func (b *Bundle) Reset(ruleIndex int, newIDs []int64) *Bundle { // eliminate the redundant rules. - var basicRules []*Rule + var basicRules []*pd.Rule if len(b.Rules) != 0 { // Make priority for rules with RuleIndexTable cause of duplication rules existence with RuleIndexPartition. // If RuleIndexTable doesn't exist, bundle itself is a independent series of rules for a partition. @@ -526,7 +518,7 @@ func (b *Bundle) Reset(ruleIndex int, newIDs []int64) *Bundle { b.ID = GroupID(newIDs[0]) b.Index = ruleIndex b.Override = true - newRules := make([]*Rule, 0, len(basicRules)*len(newIDs)) + newRules := make([]*pd.Rule, 0, len(basicRules)*len(newIDs)) for i, newID := range newIDs { // rule.id should be distinguished with each other, otherwise it will be de-duplicated in pd http api. var ruleID string @@ -566,7 +558,7 @@ func (b *Bundle) Clone() *Bundle { newBundle := &Bundle{} *newBundle = *b if len(b.Rules) > 0 { - newBundle.Rules = make([]*Rule, 0, len(b.Rules)) + newBundle.Rules = make([]*pd.Rule, 0, len(b.Rules)) for i := range b.Rules { newBundle.Rules = append(newBundle.Rules, b.Rules[i].Clone()) } @@ -595,10 +587,10 @@ func (b *Bundle) ObjectID() (int64, error) { return id, nil } -func isValidLeaderRule(rule *Rule, dcLabelKey string) bool { - if rule.Role == Leader && rule.Count == 1 { - for _, con := range rule.Constraints { - if con.Op == In && con.Key == dcLabelKey && len(con.Values) == 1 { +func isValidLeaderRule(rule *pd.Rule, dcLabelKey string) bool { + if rule.Role == pd.Leader && rule.Count == 1 { + for _, con := range rule.LabelConstraints { + if con.Op == pd.In && con.Key == dcLabelKey && len(con.Values) == 1 { return true } } @@ -610,7 +602,7 @@ func isValidLeaderRule(rule *Rule, dcLabelKey string) bool { func (b *Bundle) GetLeaderDC(dcLabelKey string) (string, bool) { for _, rule := range b.Rules { if isValidLeaderRule(rule, dcLabelKey) { - return rule.Constraints[0].Values[0], true + return rule.LabelConstraints[0].Values[0], true } } return "", false diff --git a/pkg/ddl/placement/bundle_test.go b/pkg/ddl/placement/bundle_test.go index c1b7c067c774b..0f75bf50fd69f 100644 --- a/pkg/ddl/placement/bundle_test.go +++ b/pkg/ddl/placement/bundle_test.go @@ -25,6 +25,7 @@ import ( "github.com/pingcap/tidb/pkg/tablecodec" "github.com/pingcap/tidb/pkg/util/codec" "github.com/stretchr/testify/require" + pd "github.com/tikv/pd/client/http" ) func TestEmpty(t *testing.T) { @@ -37,7 +38,7 @@ func TestEmpty(t *testing.T) { bundle = &Bundle{ID: GroupID(1), Override: true} require.False(t, bundle.IsEmpty()) - bundle = &Bundle{ID: GroupID(1), Rules: []*Rule{{ID: "434"}}} + bundle = &Bundle{ID: GroupID(1), Rules: []*pd.Rule{{ID: "434"}}} require.False(t, bundle.IsEmpty()) bundle = &Bundle{ID: GroupID(1), Index: 1, Override: true} @@ -45,14 +46,14 @@ func TestEmpty(t *testing.T) { } func TestCloneBundle(t *testing.T) { - bundle := &Bundle{ID: GroupID(1), Rules: []*Rule{{ID: "434"}}} + bundle := &Bundle{ID: GroupID(1), Rules: []*pd.Rule{{ID: "434"}}} newBundle := bundle.Clone() newBundle.ID = GroupID(2) - newBundle.Rules[0] = &Rule{ID: "121"} + newBundle.Rules[0] = &pd.Rule{ID: "121"} - require.Equal(t, &Bundle{ID: GroupID(1), Rules: []*Rule{{ID: "434"}}}, bundle) - require.Equal(t, &Bundle{ID: GroupID(2), Rules: []*Rule{{ID: "121"}}}, newBundle) + require.Equal(t, &Bundle{ID: GroupID(1), Rules: []*pd.Rule{{ID: "434"}}}, bundle) + require.Equal(t, &Bundle{ID: GroupID(2), Rules: []*pd.Rule{{ID: "121"}}}, newBundle) } func TestObjectID(t *testing.T) { @@ -92,14 +93,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "only leader", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "12", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"bj"}, }, }, @@ -113,14 +114,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "no leader", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "12", - Role: Voter, - Constraints: Constraints{ + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"bj"}, }, }, @@ -134,14 +135,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "voter and leader", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "11", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"sh"}, }, }, @@ -149,11 +150,11 @@ func TestGetLeaderDCByBundle(t *testing.T) { }, { ID: "12", - Role: Voter, - Constraints: Constraints{ + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"bj"}, }, }, @@ -167,14 +168,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "wrong label key", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "11", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "fake", - Op: In, + Op: pd.In, Values: []string{"sh"}, }, }, @@ -188,14 +189,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "wrong operator", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "11", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: NotIn, + Op: pd.NotIn, Values: []string{"sh"}, }, }, @@ -209,14 +210,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "leader have multi values", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "11", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"sh", "bj"}, }, }, @@ -230,14 +231,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "irrelvant rules", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "15", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: EngineLabelKey, - Op: NotIn, + Op: pd.NotIn, Values: []string{EngineLabelTiFlash}, }, }, @@ -245,11 +246,11 @@ func TestGetLeaderDCByBundle(t *testing.T) { }, { ID: "14", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "disk", - Op: NotIn, + Op: pd.NotIn, Values: []string{"ssd", "hdd"}, }, }, @@ -257,11 +258,11 @@ func TestGetLeaderDCByBundle(t *testing.T) { }, { ID: "13", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"bj"}, }, }, @@ -275,14 +276,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "multi leaders 1", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "16", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"sh"}, }, }, @@ -296,14 +297,14 @@ func TestGetLeaderDCByBundle(t *testing.T) { name: "multi leaders 2", bundle: &Bundle{ ID: GroupID(1), - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "17", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"sh"}, }, }, @@ -311,11 +312,11 @@ func TestGetLeaderDCByBundle(t *testing.T) { }, { ID: "18", - Role: Leader, - Constraints: Constraints{ + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ { Key: "zone", - Op: In, + Op: pd.In, Values: []string{"bj"}, }, }, @@ -342,13 +343,13 @@ func TestString(t *testing.T) { ID: GroupID(1), } - rules1, err := newRules(Voter, 3, `["+zone=sh", "+zone=sh"]`) + rules1, err := newRules(pd.Voter, 3, `["+zone=sh", "+zone=sh"]`) require.NoError(t, err) - rules2, err := newRules(Voter, 4, `["-zone=sh", "+zone=bj"]`) + rules2, err := newRules(pd.Voter, 4, `["-zone=sh", "+zone=bj"]`) require.NoError(t, err) bundle.Rules = append(rules1, rules2...) - require.Equal(t, "{\"group_id\":\"TiDB_DDL_1\",\"group_index\":0,\"group_override\":false,\"rules\":[{\"group_id\":\"\",\"id\":\"\",\"start_key\":\"\",\"end_key\":\"\",\"role\":\"voter\",\"count\":3,\"label_constraints\":[{\"key\":\"zone\",\"op\":\"in\",\"values\":[\"sh\"]}]},{\"group_id\":\"\",\"id\":\"\",\"start_key\":\"\",\"end_key\":\"\",\"role\":\"voter\",\"count\":4,\"label_constraints\":[{\"key\":\"zone\",\"op\":\"notIn\",\"values\":[\"sh\"]},{\"key\":\"zone\",\"op\":\"in\",\"values\":[\"bj\"]}]}]}", bundle.String()) + require.Equal(t, "{\"group_id\":\"TiDB_DDL_1\",\"group_index\":0,\"group_override\":false,\"rules\":[{\"group_id\":\"\",\"id\":\"\",\"start_key\":\"\",\"end_key\":\"\",\"role\":\"voter\",\"is_witness\":false,\"count\":3,\"label_constraints\":[{\"key\":\"zone\",\"op\":\"in\",\"values\":[\"sh\"]}]},{\"group_id\":\"\",\"id\":\"\",\"start_key\":\"\",\"end_key\":\"\",\"role\":\"voter\",\"is_witness\":false,\"count\":4,\"label_constraints\":[{\"key\":\"zone\",\"op\":\"notIn\",\"values\":[\"sh\"]},{\"key\":\"zone\",\"op\":\"in\",\"values\":[\"bj\"]}]}]}", bundle.String()) require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/pkg/ddl/placement/MockMarshalFailure", `return(true)`)) defer func() { @@ -372,7 +373,7 @@ func TestNewBundleFromOptions(t *testing.T) { type TestCase struct { name string input *model.PlacementSettings - output []*Rule + output []*pd.Rule err error } var tests []TestCase @@ -380,8 +381,8 @@ func TestNewBundleFromOptions(t *testing.T) { tests = append(tests, TestCase{ name: "empty 1", input: &model.PlacementSettings{}, - output: []*Rule{ - NewRule(Voter, 3, NewConstraintsDirect()), + output: []*pd.Rule{ + NewRule(pd.Voter, 3, NewConstraintsDirect()), }, }) @@ -405,12 +406,12 @@ func TestNewBundleFromOptions(t *testing.T) { PrimaryRegion: "us", Regions: "us", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), }, }) @@ -422,14 +423,14 @@ func TestNewBundleFromOptions(t *testing.T) { Regions: "us", Schedule: "majority_in_primary", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + NewRule(pd.Voter, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 1, NewConstraintsDirect()), + NewRule(pd.Voter, 1, NewConstraintsDirect()), }, }) @@ -440,12 +441,12 @@ func TestNewBundleFromOptions(t *testing.T) { Regions: "bj,sh,us", Followers: 1, }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "bj", "sh"), + NewRule(pd.Voter, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "bj", "sh"), )), }, }) @@ -456,8 +457,8 @@ func TestNewBundleFromOptions(t *testing.T) { Followers: 2, Schedule: "even", }, - output: []*Rule{ - NewRule(Voter, 3, NewConstraintsDirect()), + output: []*pd.Rule{ + NewRule(pd.Voter, 3, NewConstraintsDirect()), }, }) @@ -467,8 +468,8 @@ func TestNewBundleFromOptions(t *testing.T) { Followers: 2, Schedule: "majority_in_primary", }, - output: []*Rule{ - NewRule(Voter, 3, NewConstraintsDirect()), + output: []*pd.Rule{ + NewRule(pd.Voter, 3, NewConstraintsDirect()), }, }) @@ -516,15 +517,15 @@ func TestNewBundleFromOptions(t *testing.T) { Regions: "sh,us", Followers: 5, }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 3, NewConstraintsDirect( - NewConstraintDirect("region", In, "sh"), + NewRule(pd.Voter, 3, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "sh"), )), }, }) @@ -540,15 +541,15 @@ func TestNewBundleFromOptions(t *testing.T) { Followers: 4, Schedule: "majority_in_primary", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "sh"), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "sh"), )), - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("region", In, "sh"), + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "sh"), )), - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("region", In, "bj"), + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "bj"), )), }, }) @@ -558,12 +559,12 @@ func TestNewBundleFromOptions(t *testing.T) { input: &model.PlacementSettings{ Constraints: "[+region=us]", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), }, }) @@ -575,15 +576,15 @@ func TestNewBundleFromOptions(t *testing.T) { Followers: 2, Learners: 2, }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), - NewRule(Learner, 2, NewConstraintsDirect( - NewConstraintDirect("region", In, "us"), + NewRule(pd.Learner, 2, NewConstraintsDirect( + NewConstraintDirect("region", pd.In, "us"), )), }, }) @@ -593,9 +594,9 @@ func TestNewBundleFromOptions(t *testing.T) { input: &model.PlacementSettings{ LeaderConstraints: "[+region=as]", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", In, "as"))), - NewRule(Voter, 2, NewConstraintsDirect()), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "as"))), + NewRule(pd.Voter, 2, NewConstraintsDirect()), }, }) @@ -605,9 +606,9 @@ func TestNewBundleFromOptions(t *testing.T) { LeaderConstraints: "[+region=as]", Followers: 4, }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", In, "as"))), - NewRule(Voter, 4, NewConstraintsDirect()), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "as"))), + NewRule(pd.Voter, 4, NewConstraintsDirect()), }, }) tests = append(tests, TestCase{ @@ -616,9 +617,9 @@ func TestNewBundleFromOptions(t *testing.T) { LeaderConstraints: "[+region=as]", FollowerConstraints: `{"+region=us": 2}`, }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", In, "as"))), - NewRule(Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", In, "us"))), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "as"))), + NewRule(pd.Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us"))), }, }) @@ -628,9 +629,9 @@ func TestNewBundleFromOptions(t *testing.T) { LeaderConstraints: "[+region=as]", FollowerConstraints: "[-region=us]", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", In, "as"))), - NewRule(Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", NotIn, "us"))), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "as"))), + NewRule(pd.Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", pd.NotIn, "us"))), }, }) @@ -649,9 +650,9 @@ func TestNewBundleFromOptions(t *testing.T) { Followers: 2, FollowerConstraints: "[+region=bj]", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect()), - NewRule(Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", In, "bj"))), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect()), + NewRule(pd.Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "bj"))), }, }) @@ -732,9 +733,9 @@ func TestNewBundleFromOptions(t *testing.T) { input: &model.PlacementSettings{ FollowerConstraints: "{+disk=ssd: 1}", }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect()), - NewRule(Voter, 1, NewConstraintsDirect(NewConstraintDirect("disk", In, "ssd"))), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect()), + NewRule(pd.Voter, 1, NewConstraintsDirect(NewConstraintDirect("disk", pd.In, "ssd"))), }, }) @@ -752,10 +753,10 @@ func TestNewBundleFromOptions(t *testing.T) { input: &model.PlacementSettings{ LearnerConstraints: `{"+region=us": 2}`, }, - output: []*Rule{ - NewRule(Leader, 1, NewConstraintsDirect()), - NewRule(Voter, 2, NewConstraintsDirect()), - NewRule(Learner, 2, NewConstraintsDirect(NewConstraintDirect("region", In, "us"))), + output: []*pd.Rule{ + NewRule(pd.Leader, 1, NewConstraintsDirect()), + NewRule(pd.Voter, 2, NewConstraintsDirect()), + NewRule(pd.Learner, 2, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us"))), }, }) @@ -773,8 +774,8 @@ func TestNewBundleFromOptions(t *testing.T) { input: &model.PlacementSettings{ Constraints: `{"+region=us": 3}`, }, - output: []*Rule{ - NewRule(Voter, 3, NewConstraintsDirect(NewConstraintDirect("region", In, "us"))), + output: []*pd.Rule{ + NewRule(pd.Voter, 3, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us"))), }, }) @@ -783,10 +784,10 @@ func TestNewBundleFromOptions(t *testing.T) { input: &model.PlacementSettings{ Constraints: `{ "+region=us-east-1":2, "+region=us-east-2": 2, "+region=us-west-1": 1}`, }, - output: []*Rule{ - NewRule(Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", In, "us-east-1"))), - NewRule(Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", In, "us-east-2"))), - NewRule(Voter, 1, NewConstraintsDirect(NewConstraintDirect("region", In, "us-west-1"))), + output: []*pd.Rule{ + NewRule(pd.Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us-east-1"))), + NewRule(pd.Voter, 2, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us-east-2"))), + NewRule(pd.Voter, 1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us-west-1"))), }, }) @@ -796,9 +797,9 @@ func TestNewBundleFromOptions(t *testing.T) { Constraints: `{"+region=us-east": 3}`, LearnerConstraints: `{"+region=us-west": 1}`, }, - output: []*Rule{ - NewRule(Voter, 3, NewConstraintsDirect(NewConstraintDirect("region", In, "us-east"))), - NewRule(Learner, 1, NewConstraintsDirect(NewConstraintDirect("region", In, "us-west"))), + output: []*pd.Rule{ + NewRule(pd.Voter, 3, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us-east"))), + NewRule(pd.Learner, 1, NewConstraintsDirect(NewConstraintDirect("region", pd.In, "us-west"))), }, }) @@ -819,7 +820,7 @@ func TestResetBundleWithSingleRule(t *testing.T) { ID: GroupID(1), } - rules, err := newRules(Voter, 3, `["+zone=sh", "+zone=sh"]`) + rules, err := newRules(pd.Voter, 3, `["+zone=sh", "+zone=sh"]`) require.NoError(t, err) bundle.Rules = rules @@ -936,15 +937,15 @@ func TestTidy(t *testing.T) { ID: GroupID(1), } - rules0, err := newRules(Voter, 1, `["+zone=sh", "+zone=sh"]`) + rules0, err := newRules(pd.Voter, 1, `["+zone=sh", "+zone=sh"]`) require.NoError(t, err) require.Len(t, rules0, 1) rules0[0].Count = 0 // test prune useless rules - rules1, err := newRules(Voter, 4, `["-zone=sh", "+zone=bj"]`) + rules1, err := newRules(pd.Voter, 4, `["-zone=sh", "+zone=bj"]`) require.NoError(t, err) require.Len(t, rules1, 1) - rules2, err := newRules(Voter, 0, `{"-zone=sh,+zone=bj": 4}}`) + rules2, err := newRules(pd.Voter, 0, `{"-zone=sh,+zone=bj": 4}}`) require.NoError(t, err) bundle.Rules = append(bundle.Rules, rules0...) bundle.Rules = append(bundle.Rules, rules1...) @@ -955,23 +956,23 @@ func TestTidy(t *testing.T) { require.NoError(t, err) require.Len(t, bundle.Rules, 1) require.Equal(t, "0", bundle.Rules[0].ID) - require.Len(t, bundle.Rules[0].Constraints, 3) - require.Equal(t, Constraint{ - Op: NotIn, + require.Len(t, bundle.Rules[0].LabelConstraints, 3) + require.Equal(t, pd.LabelConstraint{ + Op: pd.NotIn, Key: EngineLabelKey, Values: []string{EngineLabelTiFlash}, - }, bundle.Rules[0].Constraints[2]) + }, bundle.Rules[0].LabelConstraints[2]) // merge - rules3, err := newRules(Follower, 4, "") + rules3, err := newRules(pd.Follower, 4, "") require.NoError(t, err) require.Len(t, rules3, 1) - rules4, err := newRules(Follower, 5, "") + rules4, err := newRules(pd.Follower, 5, "") require.NoError(t, err) require.Len(t, rules4, 1) - rules0[0].Role = Voter + rules0[0].Role = pd.Voter bundle.Rules = append(bundle.Rules, rules0...) bundle.Rules = append(bundle.Rules, rules3...) bundle.Rules = append(bundle.Rules, rules4...) @@ -985,13 +986,13 @@ func TestTidy(t *testing.T) { require.Equal(t, "0", bundle.Rules[0].ID) require.Equal(t, "1", bundle.Rules[1].ID) require.Equal(t, 9, bundle.Rules[1].Count) - require.Equal(t, Constraints{ + require.Equal(t, []pd.LabelConstraint{ { - Op: NotIn, + Op: pd.NotIn, Key: EngineLabelKey, Values: []string{EngineLabelTiFlash}, }, - }, bundle.Rules[1].Constraints) + }, bundle.Rules[1].LabelConstraints) require.Equal(t, []string{"zone", "host"}, bundle.Rules[1].LocationLabels) } err = bundle.Tidy() @@ -1009,8 +1010,8 @@ func TestTidy(t *testing.T) { require.NoError(t, err) require.Equal(t, bundle, bundle2) - bundle.Rules[1].Constraints = append(bundle.Rules[1].Constraints, Constraint{ - Op: In, + bundle.Rules[1].LabelConstraints = append(bundle.Rules[1].LabelConstraints, pd.LabelConstraint{ + Op: pd.In, Key: EngineLabelKey, Values: []string{EngineLabelTiFlash}, }) @@ -1026,40 +1027,40 @@ func TestTidy2(t *testing.T) { { name: "Empty bundle", bundle: Bundle{ - Rules: []*Rule{}, + Rules: []*pd.Rule{}, }, expected: Bundle{ - Rules: []*Rule{}, + Rules: []*pd.Rule{}, }, }, { name: "Rules with empty constraints are merged", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { - ID: "1", - Role: Leader, - Count: 1, - Constraints: Constraints{}, - LocationLabels: []string{"region"}, + ID: "1", + Role: pd.Leader, + Count: 1, + LabelConstraints: []pd.LabelConstraint{}, + LocationLabels: []string{"region"}, }, { - ID: "2", - Role: Voter, - Count: 2, - Constraints: Constraints{}, - LocationLabels: []string{"region"}, + ID: "2", + Role: pd.Voter, + Count: 2, + LabelConstraints: []pd.LabelConstraint{}, + LocationLabels: []string{"region"}, }, }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { - ID: "0", - Role: Voter, - Count: 3, - Constraints: Constraints{}, - LocationLabels: []string{"region"}, + ID: "0", + Role: pd.Voter, + Count: 3, + LabelConstraints: []pd.LabelConstraint{}, + LocationLabels: []string{"region"}, }, }, }, @@ -1067,21 +1068,21 @@ func TestTidy2(t *testing.T) { { name: "Rules with same constraints are merged, Leader + Follower", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "1", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 2, LocationLabels: []string{"region"}, @@ -1089,12 +1090,12 @@ func TestTidy2(t *testing.T) { }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "0", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 3, LocationLabels: []string{"region"}, @@ -1105,21 +1106,21 @@ func TestTidy2(t *testing.T) { { name: "Rules with same constraints are merged, Leader + Voter", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "1", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 2, LocationLabels: []string{"region"}, @@ -1127,12 +1128,12 @@ func TestTidy2(t *testing.T) { }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "0", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 3, LocationLabels: []string{"region"}, @@ -1143,30 +1144,30 @@ func TestTidy2(t *testing.T) { { name: "Rules with same constraints and role are merged, Leader + Follower + Voter", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "1", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "3", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, @@ -1174,12 +1175,12 @@ func TestTidy2(t *testing.T) { }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "0", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 3, LocationLabels: []string{"region"}, @@ -1190,39 +1191,39 @@ func TestTidy2(t *testing.T) { { name: "Rules with same constraints and role are merged, Leader + Follower + Voter + Learner", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "1", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "3", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "4", - Role: Learner, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Learner, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 2, LocationLabels: []string{"region"}, @@ -1230,21 +1231,21 @@ func TestTidy2(t *testing.T) { }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "0", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 3, LocationLabels: []string{"region"}, }, { ID: "3", - Role: Learner, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Learner, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 2, LocationLabels: []string{"region"}, @@ -1255,39 +1256,39 @@ func TestTidy2(t *testing.T) { { name: "Rules with same constraints and role are merged, Leader + Follower + Learner | Follower", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "1", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "3", - Role: Learner, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Learner, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "4", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"2"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"2"}}, }, Count: 1, LocationLabels: []string{"region"}, @@ -1295,30 +1296,30 @@ func TestTidy2(t *testing.T) { }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "0", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 2, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Learner, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Learner, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "3", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"2"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"2"}}, }, Count: 1, LocationLabels: []string{"region"}, @@ -1329,39 +1330,39 @@ func TestTidy2(t *testing.T) { { name: "Rules with same constraints and role are merged, Leader + Follower + Learner | Voter", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "1", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "3", - Role: Learner, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Learner, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "4", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"2"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"2"}}, }, Count: 1, LocationLabels: []string{"region"}, @@ -1369,39 +1370,39 @@ func TestTidy2(t *testing.T) { }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "0", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "1", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Learner, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Learner, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "3", - Role: Voter, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"2"}}, + Role: pd.Voter, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"2"}}, }, Count: 1, LocationLabels: []string{"region"}, @@ -1412,21 +1413,21 @@ func TestTidy2(t *testing.T) { { name: "Rules with different constraints are kept separate", bundle: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "1", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "2", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"2"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"2"}}, }, Count: 1, LocationLabels: []string{"region"}, @@ -1434,21 +1435,21 @@ func TestTidy2(t *testing.T) { }, }, expected: Bundle{ - Rules: []*Rule{ + Rules: []*pd.Rule{ { ID: "0", - Role: Leader, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"1"}}, + Role: pd.Leader, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"1"}}, }, Count: 1, LocationLabels: []string{"region"}, }, { ID: "1", - Role: Follower, - Constraints: Constraints{ - {Op: In, Key: "rack", Values: []string{"2"}}, + Role: pd.Follower, + LabelConstraints: []pd.LabelConstraint{ + {Op: pd.In, Key: "rack", Values: []string{"2"}}, }, Count: 1, LocationLabels: []string{"region"}, @@ -1468,8 +1469,8 @@ func TestTidy2(t *testing.T) { for i, rule := range tt.bundle.Rules { expectedRule := tt.expected.Rules[i] // Tiflash is always excluded from the constraints. - expectedRule.Constraints.Add(Constraint{ - Op: NotIn, + AddConstraint(&expectedRule.LabelConstraints, pd.LabelConstraint{ + Op: pd.NotIn, Key: EngineLabelKey, Values: []string{EngineLabelTiFlash}, }) diff --git a/pkg/ddl/placement/constraint.go b/pkg/ddl/placement/constraint.go index 49970eb31570d..a7463cd897f56 100644 --- a/pkg/ddl/placement/constraint.go +++ b/pkg/ddl/placement/constraint.go @@ -17,45 +17,24 @@ package placement import ( "fmt" "strings" -) - -// ConstraintOp defines how a Constraint matches a store. -type ConstraintOp string -const ( - // In restricts the store label value should in the value list. - // If label does not exist, `in` is always false. - In ConstraintOp = "in" - // NotIn restricts the store label value should not in the value list. - // If label does not exist, `notIn` is always true. - NotIn ConstraintOp = "notIn" - // Exists restricts the store should have the label. - Exists ConstraintOp = "exists" - // NotExists restricts the store should not have the label. - NotExists ConstraintOp = "notExists" + pd "github.com/tikv/pd/client/http" ) -// Constraint is used to filter store when trying to place peer of a region. -type Constraint struct { - Key string `json:"key,omitempty"` - Op ConstraintOp `json:"op,omitempty"` - Values []string `json:"values,omitempty"` -} - // NewConstraint will create a Constraint from a string. -func NewConstraint(label string) (Constraint, error) { - r := Constraint{} +func NewConstraint(label string) (pd.LabelConstraint, error) { + r := pd.LabelConstraint{} if len(label) < 4 { return r, fmt.Errorf("%w: %s", ErrInvalidConstraintFormat, label) } - var op ConstraintOp + var op pd.LabelConstraintOp switch label[0] { case '+': - op = In + op = pd.In case '-': - op = NotIn + op = pd.NotIn default: return r, fmt.Errorf("%w: %s", ErrInvalidConstraintFormat, label) } @@ -75,7 +54,7 @@ func NewConstraint(label string) (Constraint, error) { return r, fmt.Errorf("%w: %s", ErrInvalidConstraintFormat, label) } - if op == In && key == EngineLabelKey && strings.ToLower(val) == EngineLabelTiFlash { + if op == pd.In && key == EngineLabelKey && strings.ToLower(val) == EngineLabelTiFlash { return r, fmt.Errorf("%w: %s", ErrUnsupportedConstraint, label) } @@ -86,24 +65,24 @@ func NewConstraint(label string) (Constraint, error) { } // NewConstraintDirect will create a Constraint from argument directly. -func NewConstraintDirect(key string, op ConstraintOp, val ...string) Constraint { - return Constraint{ +func NewConstraintDirect(key string, op pd.LabelConstraintOp, val ...string) pd.LabelConstraint { + return pd.LabelConstraint{ Key: key, Op: op, Values: val, } } -// Restore converts a Constraint to a string. -func (c *Constraint) Restore() (string, error) { +// RestoreConstraint converts a Constraint to a string. +func RestoreConstraint(c *pd.LabelConstraint) (string, error) { var sb strings.Builder if len(c.Values) != 1 { return "", fmt.Errorf("%w: constraint should have exactly one label value, got %v", ErrInvalidConstraintFormat, c.Values) } switch c.Op { - case In: + case pd.In: sb.WriteString("+") - case NotIn: + case pd.NotIn: sb.WriteString("-") default: return "", fmt.Errorf("%w: disallowed operation '%s'", ErrInvalidConstraintFormat, c.Op) @@ -126,9 +105,9 @@ const ( ConstraintDuplicated ) -// CompatibleWith will check if two constraints are compatible. +// ConstraintCompatibleWith will check if two constraints are compatible. // Return (compatible, duplicated). -func (c *Constraint) CompatibleWith(o *Constraint) ConstraintCompatibility { +func ConstraintCompatibleWith(c *pd.LabelConstraint, o *pd.LabelConstraint) ConstraintCompatibility { sameKey := c.Key == o.Key if !sameKey { return ConstraintCompatible @@ -148,7 +127,7 @@ func (c *Constraint) CompatibleWith(o *Constraint) ConstraintCompatibility { // 3. can not match multiple instances: +dc=sh, +dc=bj if sameOp && sameVal { return ConstraintDuplicated - } else if (!sameOp && sameVal) || (sameOp && !sameVal && c.Op == In) { + } else if (!sameOp && sameVal) || (sameOp && !sameVal && c.Op == pd.In) { return ConstraintIncompatible } diff --git a/pkg/ddl/placement/constraint_test.go b/pkg/ddl/placement/constraint_test.go index 739d7bf6b5ba6..577cbf0d0f837 100644 --- a/pkg/ddl/placement/constraint_test.go +++ b/pkg/ddl/placement/constraint_test.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/stretchr/testify/require" + pd "github.com/tikv/pd/client/http" ) func TestNewFromYaml(t *testing.T) { @@ -32,34 +33,34 @@ func TestNewConstraint(t *testing.T) { type TestCase struct { name string input string - label Constraint + label pd.LabelConstraint err error } tests := []TestCase{ { name: "normal", input: "+zone=bj", - label: Constraint{ + label: pd.LabelConstraint{ Key: "zone", - Op: In, + Op: pd.In, Values: []string{"bj"}, }, }, { name: "normal with spaces", input: "- dc = sh ", - label: Constraint{ + label: pd.LabelConstraint{ Key: "dc", - Op: NotIn, + Op: pd.NotIn, Values: []string{"sh"}, }, }, { name: "not tiflash", input: "-engine = tiflash ", - label: Constraint{ + label: pd.LabelConstraint{ Key: "engine", - Op: NotIn, + Op: pd.NotIn, Values: []string{"tiflash"}, }, }, @@ -126,7 +127,7 @@ func TestNewConstraint(t *testing.T) { func TestRestoreConstraint(t *testing.T) { type TestCase struct { name string - input Constraint + input pd.LabelConstraint output string err error } @@ -158,8 +159,8 @@ func TestRestoreConstraint(t *testing.T) { tests = append(tests, TestCase{ name: "no values", - input: Constraint{ - Op: In, + input: pd.LabelConstraint{ + Op: pd.In, Key: "dc", Values: []string{}, }, @@ -168,8 +169,8 @@ func TestRestoreConstraint(t *testing.T) { tests = append(tests, TestCase{ name: "multiple values", - input: Constraint{ - Op: In, + input: pd.LabelConstraint{ + Op: pd.In, Key: "dc", Values: []string{"dc1", "dc2"}, }, @@ -178,7 +179,7 @@ func TestRestoreConstraint(t *testing.T) { tests = append(tests, TestCase{ name: "invalid op", - input: Constraint{ + input: pd.LabelConstraint{ Op: "[", Key: "dc", Values: []string{}, @@ -187,7 +188,7 @@ func TestRestoreConstraint(t *testing.T) { }) for _, test := range tests { - output, err := test.input.Restore() + output, err := RestoreConstraint(&test.input) comment := fmt.Sprintf("%s: %v", test.name, err) if test.err == nil { require.NoError(t, err, comment) @@ -201,8 +202,8 @@ func TestRestoreConstraint(t *testing.T) { func TestCompatibleWith(t *testing.T) { type TestCase struct { name string - i1 Constraint - i2 Constraint + i1 pd.LabelConstraint + i2 pd.LabelConstraint output ConstraintCompatibility } var tests []TestCase @@ -258,6 +259,6 @@ func TestCompatibleWith(t *testing.T) { }) for _, test := range tests { - require.Equal(t, test.output, test.i1.CompatibleWith(&test.i2), test.name) + require.Equal(t, test.output, ConstraintCompatibleWith(&test.i1, &test.i2), test.name) } } diff --git a/pkg/ddl/placement/constraints.go b/pkg/ddl/placement/constraints.go index a62d2265c36fd..adb830adb034d 100644 --- a/pkg/ddl/placement/constraints.go +++ b/pkg/ddl/placement/constraints.go @@ -23,26 +23,24 @@ import ( "sort" "strings" + pd "github.com/tikv/pd/client/http" "gopkg.in/yaml.v2" ) -// Constraints is a slice of constraints. -type Constraints []Constraint - // NewConstraints will check each labels, and build the Constraints. -func NewConstraints(labels []string) (Constraints, error) { +func NewConstraints(labels []string) ([]pd.LabelConstraint, error) { if len(labels) == 0 { return nil, nil } - constraints := make(Constraints, 0, len(labels)) + constraints := make([]pd.LabelConstraint, 0, len(labels)) for _, str := range labels { label, err := NewConstraint(strings.TrimSpace(str)) if err != nil { return constraints, err } - err = constraints.Add(label) + err = AddConstraint(&constraints, label) if err != nil { return constraints, err } @@ -52,7 +50,7 @@ func NewConstraints(labels []string) (Constraints, error) { // preCheckDictConstraintStr will check the label string, and return the new labels and role. // role maybe be override by the label string, eg `#evict-leader`. -func preCheckDictConstraintStr(labelStr string, role PeerRoleType) ([]string, PeerRoleType, error) { +func preCheckDictConstraintStr(labelStr string, role pd.PeerRoleType) ([]string, pd.PeerRoleType, error) { innerLabels := strings.Split(labelStr, ",") overrideRole := role newLabels := make([]string, 0, len(innerLabels)) @@ -60,8 +58,8 @@ func preCheckDictConstraintStr(labelStr string, role PeerRoleType) ([]string, Pe if strings.HasPrefix(str, attributePrefix) { switch str[1:] { case attributeEvictLeader: - if role == Voter { - overrideRole = Follower + if role == pd.Voter { + overrideRole = pd.Follower } default: return newLabels, overrideRole, fmt.Errorf("%w: unsupported attribute '%s'", ErrUnsupportedConstraint, str) @@ -75,7 +73,7 @@ func preCheckDictConstraintStr(labelStr string, role PeerRoleType) ([]string, Pe // NewConstraintsFromYaml will transform parse the raw 'array' constraints and call NewConstraints. // Refer to https://github.com/pingcap/tidb/blob/master/docs/design/2020-06-24-placement-rules-in-sql.md. -func NewConstraintsFromYaml(c []byte) (Constraints, error) { +func NewConstraintsFromYaml(c []byte) ([]pd.LabelConstraint, error) { constraints := []string{} err := yaml.UnmarshalStrict(c, &constraints) if err != nil { @@ -85,19 +83,19 @@ func NewConstraintsFromYaml(c []byte) (Constraints, error) { } // NewConstraintsDirect is a helper for creating new constraints from individual constraint. -func NewConstraintsDirect(c ...Constraint) Constraints { +func NewConstraintsDirect(c ...pd.LabelConstraint) []pd.LabelConstraint { return c } -// Restore converts label constraints to a string. -func (constraints *Constraints) Restore() (string, error) { +// RestoreConstraints converts label constraints to a string. +func RestoreConstraints(constraints *[]pd.LabelConstraint) (string, error) { var sb strings.Builder for i, constraint := range *constraints { if i > 0 { sb.WriteByte(',') } sb.WriteByte('"') - conStr, err := constraint.Restore() + conStr, err := RestoreConstraint(&constraint) if err != nil { return "", err } @@ -107,14 +105,14 @@ func (constraints *Constraints) Restore() (string, error) { return sb.String(), nil } -// Add will add a new label constraint, with validation of all constraints. +// AddConstraint will add a new label constraint, with validation of all constraints. // Note that Add does not validate one single constraint. -func (constraints *Constraints) Add(label Constraint) error { +func AddConstraint(constraints *[]pd.LabelConstraint, label pd.LabelConstraint) error { pass := true for i := range *constraints { cnst := (*constraints)[i] - res := label.CompatibleWith(&cnst) + res := ConstraintCompatibleWith(&label, &cnst) if res == ConstraintCompatible { continue } @@ -122,11 +120,11 @@ func (constraints *Constraints) Add(label Constraint) error { pass = false continue } - s1, err := label.Restore() + s1, err := RestoreConstraint(&label) if err != nil { s1 = err.Error() } - s2, err := cnst.Restore() + s2, err := RestoreConstraint(&cnst) if err != nil { s2 = err.Error() } @@ -139,11 +137,11 @@ func (constraints *Constraints) Add(label Constraint) error { return nil } -// FingerPrint returns a unique string for the constraints. -func (constraints *Constraints) FingerPrint() string { - copied := make(Constraints, len(*constraints)) +// ConstraintsFingerPrint returns a unique string for the constraints. +func ConstraintsFingerPrint(constraints *[]pd.LabelConstraint) string { + copied := make([]pd.LabelConstraint, len(*constraints)) copy(copied, *constraints) - slices.SortStableFunc(copied, func(i, j Constraint) int { + slices.SortStableFunc(copied, func(i, j pd.LabelConstraint) int { a, b := constraintToString(&i), constraintToString(&j) return cmp.Compare(a, b) }) @@ -161,7 +159,7 @@ func (constraints *Constraints) FingerPrint() string { return hashStr } -func constraintToString(c *Constraint) string { +func constraintToString(c *pd.LabelConstraint) string { // Sort the values in the constraint sortedValues := make([]string, len(c.Values)) copy(sortedValues, c.Values) diff --git a/pkg/ddl/placement/constraints_test.go b/pkg/ddl/placement/constraints_test.go index 17a4b03843255..a8d9899999d2c 100644 --- a/pkg/ddl/placement/constraints_test.go +++ b/pkg/ddl/placement/constraints_test.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/stretchr/testify/require" + pd "github.com/tikv/pd/client/http" ) func TestNewConstraints(t *testing.T) { @@ -38,8 +39,8 @@ func TestNewConstraints(t *testing.T) { func TestAdd(t *testing.T) { type TestCase struct { name string - labels Constraints - label Constraint + labels []pd.LabelConstraint + label pd.LabelConstraint err error } var tests []TestCase @@ -66,8 +67,8 @@ func TestAdd(t *testing.T) { tests = append(tests, TestCase{ "duplicated constraints should not stop conflicting constraints check", - append(labels, Constraint{ - Op: NotIn, + append(labels, pd.LabelConstraint{ + Op: pd.NotIn, Key: "zone", Values: []string{"sh"}, }), label, @@ -78,19 +79,19 @@ func TestAdd(t *testing.T) { require.NoError(t, err) tests = append(tests, TestCase{ "invalid label in operand", - labels, Constraint{Op: "["}, + labels, pd.LabelConstraint{Op: "["}, nil, }) tests = append(tests, TestCase{ "invalid label in operator", - Constraints{{Op: "["}}, label, + []pd.LabelConstraint{{Op: "["}}, label, nil, }) tests = append(tests, TestCase{ "invalid label in both, same key", - Constraints{{Op: "[", Key: "dc"}}, Constraint{Op: "]", Key: "dc"}, + []pd.LabelConstraint{{Op: "[", Key: "dc"}}, pd.LabelConstraint{Op: "]", Key: "dc"}, ErrConflictingConstraints, }) @@ -105,7 +106,7 @@ func TestAdd(t *testing.T) { }) for _, test := range tests { - err := test.labels.Add(test.label) + err := AddConstraint(&test.labels, test.label) comment := fmt.Sprintf("%s: %v", test.name, err) if test.err == nil { require.NoError(t, err, comment) @@ -119,7 +120,7 @@ func TestAdd(t *testing.T) { func TestRestoreConstraints(t *testing.T) { type TestCase struct { name string - input Constraints + input []pd.LabelConstraint output string err error } @@ -127,7 +128,7 @@ func TestRestoreConstraints(t *testing.T) { tests = append(tests, TestCase{ "normal1", - Constraints{}, + []pd.LabelConstraint{}, "", nil, }) @@ -138,14 +139,14 @@ func TestRestoreConstraints(t *testing.T) { require.NoError(t, err) tests = append(tests, TestCase{ "normal2", - Constraints{input1, input2}, + []pd.LabelConstraint{input1, input2}, `"+zone=bj","-zone=sh"`, nil, }) tests = append(tests, TestCase{ "error", - Constraints{{ + []pd.LabelConstraint{{ Op: "[", Key: "dc", Values: []string{"dc1"}, @@ -155,7 +156,7 @@ func TestRestoreConstraints(t *testing.T) { }) for _, test := range tests { - res, err := test.input.Restore() + res, err := RestoreConstraints(&test.input) comment := fmt.Sprintf("%s: %v", test.name, err) if test.err == nil { require.NoError(t, err, comment) diff --git a/pkg/ddl/placement/meta_bundle_test.go b/pkg/ddl/placement/meta_bundle_test.go index 093a3651e7f23..8af316db0d45a 100644 --- a/pkg/ddl/placement/meta_bundle_test.go +++ b/pkg/ddl/placement/meta_bundle_test.go @@ -29,6 +29,7 @@ import ( "github.com/pingcap/tidb/pkg/tablecodec" "github.com/pingcap/tidb/pkg/util/codec" "github.com/stretchr/testify/require" + pd "github.com/tikv/pd/client/http" ) type metaBundleSuite struct { @@ -342,9 +343,9 @@ func (s *metaBundleSuite) checkPartitionBundle(t *testing.T, def model.Partition s.checkTwoJSONObjectEquals(t, expected, got) } -func (s *metaBundleSuite) expectedRules(t *testing.T, ref *model.PolicyRefInfo) []*placement.Rule { +func (s *metaBundleSuite) expectedRules(t *testing.T, ref *model.PolicyRefInfo) []*pd.Rule { if ref == nil { - return []*placement.Rule{} + return []*pd.Rule{} } var policy *model.PolicyInfo diff --git a/pkg/ddl/placement/rule.go b/pkg/ddl/placement/rule.go index c52839c37bb32..5364607a1bb96 100644 --- a/pkg/ddl/placement/rule.go +++ b/pkg/ddl/placement/rule.go @@ -22,23 +22,10 @@ import ( "strings" "github.com/pingcap/tidb/pkg/util/codec" + pd "github.com/tikv/pd/client/http" "gopkg.in/yaml.v2" ) -// PeerRoleType is the expected peer type of the placement rule. -type PeerRoleType string - -const ( - // Voter can either match a leader peer or follower peer. - Voter PeerRoleType = "voter" - // Leader matches a leader. - Leader PeerRoleType = "leader" - // Follower matches a follower. - Follower PeerRoleType = "follower" - // Learner matches a learner. - Learner PeerRoleType = "learner" -) - const ( attributePrefix = "#" // AttributeEvictLeader is used to evict leader from a store. @@ -52,22 +39,10 @@ type RuleGroupConfig struct { Override bool `json:"override"` } -// Rule is the core placement rule struct. Check https://github.com/tikv/pd/blob/master/server/schedule/placement/rule.go. -type Rule struct { - GroupID string `json:"group_id"` - ID string `json:"id"` - Index int `json:"index,omitempty"` - Override bool `json:"override,omitempty"` - StartKeyHex string `json:"start_key"` - EndKeyHex string `json:"end_key"` - Role PeerRoleType `json:"role"` - Count int `json:"count"` - Constraints Constraints `json:"label_constraints,omitempty"` - LocationLabels []string `json:"location_labels,omitempty"` -} - -var _ json.Marshaler = (*TiFlashRule)(nil) -var _ json.Unmarshaler = (*TiFlashRule)(nil) +var ( + _ json.Marshaler = (*TiFlashRule)(nil) + _ json.Unmarshaler = (*TiFlashRule)(nil) +) // TiFlashRule extends Rule with other necessary fields. type TiFlashRule struct { @@ -75,9 +50,9 @@ type TiFlashRule struct { ID string Index int Override bool - Role PeerRoleType + Role pd.PeerRoleType Count int - Constraints Constraints + Constraints []pd.LabelConstraint LocationLabels []string IsolationLevel string StartKey []byte @@ -85,17 +60,17 @@ type TiFlashRule struct { } type tiFlashRule struct { - GroupID string `json:"group_id"` - ID string `json:"id"` - Index int `json:"index,omitempty"` - Override bool `json:"override,omitempty"` - Role PeerRoleType `json:"role"` - Count int `json:"count"` - Constraints Constraints `json:"label_constraints,omitempty"` - LocationLabels []string `json:"location_labels,omitempty"` - IsolationLevel string `json:"isolation_level,omitempty"` - StartKeyHex string `json:"start_key"` - EndKeyHex string `json:"end_key"` + GroupID string `json:"group_id"` + ID string `json:"id"` + Index int `json:"index,omitempty"` + Override bool `json:"override,omitempty"` + Role pd.PeerRoleType `json:"role"` + Count int `json:"count"` + Constraints []pd.LabelConstraint `json:"label_constraints,omitempty"` + LocationLabels []string `json:"location_labels,omitempty"` + IsolationLevel string `json:"isolation_level,omitempty"` + StartKeyHex string `json:"start_key"` + EndKeyHex string `json:"end_key"` } // MarshalJSON implements json.Marshaler interface for TiFlashRule. @@ -155,7 +130,7 @@ func (r *TiFlashRule) UnmarshalJSON(bytes []byte) error { // RuleBuilder is used to build the Rules from a constraint string. type RuleBuilder struct { - role PeerRoleType + role pd.PeerRoleType replicasNum uint64 skipCheckReplicasConsistent bool constraintStr string @@ -167,7 +142,7 @@ func NewRuleBuilder() *RuleBuilder { } // SetRole sets the role of the rule. -func (b *RuleBuilder) SetRole(role PeerRoleType) *RuleBuilder { +func (b *RuleBuilder) SetRole(role pd.PeerRoleType) *RuleBuilder { b.role = role return b } @@ -192,14 +167,14 @@ func (b *RuleBuilder) SetConstraintStr(constraintStr string) *RuleBuilder { // BuildRulesWithDictConstraintsOnly constructs []*Rule from a yaml-compatible representation of // 'dict' constraints. -func (b *RuleBuilder) BuildRulesWithDictConstraintsOnly() ([]*Rule, error) { +func (b *RuleBuilder) BuildRulesWithDictConstraintsOnly() ([]*pd.Rule, error) { return newRulesWithDictConstraints(b.role, b.constraintStr) } // BuildRules constructs []*Rule from a yaml-compatible representation of // 'array' or 'dict' constraints. // Refer to https://github.com/pingcap/tidb/blob/master/docs/design/2020-06-24-placement-rules-in-sql.md. -func (b *RuleBuilder) BuildRules() ([]*Rule, error) { +func (b *RuleBuilder) BuildRules() ([]*pd.Rule, error) { rules, err := newRules(b.role, b.replicasNum, b.constraintStr) // check if replicas is consistent if err == nil { @@ -219,11 +194,11 @@ func (b *RuleBuilder) BuildRules() ([]*Rule, error) { // NewRule constructs *Rule from role, count, and constraints. It is here to // consistent the behavior of creating new rules. -func NewRule(role PeerRoleType, replicas uint64, cnst Constraints) *Rule { - return &Rule{ - Role: role, - Count: int(replicas), - Constraints: cnst, +func NewRule(role pd.PeerRoleType, replicas uint64, cnst []pd.LabelConstraint) *pd.Rule { + return &pd.Rule{ + Role: role, + Count: int(replicas), + LabelConstraints: cnst, } } @@ -242,7 +217,7 @@ func getYamlMapFormatError(str string) error { // newRules constructs []*Rule from a yaml-compatible representation of // 'array' or 'dict' constraints. // Refer to https://github.com/pingcap/tidb/blob/master/docs/design/2020-06-24-placement-rules-in-sql.md. -func newRules(role PeerRoleType, replicas uint64, cnstr string) (rules []*Rule, err error) { +func newRules(role pd.PeerRoleType, replicas uint64, cnstr string) (rules []*pd.Rule, err error) { cnstbytes := []byte(cnstr) constraints1, err1 := NewConstraintsFromYaml(cnstbytes) if err1 == nil { @@ -268,8 +243,8 @@ func newRules(role PeerRoleType, replicas uint64, cnstr string) (rules []*Rule, // newRulesWithDictConstraints constructs []*Rule from a yaml-compatible representation of // 'dict' constraints. -func newRulesWithDictConstraints(role PeerRoleType, cnstr string) ([]*Rule, error) { - rules := []*Rule{} +func newRulesWithDictConstraints(role pd.PeerRoleType, cnstr string) ([]*pd.Rule, error) { + rules := []*pd.Rule{} cnstbytes := []byte(cnstr) constraints2 := map[string]int{} err2 := yaml.UnmarshalStrict(cnstbytes, &constraints2) @@ -302,15 +277,3 @@ func newRulesWithDictConstraints(role PeerRoleType, cnstr string) ([]*Rule, erro return nil, fmt.Errorf("%w: should be [constraint1, ...] or {constraint1: cnt1, ...}, error %s, or any yaml compatible representation", ErrInvalidConstraintsFormat, err2) } - -// Clone is used to duplicate a RuleOp for safe modification. -// Note that it is a shallow copy: Constraints is not cloned. -func (r *Rule) Clone() *Rule { - n := &Rule{} - *n = *r - return n -} - -func (r *Rule) String() string { - return fmt.Sprintf("%+v", *r) -} diff --git a/pkg/ddl/placement/rule_test.go b/pkg/ddl/placement/rule_test.go index dd6eadf4d29c5..89232e44fc759 100644 --- a/pkg/ddl/placement/rule_test.go +++ b/pkg/ddl/placement/rule_test.go @@ -21,18 +21,19 @@ import ( "testing" "github.com/stretchr/testify/require" + pd "github.com/tikv/pd/client/http" ) func TestClone(t *testing.T) { - rule := &Rule{ID: "434"} + rule := &pd.Rule{ID: "434"} newRule := rule.Clone() newRule.ID = "121" - require.Equal(t, &Rule{ID: "434"}, rule) - require.Equal(t, &Rule{ID: "121"}, newRule) + require.Equal(t, &pd.Rule{ID: "434"}, rule) + require.Equal(t, &pd.Rule{ID: "121"}, newRule) } -func matchRules(t1, t2 []*Rule, prefix string, t *testing.T) { +func matchRules(t1, t2 []*pd.Rule, prefix string, t *testing.T) { require.Equal(t, len(t2), len(t1), prefix) for i := range t1 { found := false @@ -52,7 +53,7 @@ func TestNewRuleAndNewRules(t *testing.T) { name string input string replicas uint64 - output []*Rule + output []*pd.Rule err error } var tests []TestCase @@ -61,8 +62,8 @@ func TestNewRuleAndNewRules(t *testing.T) { name: "empty constraints", input: "", replicas: 3, - output: []*Rule{ - NewRule(Voter, 3, NewConstraintsDirect()), + output: []*pd.Rule{ + NewRule(pd.Voter, 3, NewConstraintsDirect()), }, }) @@ -77,10 +78,10 @@ func TestNewRuleAndNewRules(t *testing.T) { name: "normal list constraints", input: `["+zone=sh", "+region=sh"]`, replicas: 3, - output: []*Rule{ - NewRule(Voter, 3, NewConstraintsDirect( - NewConstraintDirect("zone", In, "sh"), - NewConstraintDirect("region", In, "sh"), + output: []*pd.Rule{ + NewRule(pd.Voter, 3, NewConstraintsDirect( + NewConstraintDirect("zone", pd.In, "sh"), + NewConstraintDirect("region", pd.In, "sh"), )), }, }) @@ -88,13 +89,13 @@ func TestNewRuleAndNewRules(t *testing.T) { tests = append(tests, TestCase{ name: "normal dict constraints", input: `{"+zone=sh,-zone=bj":2, "+zone=sh": 1}`, - output: []*Rule{ - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("zone", In, "sh"), - NewConstraintDirect("zone", NotIn, "bj"), + output: []*pd.Rule{ + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("zone", pd.In, "sh"), + NewConstraintDirect("zone", pd.NotIn, "bj"), )), - NewRule(Voter, 1, NewConstraintsDirect( - NewConstraintDirect("zone", In, "sh"), + NewRule(pd.Voter, 1, NewConstraintsDirect( + NewConstraintDirect("zone", pd.In, "sh"), )), }, }) @@ -102,13 +103,13 @@ func TestNewRuleAndNewRules(t *testing.T) { tests = append(tests, TestCase{ name: "normal dict constraints, with count", input: "{'+zone=sh,-zone=bj':2, '+zone=sh': 1}", - output: []*Rule{ - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("zone", In, "sh"), - NewConstraintDirect("zone", NotIn, "bj"), + output: []*pd.Rule{ + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("zone", pd.In, "sh"), + NewConstraintDirect("zone", pd.NotIn, "bj"), )), - NewRule(Voter, 1, NewConstraintsDirect( - NewConstraintDirect("zone", In, "sh"), + NewRule(pd.Voter, 1, NewConstraintsDirect( + NewConstraintDirect("zone", pd.In, "sh"), )), }, }) @@ -147,13 +148,13 @@ func TestNewRuleAndNewRules(t *testing.T) { tests = append(tests, TestCase{ name: "normal dict constraint with evict leader attribute", input: `{"+zone=sh,-zone=bj":2, "+zone=sh,#evict-leader": 1}`, - output: []*Rule{ - NewRule(Voter, 2, NewConstraintsDirect( - NewConstraintDirect("zone", In, "sh"), - NewConstraintDirect("zone", NotIn, "bj"), + output: []*pd.Rule{ + NewRule(pd.Voter, 2, NewConstraintsDirect( + NewConstraintDirect("zone", pd.In, "sh"), + NewConstraintDirect("zone", pd.NotIn, "bj"), )), - NewRule(Follower, 1, NewConstraintsDirect( - NewConstraintDirect("zone", In, "sh"), + NewRule(pd.Follower, 1, NewConstraintsDirect( + NewConstraintDirect("zone", pd.In, "sh"), )), }, }) @@ -172,7 +173,7 @@ func TestNewRuleAndNewRules(t *testing.T) { for _, tt := range tests { comment := fmt.Sprintf("[%s]", tt.name) - output, err := newRules(Voter, tt.replicas, tt.input) + output, err := newRules(pd.Voter, tt.replicas, tt.input) if tt.err == nil { require.NoError(t, err, comment) matchRules(tt.output, output, comment, t) diff --git a/pkg/domain/infosync/info.go b/pkg/domain/infosync/info.go index d60806c0f941b..5b53adc260cff 100644 --- a/pkg/domain/infosync/info.go +++ b/pkg/domain/infosync/info.go @@ -213,7 +213,7 @@ func GlobalInfoSyncerInit( pdHTTPCli = pdHTTPCli.WithRespHandler(pdResponseHandler) } is.labelRuleManager = initLabelRuleManager(pdHTTPCli) - is.placementManager = initPlacementManager(etcdCli) + is.placementManager = initPlacementManager(pdHTTPCli) is.scheduleManager = initScheduleManager(etcdCli) is.tiflashReplicaManager = initTiFlashReplicaManager(etcdCli, codec) is.resourceManagerClient = initResourceManagerClient(pdCli) @@ -254,11 +254,11 @@ func initLabelRuleManager(pdHTTPCli pdhttp.Client) LabelRuleManager { return &PDLabelManager{pdHTTPCli} } -func initPlacementManager(etcdCli *clientv3.Client) PlacementManager { - if etcdCli == nil { +func initPlacementManager(pdHTTPCli pdhttp.Client) PlacementManager { + if pdHTTPCli == nil { return &mockPlacementManager{} } - return &PDPlacementManager{etcdCli: etcdCli} + return &PDPlacementManager{pdHTTPCli} } func initResourceManagerClient(pdCli pd.Client) (cli pd.ResourceManagerClient) { diff --git a/pkg/domain/infosync/placement_manager.go b/pkg/domain/infosync/placement_manager.go index 2d1597bf8f0e3..2d9de6a24d3e4 100644 --- a/pkg/domain/infosync/placement_manager.go +++ b/pkg/domain/infosync/placement_manager.go @@ -15,18 +15,11 @@ package infosync import ( - "bytes" "context" - "encoding/json" - "net/http" - "path" "sync" - "github.com/pingcap/log" "github.com/pingcap/tidb/pkg/ddl/placement" pd "github.com/tikv/pd/client/http" - clientv3 "go.etcd.io/etcd/client/v3" - "go.uber.org/zap" ) // PlacementManager manages placement settings @@ -41,27 +34,30 @@ type PlacementManager interface { // PDPlacementManager manages placement with pd type PDPlacementManager struct { - etcdCli *clientv3.Client + pdHTTPCli pd.Client } // GetRuleBundle is used to get one specific rule bundle from PD. func (m *PDPlacementManager) GetRuleBundle(ctx context.Context, name string) (*placement.Bundle, error) { - bundle := &placement.Bundle{ID: name} - res, err := doRequest(ctx, "GetPlacementRule", m.etcdCli.Endpoints(), path.Join(pd.Config, "placement-rule", name), http.MethodGet, nil) - if err == nil && res != nil { - err = json.Unmarshal(res, bundle) + groupBundle, err := m.pdHTTPCli.GetPlacementRuleBundleByGroup(ctx, name) + if err != nil { + return nil, err } - return bundle, err + groupBundle.ID = name + return (*placement.Bundle)(groupBundle), err } // GetAllRuleBundles is used to get all rule bundles from PD. It is used to load full rules from PD while fullload infoschema. func (m *PDPlacementManager) GetAllRuleBundles(ctx context.Context) ([]*placement.Bundle, error) { - var bundles []*placement.Bundle - res, err := doRequest(ctx, "GetAllPlacementRules", m.etcdCli.Endpoints(), path.Join(pd.Config, "placement-rule"), http.MethodGet, nil) - if err == nil && res != nil { - err = json.Unmarshal(res, &bundles) + bundles, err := m.pdHTTPCli.GetAllPlacementRuleBundles(ctx) + if err != nil { + return nil, err + } + rules := make([]*placement.Bundle, 0, len(bundles)) + for _, bundle := range bundles { + rules = append(rules, (*placement.Bundle)(bundle)) } - return bundles, err + return rules, nil } // PutRuleBundles is used to post specific rule bundles to PD. @@ -69,15 +65,11 @@ func (m *PDPlacementManager) PutRuleBundles(ctx context.Context, bundles []*plac if len(bundles) == 0 { return nil } - - b, err := json.Marshal(bundles) - if err != nil { - return err + ruleBundles := make([]*pd.GroupBundle, 0, len(bundles)) + for _, bundle := range bundles { + ruleBundles = append(ruleBundles, (*pd.GroupBundle)(bundle)) } - - log.Debug("Put placement rule bundles", zap.String("rules", string(b))) - _, err = doRequest(ctx, "PutPlacementRules", m.etcdCli.Endpoints(), path.Join(pd.Config, "placement-rule")+"?partial=true", http.MethodPost, bytes.NewReader(b)) - return err + return m.pdHTTPCli.SetPlacementRuleBundles(ctx, ruleBundles, true) } type mockPlacementManager struct { diff --git a/pkg/domain/infosync/tiflash_manager.go b/pkg/domain/infosync/tiflash_manager.go index f1d93c024e39e..7b549ec25f1ed 100644 --- a/pkg/domain/infosync/tiflash_manager.go +++ b/pkg/domain/infosync/tiflash_manager.go @@ -314,19 +314,19 @@ var _ json.Marshaler = (*RuleOp)(nil) var _ json.Unmarshaler = (*RuleOp)(nil) type ruleOp struct { - GroupID string `json:"group_id"` - ID string `json:"id"` - Index int `json:"index,omitempty"` - Override bool `json:"override,omitempty"` - Role placement.PeerRoleType `json:"role"` - Count int `json:"count"` - Constraints placement.Constraints `json:"label_constraints,omitempty"` - LocationLabels []string `json:"location_labels,omitempty"` - IsolationLevel string `json:"isolation_level,omitempty"` - StartKeyHex string `json:"start_key"` - EndKeyHex string `json:"end_key"` - Action RuleOpType `json:"action"` - DeleteByIDPrefix bool `json:"delete_by_id_prefix"` + GroupID string `json:"group_id"` + ID string `json:"id"` + Index int `json:"index,omitempty"` + Override bool `json:"override,omitempty"` + Role pd.PeerRoleType `json:"role"` + Count int `json:"count"` + Constraints []pd.LabelConstraint `json:"label_constraints,omitempty"` + LocationLabels []string `json:"location_labels,omitempty"` + IsolationLevel string `json:"isolation_level,omitempty"` + StartKeyHex string `json:"start_key"` + EndKeyHex string `json:"end_key"` + Action RuleOpType `json:"action"` + DeleteByIDPrefix bool `json:"delete_by_id_prefix"` } // MarshalJSON implements json.Marshaler interface for RuleOp. @@ -544,12 +544,12 @@ func makeBaseRule() placement.TiFlashRule { ID: "", Index: placement.RuleIndexTiFlash, Override: false, - Role: placement.Learner, + Role: pd.Learner, Count: 2, - Constraints: []placement.Constraint{ + Constraints: []pd.LabelConstraint{ { Key: "engine", - Op: placement.In, + Op: pd.In, Values: []string{"tiflash"}, }, }, @@ -874,7 +874,7 @@ func isRuleMatch(rule placement.TiFlashRule, startKey []byte, endKey []byte, cou } ok := false for _, c := range rule.Constraints { - if c.Key == "engine" && len(c.Values) == 1 && c.Values[0] == "tiflash" && c.Op == placement.In { + if c.Key == "engine" && len(c.Values) == 1 && c.Values[0] == "tiflash" && c.Op == pd.In { ok = true break } @@ -894,7 +894,7 @@ func isRuleMatch(rule placement.TiFlashRule, startKey []byte, endKey []byte, cou if rule.Count != count { return false } - if rule.Role != placement.Learner { + if rule.Role != pd.Learner { return false } return true From cf1b5cdfc7f1a804ac76f624941d7210bda4eaec Mon Sep 17 00:00:00 2001 From: JmPotato Date: Mon, 27 Nov 2023 13:50:58 +0800 Subject: [PATCH 2/2] Update the PD HTTP client version Signed-off-by: JmPotato --- DEPS.bzl | 12 ++++++------ br/pkg/pdutil/pd.go | 2 +- go.mod | 3 +-- go.sum | 4 ++-- pkg/domain/infosync/tiflash_manager.go | 2 +- pkg/executor/infoschema_reader.go | 2 +- pkg/store/helper/helper.go | 2 +- 7 files changed, 13 insertions(+), 14 deletions(-) diff --git a/DEPS.bzl b/DEPS.bzl index fce821be35c63..672d7155bc10e 100644 --- a/DEPS.bzl +++ b/DEPS.bzl @@ -7158,13 +7158,13 @@ def go_deps(): name = "com_github_tikv_pd_client", build_file_proto_mode = "disable_global", importpath = "github.com/tikv/pd/client", - sha256 = "38789aba9a8542056f58fa8374e794a7b0c5949531744a9962634385b717134f", - strip_prefix = "github.com/JmPotato/pd/client@v0.0.0-20231123144827-8fc4cf2ee7b0", + sha256 = "5232ba0bba677a6d4614ae2cc102554d59cd00d473d9138739508d6f25169f02", + strip_prefix = "github.com/tikv/pd/client@v0.0.0-20231127075044-9f4803d8bd05", urls = [ - "http://bazel-cache.pingcap.net:8080/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", - "http://ats.apps.svc/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", - "https://cache.hawkingrei.com/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", - "https://storage.googleapis.com/pingcapmirror/gomod/github.com/JmPotato/pd/client/com_github_jmpotato_pd_client-v0.0.0-20231123144827-8fc4cf2ee7b0.zip", + "http://bazel-cache.pingcap.net:8080/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231127075044-9f4803d8bd05.zip", + "http://ats.apps.svc/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231127075044-9f4803d8bd05.zip", + "https://cache.hawkingrei.com/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231127075044-9f4803d8bd05.zip", + "https://storage.googleapis.com/pingcapmirror/gomod/github.com/tikv/pd/client/com_github_tikv_pd_client-v0.0.0-20231127075044-9f4803d8bd05.zip", ], ) go_repository( diff --git a/br/pkg/pdutil/pd.go b/br/pkg/pdutil/pd.go index 779d3044de11d..7eae3a0652989 100644 --- a/br/pkg/pdutil/pd.go +++ b/br/pkg/pdutil/pd.go @@ -389,7 +389,7 @@ func (p *PdController) getRegionCountWith( } var err error for _, addr := range p.getAllPDAddrs() { - v, e := get(ctx, addr, pdhttp.RegionStatsByKeyRange(start, end), p.cli, http.MethodGet, nil) + v, e := get(ctx, addr, pdhttp.RegionStatsByKeyRange(pdhttp.NewKeyRange(start, end)), p.cli, http.MethodGet, nil) if e != nil { err = e continue diff --git a/go.mod b/go.mod index 4b89cb2c77649..1d687632d74da 100644 --- a/go.mod +++ b/go.mod @@ -103,7 +103,7 @@ require ( github.com/tdakkota/asciicheck v0.2.0 github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2 github.com/tikv/client-go/v2 v2.0.8-0.20231116051730-1c2351c28173 - github.com/tikv/pd/client v0.0.0-20231121080541-8919bc11f770 + github.com/tikv/pd/client v0.0.0-20231127075044-9f4803d8bd05 github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 github.com/twmb/murmur3 v1.1.6 github.com/uber/jaeger-client-go v2.22.1+incompatible @@ -314,5 +314,4 @@ replace ( github.com/dgrijalva/jwt-go => github.com/form3tech-oss/jwt-go v3.2.6-0.20210809144907-32ab6a8243d7+incompatible github.com/go-ldap/ldap/v3 => github.com/YangKeao/ldap/v3 v3.4.5-0.20230421065457-369a3bab1117 github.com/pingcap/tidb/pkg/parser => ./pkg/parser - github.com/tikv/pd/client v0.0.0-20231121080541-8919bc11f770 => github.com/JmPotato/pd/client v0.0.0-20231123144827-8fc4cf2ee7b0 ) diff --git a/go.sum b/go.sum index b8ba77b331e47..5a8d1523eb5bd 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,6 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Jeffail/gabs/v2 v2.5.1 h1:ANfZYjpMlfTTKebycu4X1AgkVWumFVDYQl7JwOr4mDk= github.com/Jeffail/gabs/v2 v2.5.1/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI= -github.com/JmPotato/pd/client v0.0.0-20231123144827-8fc4cf2ee7b0 h1:EfoujwJPhwsS0Qe/Tc60nn2e9HfJPM9w5zbspIYNI74= -github.com/JmPotato/pd/client v0.0.0-20231123144827-8fc4cf2ee7b0/go.mod h1:cd6zBqRM9aogxf26K8NnFRPVtq9BnRE59tKEpX8IaWQ= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -994,6 +992,8 @@ github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a h1:J/YdBZ46WKpXsxsW github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a/go.mod h1:h4xBhSNtOeEosLJ4P7JyKXX7Cabg7AVkWCK5gV2vOrM= github.com/tikv/client-go/v2 v2.0.8-0.20231116051730-1c2351c28173 h1:lmJzX0kqrV7kO21wrZPbtjkidzwbDCfXeQrhDWEi5dE= github.com/tikv/client-go/v2 v2.0.8-0.20231116051730-1c2351c28173/go.mod h1:BOGTSZtbMHEnGC4HOpbONdnTQF+E9nb2Io7c3P9sb7g= +github.com/tikv/pd/client v0.0.0-20231127075044-9f4803d8bd05 h1:87NPUfzaVrO5MTBwVCPQ/FlJGpFnHi6WFYHDYD3n3Zc= +github.com/tikv/pd/client v0.0.0-20231127075044-9f4803d8bd05/go.mod h1:cd6zBqRM9aogxf26K8NnFRPVtq9BnRE59tKEpX8IaWQ= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= diff --git a/pkg/domain/infosync/tiflash_manager.go b/pkg/domain/infosync/tiflash_manager.go index 7b549ec25f1ed..f4ea36b21c63a 100644 --- a/pkg/domain/infosync/tiflash_manager.go +++ b/pkg/domain/infosync/tiflash_manager.go @@ -495,7 +495,7 @@ func (m *TiFlashReplicaManagerCtx) GetRegionCountFromPD(ctx context.Context, tab endKey := tablecodec.EncodeTablePrefix(tableID + 1) startKey, endKey = m.codec.EncodeRegionRange(startKey, endKey) - p := fmt.Sprintf("%s&count", pd.RegionStatsByKeyRange(startKey, endKey)) + p := fmt.Sprintf("%s&count", pd.RegionStatsByKeyRange(pd.NewKeyRange(startKey, endKey))) res, err := doRequest(ctx, "GetPDRegionStats", m.etcdCli.Endpoints(), p, "GET", nil) if err != nil { return errors.Trace(err) diff --git a/pkg/executor/infoschema_reader.go b/pkg/executor/infoschema_reader.go index af79439a5eef7..bf3747e0d410f 100644 --- a/pkg/executor/infoschema_reader.go +++ b/pkg/executor/infoschema_reader.go @@ -1730,7 +1730,7 @@ func (*memtableRetriever) getRegionsInfoForSingleTable(ctx context.Context, help if err != nil { return nil, err } - return pdCli.GetRegionsByKeyRange(ctx, sk, ek, -1) + return pdCli.GetRegionsByKeyRange(ctx, pd.NewKeyRange(sk, ek), -1) } func (e *memtableRetriever) setNewTiKVRegionStatusCol(region *pd.RegionInfo, table *helper.TableInfo) { diff --git a/pkg/store/helper/helper.go b/pkg/store/helper/helper.go index acc65afd5b03e..824d93159e5f9 100644 --- a/pkg/store/helper/helper.go +++ b/pkg/store/helper/helper.go @@ -806,7 +806,7 @@ func (h *Helper) GetPDRegionStats(ctx context.Context, tableID int64, noIndexSta startKey = codec.EncodeBytes([]byte{}, startKey) endKey = codec.EncodeBytes([]byte{}, endKey) - return pdCli.GetRegionStatusByKeyRange(ctx, startKey, endKey) + return pdCli.GetRegionStatusByKeyRange(ctx, pd.NewKeyRange(startKey, endKey)) } // GetTiFlashTableIDFromEndKey computes tableID from pd rule's endKey.