From 9e61c9f9a9eb0e88e21dafc8d1a553dcd5970a19 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 25 Aug 2021 15:12:03 +0800 Subject: [PATCH 1/8] support create and drop placement policy Signed-off-by: ailinkid <314806019@qq.com> --- ddl/ddl.go | 2 + ddl/ddl_api.go | 92 +++++++++++++++++++ ddl/ddl_worker.go | 4 + ddl/error.go | 4 +- ddl/partition.go | 10 +-- ddl/placement_policy.go | 166 +++++++++++++++++++++++++++++++++++ ddl/placement_policy_test.go | 133 ++++++++++++++++++++++++++++ ddl/table.go | 2 +- executor/ddl.go | 11 +++ go.mod | 2 +- go.sum | 4 +- infoschema/builder.go | 28 ++++++ infoschema/error.go | 4 + infoschema/infoschema.go | 17 +++- meta/meta.go | 18 +++- meta/meta_test.go | 2 +- 16 files changed, 483 insertions(+), 16 deletions(-) create mode 100644 ddl/placement_policy.go create mode 100644 ddl/placement_policy_test.go diff --git a/ddl/ddl.go b/ddl/ddl.go index bad34f76e3cbb..7f9f0102120d9 100644 --- a/ddl/ddl.go +++ b/ddl/ddl.go @@ -115,6 +115,8 @@ type DDL interface { CreateSequence(ctx sessionctx.Context, stmt *ast.CreateSequenceStmt) error DropSequence(ctx sessionctx.Context, tableIdent ast.Ident, ifExists bool) (err error) AlterSequence(ctx sessionctx.Context, stmt *ast.AlterSequenceStmt) error + CreatePlacementPolicy(ctx sessionctx.Context, stmt *ast.CreatePlacementPolicyStmt) error + DropPlacementPolicy(ctx sessionctx.Context, stmt *ast.DropPlacementPolicyStmt) error // CreateSchemaWithInfo creates a database (schema) given its database info. // diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 127d2f9c78c18..8478796b97871 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -57,6 +57,7 @@ import ( "github.com/pingcap/tidb/util/domainutil" "github.com/pingcap/tidb/util/logutil" "github.com/pingcap/tidb/util/mock" + "github.com/pingcap/tidb/util/placementpolicy" "github.com/pingcap/tidb/util/set" "go.uber.org/zap" ) @@ -6146,3 +6147,94 @@ func (d *ddl) AlterTablePartitionAttributes(ctx sessionctx.Context, ident ast.Id err = d.callHookOnChanged(err) return errors.Trace(err) } + +func buildPolicyInfo(stmt *ast.CreatePlacementPolicyStmt) (*placementpolicy.PolicyInfo, error) { + policyInfo := &placementpolicy.PolicyInfo{} + policyInfo.Name = stmt.PolicyName + for _, opt := range stmt.PlacementOptions { + switch opt.Tp { + case ast.PlacementOptionPrimaryRegion: + policyInfo.PrimaryRegion = opt.StrValue + case ast.PlacementOptionRegions: + policyInfo.Regions = opt.StrValue + case ast.PlacementOptionFollowerCount: + policyInfo.Followers = opt.UintValue + case ast.PlacementOptionVoterCount: + policyInfo.Voters = opt.UintValue + case ast.PlacementOptionLearnerCount: + policyInfo.Learners = opt.UintValue + case ast.PlacementOptionSchedule: + policyInfo.Schedule = opt.StrValue + case ast.PlacementOptionConstraints: + policyInfo.Schedule = opt.StrValue + case ast.PlacementOptionLearnerConstraints: + policyInfo.LearnerConstraints = opt.StrValue + case ast.PlacementOptionFollowerConstraints: + policyInfo.FollowerConstraints = opt.StrValue + case ast.PlacementOptionVoterConstraints: + policyInfo.VoterConstraints = opt.StrValue + default: + return nil, errors.Trace(errors.New("unknown placement policy option")) + } + } + return policyInfo, nil +} + +func (d *ddl) CreatePlacementPolicy(ctx sessionctx.Context, stmt *ast.CreatePlacementPolicyStmt) (err error) { + policyName := stmt.PolicyName + is := d.GetInfoSchemaWithInterceptor(ctx) + // Check policy existence. + _, ok := is.PolicyByName(policyName) + if ok { + err = infoschema.ErrPlacementPolicyExists.GenWithStackByArgs(policyName) + if stmt.IfNotExists { + ctx.GetSessionVars().StmtCtx.AppendNote(err) + return nil + } + return err + } + // Auto fill the policyID when it is inserted. + policyInfo, err := buildPolicyInfo(stmt) + if err != nil { + return errors.Trace(err) + } + + job := &model.Job{ + SchemaName: policyInfo.Name.L, + Type: model.ActionCreatePlacementPolicy, + BinlogInfo: &model.HistoryInfo{}, + Args: []interface{}{policyInfo}, + } + err = d.doDDLJob(ctx, job) + err = d.callHookOnChanged(err) + return errors.Trace(err) +} + +func (d *ddl) DropPlacementPolicy(ctx sessionctx.Context, stmt *ast.DropPlacementPolicyStmt) (err error) { + policyName := stmt.PolicyName + is := d.GetInfoSchemaWithInterceptor(ctx) + // Check policy existence. + policy, ok := is.PolicyByName(policyName) + if !ok { + err = infoschema.ErrPlacementPolicyNotExists.GenWithStackByArgs(policyName) + if stmt.IfExists { + ctx.GetSessionVars().StmtCtx.AppendNote(err) + return nil + } + return err + } + + job := &model.Job{ + SchemaID: policy.ID, + SchemaName: policy.Name.L, + Type: model.ActionDropPlacementPolicy, + BinlogInfo: &model.HistoryInfo{}, + Args: []interface{}{policyName}, + } + err = d.doDDLJob(ctx, job) + err = d.callHookOnChanged(err) + return errors.Trace(err) +} + +type policyRelatedIDs struct { +} diff --git a/ddl/ddl_worker.go b/ddl/ddl_worker.go index bef94b4edf91c..b380887cc1c52 100644 --- a/ddl/ddl_worker.go +++ b/ddl/ddl_worker.go @@ -834,6 +834,10 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, ver, err = onAlterTableAttributes(t, job) case model.ActionAlterTablePartitionAttributes: ver, err = onAlterTablePartitionAttributes(t, job) + case model.ActionCreatePlacementPolicy: + ver, err = onCreatePlacementPolicy(d, t, job) + case model.ActionDropPlacementPolicy: + ver, err = onDropPlacementPolicy(t, job) default: // Invalid job, cancel it. job.State = model.JobStateCancelled diff --git a/ddl/error.go b/ddl/error.go index 42ba073829e72..2576bf9c79271 100644 --- a/ddl/error.go +++ b/ddl/error.go @@ -253,10 +253,10 @@ var ( // ErrTableOptionInsertMethodUnsupported is returned when create/alter table with insert method option. ErrTableOptionInsertMethodUnsupported = dbterror.ClassDDL.NewStd(mysql.ErrTableOptionInsertMethodUnsupported) - // ErrInvalidPlacementSpec is returned when add/alter an invalid placement rule + // ErrInvalidPlacementSpec is returned when add/alter an invalid placement_policy rule ErrInvalidPlacementSpec = dbterror.ClassDDL.NewStd(mysql.ErrInvalidPlacementSpec) - // ErrInvalidPlacementPolicyCheck is returned when txn_scope and commit data changing do not meet the placement policy + // ErrInvalidPlacementPolicyCheck is returned when txn_scope and commit data changing do not meet the placement_policy policy ErrInvalidPlacementPolicyCheck = dbterror.ClassDDL.NewStd(mysql.ErrPlacementPolicyCheck) // ErrMultipleDefConstInListPart returns multiple definition of same constant in list partitioning. diff --git a/ddl/partition.go b/ddl/partition.go index 0a3556bcb09fb..32b2e52747056 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -942,7 +942,7 @@ func (w *worker) onDropTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) ( err = dropRuleBundles(d, physicalTableIDs) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") } ver, err = updateVersionAndTableInfo(t, job, tblInfo, true) if err != nil { @@ -972,7 +972,7 @@ func (w *worker) onDropTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) ( err = dropRuleBundles(d, physicalTableIDs) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") } job.SchemaState = model.StateDeleteOnly ver, err = updateVersionAndTableInfo(t, job, tblInfo, originalState != job.SchemaState) @@ -1108,7 +1108,7 @@ func onTruncateTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) (int64, e err = infosync.PutRuleBundles(context.TODO(), bundles) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") } newIDs := make([]int64, len(oldIDs)) @@ -1315,7 +1315,7 @@ func (w *worker) onExchangeTablePartition(d *ddlCtx, t *meta.Meta, job *model.Jo err = infosync.PutRuleBundles(context.TODO(), bundles) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") } ver, err = updateSchemaVersion(t, job) @@ -1746,7 +1746,7 @@ func onAlterTableAlterPartition(t *meta.Meta, job *model.Job) (ver int64, err er err = infosync.PutRuleBundles(context.TODO(), []*placement.Bundle{bundle}) if err != nil { job.State = model.JobStateCancelled - return 0, errors.Wrapf(err, "failed to notify PD the placement rules") + return 0, errors.Wrapf(err, "failed to notify PD the placement_policy rules") } ptInfo.SetStateByID(partitionID, model.StatePublic) // used by ApplyDiff in updateSchemaVersion diff --git a/ddl/placement_policy.go b/ddl/placement_policy.go new file mode 100644 index 0000000000000..e6651546a77e1 --- /dev/null +++ b/ddl/placement_policy.go @@ -0,0 +1,166 @@ +// 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 ddl + +import ( + "fmt" + + "github.com/pingcap/errors" + "github.com/pingcap/parser/model" + "github.com/pingcap/tidb/infoschema" + "github.com/pingcap/tidb/meta" + "github.com/pingcap/tidb/util/placementpolicy" +) + +func onCreatePlacementPolicy(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) { + policyInfo := &placementpolicy.PolicyInfo{} + if err := job.DecodeArgs(policyInfo); err != nil { + job.State = model.JobStateCancelled + return ver, errors.Trace(err) + } + policyInfo.State = model.StateNone + + err := checkPlacementPolicyNotExistAndCancelExistJob(d, t, job, policyInfo) + if err != nil { + return ver, errors.Trace(err) + } + switch policyInfo.State { + case model.StateNone: + // none -> public + policyInfo.State = model.StatePublic + err = t.CreatePolicy(policyInfo) + if err != nil { + return ver, errors.Trace(err) + } + job.SchemaID = policyInfo.ID + + ver, err = updateSchemaVersion(t, job) + if err != nil { + return ver, errors.Trace(err) + } + // Finish this job. + job.FinishDBJob(model.JobStateDone, model.StatePublic, ver, nil) + return ver, nil + default: + // We can't enter here. + return ver, ErrInvalidDDLState.GenWithStackByArgs("policy", policyInfo.State) + } +} + +func getPolicyInfo(t *meta.Meta, policyID int64) (*placementpolicy.PolicyInfo, error) { + policy, err := t.GetPolicy(policyID) + if err != nil { + if meta.ErrPolicyNotExists.Equal(err) { + return nil, errors.Trace(infoschema.ErrPlacementPolicyNotExists.GenWithStackByArgs( + fmt.Sprintf("(Policy ID %d)", policyID), + )) + } + return nil, errors.Trace(err) + } + return policy, nil +} + +func checkPlacementPolicyNotExistAndCancelExistJob(d *ddlCtx, t *meta.Meta, job *model.Job, info *placementpolicy.PolicyInfo) error { + currVer, err := t.GetSchemaVersion() + if err != nil { + return err + } + is := d.infoCache.GetLatest() + if is.SchemaMetaVersion() == currVer { + // Use cached policy. + _, ok := is.PolicyByName(info.Name) + if ok { + job.State = model.JobStateCancelled + return infoschema.ErrPlacementPolicyExists.GenWithStackByArgs(info.Name) + } + return nil + } + // Check in meta directly. + policies, err := t.ListPolicies() + if err != nil { + return errors.Trace(err) + } + for _, policy := range policies { + if policy.Name.L == info.Name.L { + job.State = model.JobStateCancelled + return infoschema.ErrPlacementPolicyExists.GenWithStackByArgs(info.Name) + } + } + return nil +} + +func checkPlacementPolicyExistAndCancelNonExistJob(t *meta.Meta, job *model.Job, policyID int64) (*placementpolicy.PolicyInfo, error) { + policy, err := getPolicyInfo(t, policyID) + if err == nil { + return policy, nil + } + if infoschema.ErrPlacementPolicyNotExists.Equal(err) { + job.State = model.JobStateCancelled + } + return nil, err +} + +func onDropPlacementPolicy(t *meta.Meta, job *model.Job) (ver int64, _ error) { + policyInfo, err := checkPlacementPolicyExistAndCancelNonExistJob(t, job, job.SchemaID) + if err != nil { + return ver, errors.Trace(err) + } + switch policyInfo.State { + case model.StatePublic: + // public -> write only + policyInfo.State = model.StateWriteOnly + err = t.UpdatePolicy(policyInfo) + if err != nil { + return ver, errors.Trace(err) + } + ver, err = updateSchemaVersion(t, job) + if err != nil { + return ver, errors.Trace(err) + } + // Update the job state when all affairs done. + job.SchemaState = model.StateWriteOnly + case model.StateWriteOnly: + // write only -> delete only + policyInfo.State = model.StateDeleteOnly + err = t.UpdatePolicy(policyInfo) + if err != nil { + return ver, errors.Trace(err) + } + ver, err = updateSchemaVersion(t, job) + if err != nil { + return ver, errors.Trace(err) + } + // Update the job state when all affairs done. + job.SchemaState = model.StateDeleteOnly + case model.StateDeleteOnly: + policyInfo.State = model.StateNone + if err = t.DropPolicy(policyInfo.ID); err != nil { + return ver, errors.Trace(err) + } + ver, err = updateSchemaVersion(t, job) + if err != nil { + return ver, errors.Trace(err) + } + // TODO: Reset all the policy reference, (modify meta & notify pd) + // If any partitions currently use this policy, they will be converted to the policy used by the table + // they belong to. If any databases use this policy, they will be converted to the default placement_policy policy. + + // Finish this job. By now policy don't consider the binlog sync. + job.FinishDBJob(model.JobStateDone, model.StateNone, ver, nil) + default: + err = ErrInvalidDDLState.GenWithStackByArgs("policy", policyInfo.State) + } + return ver, errors.Trace(err) +} diff --git a/ddl/placement_policy_test.go b/ddl/placement_policy_test.go new file mode 100644 index 0000000000000..bdb66430b0a2e --- /dev/null +++ b/ddl/placement_policy_test.go @@ -0,0 +1,133 @@ +// 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 ddl_test + +import ( + "context" + . "github.com/pingcap/check" + "github.com/pingcap/parser/model" + "github.com/pingcap/tidb/ddl" + "github.com/pingcap/tidb/domain" + mysql "github.com/pingcap/tidb/errno" + "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/meta" + "github.com/pingcap/tidb/sessionctx" + "github.com/pingcap/tidb/util/placementpolicy" + "github.com/pingcap/tidb/util/testkit" +) + +func (s *testDBSuite6) TestPlacementPolicy(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop placement policy if exists x") + + originalHook := s.dom.DDL().GetHook() + defer s.dom.DDL().(ddl.DDLForTest).SetHook(originalHook) + + hook := &ddl.TestDDLCallback{} + var policyID int64 + hook.OnJobUpdatedExported = func(job *model.Job) { + if policyID != 0 { + return + } + // job.SchemaID will be assigned when the policy is created. + if job.SchemaName == "x" && job.Type == model.ActionCreatePlacementPolicy && job.SchemaID != 0 { + policyID = job.SchemaID + return + } + } + s.dom.DDL().(ddl.DDLForTest).SetHook(hook) + + tk.MustExec("create placement policy x " + + "PRIMARY_REGION=\"cn-east-1\" " + + "REGIONS=\"cn-east-1,cn-east-2\" " + + "LEARNERS=1 " + + "LEARNER_CONSTRAINTS=\"[+region=cn-west-1]\" " + + "VOTERS=3 " + + "VOTER_CONSTRAINTS=\"[+disk=ssd]\"") + + checkFunc := func(policyInfo *placementpolicy.PolicyInfo) { + c.Assert(policyInfo.ID != 0, Equals, true) + c.Assert(policyInfo.Name.L, Equals, "x") + c.Assert(policyInfo.PrimaryRegion, Equals, "cn-east-1") + c.Assert(policyInfo.Regions, Equals, "cn-east-1,cn-east-2") + c.Assert(policyInfo.Followers, Equals, uint64(0)) + c.Assert(policyInfo.FollowerConstraints, Equals, "") + c.Assert(policyInfo.Voters, Equals, uint64(3)) + c.Assert(policyInfo.VoterConstraints, Equals, "[+disk=ssd]") + c.Assert(policyInfo.Learners, Equals, uint64(1)) + c.Assert(policyInfo.LearnerConstraints, Equals, "[+region=cn-west-1]") + c.Assert(policyInfo.State, Equals, model.StatePublic) + c.Assert(policyInfo.Schedule, Equals, "") + } + + // Check the policy is correctly reloaded in the information schema. + po := testGetPolicyByNameFromIS(c, tk.Se, "x") + checkFunc(po) + + // Check the policy is correctly written in the kv meta. + po = testGetPolicyByIDFromMeta(c, s.store, policyID) + checkFunc(po) + + tk.MustGetErrCode("create placement policy x "+ + "PRIMARY_REGION=\"cn-east-1\" "+ + "REGIONS=\"cn-east-1,cn-east-2\" ", mysql.ErrPlacementPolicyExists) + + tk.MustGetErrCode("create placement policy X "+ + "PRIMARY_REGION=\"cn-east-1\" "+ + "REGIONS=\"cn-east-1,cn-east-2\" ", mysql.ErrPlacementPolicyExists) + + tk.MustGetErrCode("create placement policy `X` "+ + "PRIMARY_REGION=\"cn-east-1\" "+ + "REGIONS=\"cn-east-1,cn-east-2\" ", mysql.ErrPlacementPolicyExists) + + tk.MustExec("create placement policy if not exists X " + + "PRIMARY_REGION=\"cn-east-1\" " + + "REGIONS=\"cn-east-1,cn-east-2\" ") + + tk.MustExec("drop placement policy x") + tk.MustGetErrCode("drop placement policy x", mysql.ErrPlacementPolicyNotExists) + tk.MustExec("drop placement policy if exists x") + + // TODO: privilege check & constraint syntax check. +} + +func testGetPolicyByIDFromMeta(c *C, store kv.Storage, policyID int64) *placementpolicy.PolicyInfo { + var ( + policyInfo *placementpolicy.PolicyInfo + err error + ) + err1 := kv.RunInNewTxn(context.Background(), store, false, func(ctx context.Context, txn kv.Transaction) error { + t := meta.NewMeta(txn) + policyInfo, err = t.GetPolicy(policyID) + if err != nil { + return err + } + return nil + }) + c.Assert(err1, IsNil) + c.Assert(policyInfo, NotNil) + return policyInfo +} + +func testGetPolicyByNameFromIS(c *C, ctx sessionctx.Context, policy string) *placementpolicy.PolicyInfo { + dom := domain.GetDomain(ctx) + // Make sure the table schema is the new schema. + err := dom.Reload() + c.Assert(err, IsNil) + po, ok := dom.InfoSchema().PolicyByName(model.NewCIStr(policy)) + c.Assert(ok, Equals, true) + return po +} diff --git a/ddl/table.go b/ddl/table.go index 36ea2a6174b00..1df9c635cdf84 100644 --- a/ddl/table.go +++ b/ddl/table.go @@ -515,7 +515,7 @@ func onTruncateTable(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ erro err = infosync.PutRuleBundles(context.TODO(), bundles) if err != nil { job.State = model.JobStateCancelled - return 0, errors.Wrapf(err, "failed to notify PD the placement rules") + return 0, errors.Wrapf(err, "failed to notify PD the placement_policy rules") } tableRuleID := fmt.Sprintf(label.TableIDFormat, label.IDPrefix, job.SchemaName, tblInfo.Name.L) diff --git a/executor/ddl.go b/executor/ddl.go index e8b28b8e3e876..e242fc0600238 100644 --- a/executor/ddl.go +++ b/executor/ddl.go @@ -233,6 +233,10 @@ func (e *DDLExec) Next(ctx context.Context, req *chunk.Chunk) (err error) { err = e.executeDropSequence(x) case *ast.AlterSequenceStmt: err = e.executeAlterSequence(x) + case *ast.CreatePlacementPolicyStmt: + err = e.executeCreatePlacementPolicy(x) + case *ast.DropPlacementPolicyStmt: + err = e.executeDropPlacementPolicy(x) } if err != nil { // If the owner return ErrTableNotExists error when running this DDL, it may be caused by schema changed, @@ -903,3 +907,10 @@ func (e *DDLExec) executeCreateSequence(s *ast.CreateSequenceStmt) error { func (e *DDLExec) executeAlterSequence(s *ast.AlterSequenceStmt) error { return domain.GetDomain(e.ctx).DDL().AlterSequence(e.ctx, s) } + +func (e *DDLExec) executeCreatePlacementPolicy(s *ast.CreatePlacementPolicyStmt) error { + return domain.GetDomain(e.ctx).DDL().CreatePlacementPolicy(e.ctx, s) +} +func (e *DDLExec) executeDropPlacementPolicy(s *ast.DropPlacementPolicyStmt) error { + return domain.GetDomain(e.ctx).DDL().DropPlacementPolicy(e.ctx, s) +} diff --git a/go.mod b/go.mod index 613f89b960b21..86f8abee5b1b9 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/pingcap/fn v0.0.0-20200306044125-d5540d389059 github.com/pingcap/kvproto v0.0.0-20210806074406-317f69fb54b4 github.com/pingcap/log v0.0.0-20210818144256-6455d4a4c6f9 - github.com/pingcap/parser v0.0.0-20210823033705-7a7940986a30 + github.com/pingcap/parser v0.0.0-20210823071803-562fed23b4fb github.com/pingcap/sysutil v0.0.0-20210730114356-fcd8a63f68c5 github.com/pingcap/tidb-tools v5.0.3+incompatible github.com/pingcap/tipb v0.0.0-20210708040514-0f154bb0dc0f diff --git a/go.sum b/go.sum index 1bb9c7bd38f21..65fb61eeab746 100644 --- a/go.sum +++ b/go.sum @@ -566,8 +566,8 @@ github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuR github.com/pingcap/log v0.0.0-20210818144256-6455d4a4c6f9 h1:6t7vOzOGF3/iz+wpcwu8N/+aoWTOMq2xc+Y0pYMJOhU= github.com/pingcap/log v0.0.0-20210818144256-6455d4a4c6f9/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= github.com/pingcap/parser v0.0.0-20210525032559-c37778aff307/go.mod h1:xZC8I7bug4GJ5KtHhgAikjTfU4kBv1Sbo3Pf1MZ6lVw= -github.com/pingcap/parser v0.0.0-20210823033705-7a7940986a30 h1:UPeHfUVa9AanMJJ1Sp6+WRWYazL4qHCDcYwP33L5ZUw= -github.com/pingcap/parser v0.0.0-20210823033705-7a7940986a30/go.mod h1:Ek0mLKEqUGnQqBw1JnYrJQxsguU433DU68yUbsoeJ7s= +github.com/pingcap/parser v0.0.0-20210823071803-562fed23b4fb h1:umpYsBhJ0or/Sf6rLkDUkysdLMxtrpAa+MpYtGN2Kdg= +github.com/pingcap/parser v0.0.0-20210823071803-562fed23b4fb/go.mod h1:Ek0mLKEqUGnQqBw1JnYrJQxsguU433DU68yUbsoeJ7s= github.com/pingcap/sysutil v0.0.0-20200206130906-2bfa6dc40bcd/go.mod h1:EB/852NMQ+aRKioCpToQ94Wl7fktV+FNnxf3CX/TTXI= github.com/pingcap/sysutil v0.0.0-20210315073920-cc0985d983a3/go.mod h1:tckvA041UWP+NqYzrJ3fMgC/Hw9wnmQ/tUkp/JaHly8= github.com/pingcap/sysutil v0.0.0-20210730114356-fcd8a63f68c5 h1:7rvAtZe/ZUzOKzgriNPQoBNvleJXBk4z7L3Z47+tS98= diff --git a/infoschema/builder.go b/infoschema/builder.go index d86ef74e3ddce..3847904990040 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -55,6 +55,10 @@ func (b *Builder) ApplyDiff(m *meta.Meta, diff *model.SchemaDiff) ([]int64, erro return b.applyDropSchema(diff.SchemaID), nil case model.ActionModifySchemaCharsetAndCollate: return nil, b.applyModifySchemaCharsetAndCollate(m, diff) + case model.ActionCreatePlacementPolicy: + return nil, b.applyCreatePolicy(m, diff) + case model.ActionDropPlacementPolicy: + return b.applyDropPolicy(diff.SchemaID), nil } roDBInfo, ok := b.is.SchemaByID(diff.SchemaID) if !ok { @@ -242,6 +246,20 @@ func (b *Builder) copySortedTables(oldTableID, newTableID int64) { } } +func (b *Builder) applyCreatePolicy(m *meta.Meta, diff *model.SchemaDiff) error { + po, err := m.GetPolicy(diff.SchemaID) + if err != nil { + return errors.Trace(err) + } + if po == nil { + return ErrPlacementPolicyExists.GenWithStackByArgs( + fmt.Sprintf("(Policy ID %d)", diff.SchemaID), + ) + } + b.is.policyMap[po.Name.L] = po + return nil +} + func (b *Builder) applyCreateSchema(m *meta.Meta, diff *model.SchemaDiff) error { di, err := m.GetDatabase(diff.SchemaID) if err != nil { @@ -275,6 +293,16 @@ func (b *Builder) applyModifySchemaCharsetAndCollate(m *meta.Meta, diff *model.S return nil } +func (b *Builder) applyDropPolicy(PolicyID int64) []int64 { + po, ok := b.is.PolicyByID(PolicyID) + if !ok { + return nil + } + delete(b.is.policyMap, po.Name.L) + // TODO: return the policy related table ids + return []int64{} +} + func (b *Builder) applyDropSchema(schemaID int64) []int64 { di, ok := b.is.SchemaByID(schemaID) if !ok { diff --git a/infoschema/error.go b/infoschema/error.go index b9c0854bab051..699466b741125 100644 --- a/infoschema/error.go +++ b/infoschema/error.go @@ -28,6 +28,10 @@ var ( ErrAccessDenied = dbterror.ClassSchema.NewStd(mysql.ErrAccessDenied) // ErrDatabaseNotExists returns for database not exists. ErrDatabaseNotExists = dbterror.ClassSchema.NewStd(mysql.ErrBadDB) + // ErrPlacementPolicyExists returns for placement_policy policy already exists. + ErrPlacementPolicyExists = dbterror.ClassSchema.NewStd(mysql.ErrPlacementPolicyExists) + // ErrPlacementPolicyNotExists return for placement_policy policy not exists. + ErrPlacementPolicyNotExists = dbterror.ClassSchema.NewStd(mysql.ErrPlacementPolicyNotExists) // ErrTableExists returns for table already exists. ErrTableExists = dbterror.ClassSchema.NewStd(mysql.ErrTableExists) // ErrTableDropExists returns for dropping a non-existent table. diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index b13d0ede1fdbe..fbeb3c2f23ac3 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -39,6 +39,7 @@ type InfoSchema interface { TableExists(schema, table model.CIStr) bool SchemaByID(id int64) (*model.DBInfo, bool) SchemaByTable(tableInfo *model.TableInfo) (*model.DBInfo, bool) + PolicyByName(name model.CIStr) (*placementpolicy.PolicyInfo, bool) TableByID(id int64) (table.Table, bool) AllocByID(id int64) (autoid.Allocators, bool) AllSchemaNames() []string @@ -95,7 +96,7 @@ type infoSchema struct { ruleBundleMutex sync.RWMutex ruleBundleMap map[string]*placement.Bundle - // policyMap stores all placement policies. + // policyMap stores all placement_policy policies. policyMutex sync.RWMutex policyMap map[string]*placementpolicy.PolicyInfo @@ -214,6 +215,16 @@ func (is *infoSchema) TableExists(schema, table model.CIStr) bool { return false } +func (is *infoSchema) PolicyByID(id int64) (val *placementpolicy.PolicyInfo, ok bool) { + // TODO: use another hash map to avoid traveling on the policy map + for _, v := range is.policyMap { + if v.ID == id { + return v, true + } + } + return nil, false +} + func (is *infoSchema) SchemaByID(id int64) (val *model.DBInfo, ok bool) { for _, v := range is.schemaMap { if v.dbInfo.ID == id { @@ -355,10 +366,10 @@ func HasAutoIncrementColumn(tbInfo *model.TableInfo) (bool, string) { } // PolicyByName is used to find the policy. -func (is *infoSchema) PolicyByName(name string) (*placementpolicy.PolicyInfo, bool) { +func (is *infoSchema) PolicyByName(name model.CIStr) (*placementpolicy.PolicyInfo, bool) { is.policyMutex.RLock() defer is.policyMutex.RUnlock() - t, r := is.policyMap[name] + t, r := is.policyMap[name.L] return t, r } diff --git a/meta/meta.go b/meta/meta.go index e4872e7d08740..bf03073c55d33 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -490,6 +490,18 @@ func (m *Meta) RestartSequenceValue(dbID int64, tableInfo *model.TableInfo, seqV return errors.Trace(m.txn.HSet(m.dbKey(dbID), m.sequenceKey(tableInfo.ID), []byte(strconv.FormatInt(seqValue, 10)))) } +func (m *Meta) DropPolicy(policyID int64) error { + // Check if policy exists. + policyKey := m.policyKey(policyID) + if err := m.txn.HClear(policyKey); err != nil { + return errors.Trace(err) + } + if err := m.txn.HDel(mPolicies, policyKey); err != nil { + return errors.Trace(err) + } + return nil +} + // DropDatabase drops whole database. func (m *Meta) DropDatabase(dbID int64) error { // Check if db exists. @@ -669,9 +681,13 @@ func (m *Meta) ListPolicies() ([]*placement.PolicyInfo, error) { func (m *Meta) GetPolicy(policyID int64) (*placement.PolicyInfo, error) { policyKey := m.policyKey(policyID) value, err := m.txn.HGet(mPolicies, policyKey) - if err != nil || value == nil { + if err != nil { return nil, errors.Trace(err) } + if value == nil { + return nil, ErrPolicyNotExists.GenWithStack("policy id : %d doesn't exist", policyID) + } + value, err = detachMagicByte(value) if err != nil { return nil, errors.Trace(err) diff --git a/meta/meta_test.go b/meta/meta_test.go index d5512a1145ced..524b1d131c5aa 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -74,7 +74,7 @@ func TestPlacementPolicy(t *testing.T) { require.NoError(t, err) require.Equal(t, policy, val) - // mock updating the placement policy. + // mock updating the placement_policy policy. policy.Name = model.NewCIStr("bb") policy.LearnerConstraints = "+zone=nanjing" err = m.UpdatePolicy(policy) From 7694a70002a71575fcb43e11053f783914ba885c Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 25 Aug 2021 15:59:07 +0800 Subject: [PATCH 2/8] clean code Signed-off-by: ailinkid <314806019@qq.com> --- ddl/ddl_api.go | 3 --- ddl/error.go | 4 ++-- ddl/partition.go | 10 +++++----- ddl/table.go | 2 +- infoschema/infoschema.go | 2 +- meta/meta_test.go | 2 +- 6 files changed, 10 insertions(+), 13 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 8478796b97871..77c375a47266f 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -6235,6 +6235,3 @@ func (d *ddl) DropPlacementPolicy(ctx sessionctx.Context, stmt *ast.DropPlacemen err = d.callHookOnChanged(err) return errors.Trace(err) } - -type policyRelatedIDs struct { -} diff --git a/ddl/error.go b/ddl/error.go index 2576bf9c79271..42ba073829e72 100644 --- a/ddl/error.go +++ b/ddl/error.go @@ -253,10 +253,10 @@ var ( // ErrTableOptionInsertMethodUnsupported is returned when create/alter table with insert method option. ErrTableOptionInsertMethodUnsupported = dbterror.ClassDDL.NewStd(mysql.ErrTableOptionInsertMethodUnsupported) - // ErrInvalidPlacementSpec is returned when add/alter an invalid placement_policy rule + // ErrInvalidPlacementSpec is returned when add/alter an invalid placement rule ErrInvalidPlacementSpec = dbterror.ClassDDL.NewStd(mysql.ErrInvalidPlacementSpec) - // ErrInvalidPlacementPolicyCheck is returned when txn_scope and commit data changing do not meet the placement_policy policy + // ErrInvalidPlacementPolicyCheck is returned when txn_scope and commit data changing do not meet the placement policy ErrInvalidPlacementPolicyCheck = dbterror.ClassDDL.NewStd(mysql.ErrPlacementPolicyCheck) // ErrMultipleDefConstInListPart returns multiple definition of same constant in list partitioning. diff --git a/ddl/partition.go b/ddl/partition.go index 32b2e52747056..0a3556bcb09fb 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -942,7 +942,7 @@ func (w *worker) onDropTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) ( err = dropRuleBundles(d, physicalTableIDs) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement rules") } ver, err = updateVersionAndTableInfo(t, job, tblInfo, true) if err != nil { @@ -972,7 +972,7 @@ func (w *worker) onDropTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) ( err = dropRuleBundles(d, physicalTableIDs) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement rules") } job.SchemaState = model.StateDeleteOnly ver, err = updateVersionAndTableInfo(t, job, tblInfo, originalState != job.SchemaState) @@ -1108,7 +1108,7 @@ func onTruncateTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) (int64, e err = infosync.PutRuleBundles(context.TODO(), bundles) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement rules") } newIDs := make([]int64, len(oldIDs)) @@ -1315,7 +1315,7 @@ func (w *worker) onExchangeTablePartition(d *ddlCtx, t *meta.Meta, job *model.Jo err = infosync.PutRuleBundles(context.TODO(), bundles) if err != nil { job.State = model.JobStateCancelled - return ver, errors.Wrapf(err, "failed to notify PD the placement_policy rules") + return ver, errors.Wrapf(err, "failed to notify PD the placement rules") } ver, err = updateSchemaVersion(t, job) @@ -1746,7 +1746,7 @@ func onAlterTableAlterPartition(t *meta.Meta, job *model.Job) (ver int64, err er err = infosync.PutRuleBundles(context.TODO(), []*placement.Bundle{bundle}) if err != nil { job.State = model.JobStateCancelled - return 0, errors.Wrapf(err, "failed to notify PD the placement_policy rules") + return 0, errors.Wrapf(err, "failed to notify PD the placement rules") } ptInfo.SetStateByID(partitionID, model.StatePublic) // used by ApplyDiff in updateSchemaVersion diff --git a/ddl/table.go b/ddl/table.go index 1df9c635cdf84..36ea2a6174b00 100644 --- a/ddl/table.go +++ b/ddl/table.go @@ -515,7 +515,7 @@ func onTruncateTable(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ erro err = infosync.PutRuleBundles(context.TODO(), bundles) if err != nil { job.State = model.JobStateCancelled - return 0, errors.Wrapf(err, "failed to notify PD the placement_policy rules") + return 0, errors.Wrapf(err, "failed to notify PD the placement rules") } tableRuleID := fmt.Sprintf(label.TableIDFormat, label.IDPrefix, job.SchemaName, tblInfo.Name.L) diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index fbeb3c2f23ac3..070350c5c9394 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -96,7 +96,7 @@ type infoSchema struct { ruleBundleMutex sync.RWMutex ruleBundleMap map[string]*placement.Bundle - // policyMap stores all placement_policy policies. + // policyMap stores all placement policies. policyMutex sync.RWMutex policyMap map[string]*placementpolicy.PolicyInfo diff --git a/meta/meta_test.go b/meta/meta_test.go index 524b1d131c5aa..d5512a1145ced 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -74,7 +74,7 @@ func TestPlacementPolicy(t *testing.T) { require.NoError(t, err) require.Equal(t, policy, val) - // mock updating the placement_policy policy. + // mock updating the placement policy. policy.Name = model.NewCIStr("bb") policy.LearnerConstraints = "+zone=nanjing" err = m.UpdatePolicy(policy) From 927ed78398807ce17a2d2f24f79ad4228180eb2b Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 25 Aug 2021 16:06:40 +0800 Subject: [PATCH 3/8] fmt Signed-off-by: ailinkid <314806019@qq.com> --- ddl/placement_policy_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ddl/placement_policy_test.go b/ddl/placement_policy_test.go index bdb66430b0a2e..09be17d201a41 100644 --- a/ddl/placement_policy_test.go +++ b/ddl/placement_policy_test.go @@ -16,6 +16,7 @@ package ddl_test import ( "context" + . "github.com/pingcap/check" "github.com/pingcap/parser/model" "github.com/pingcap/tidb/ddl" From 2c213c0a6c62b37c56fef1e5b86d5e8ded79cff0 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Thu, 26 Aug 2021 13:49:39 +0800 Subject: [PATCH 4/8] lint Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 1 + 1 file changed, 1 insertion(+) diff --git a/meta/meta.go b/meta/meta.go index bf03073c55d33..05f0f011dea18 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -490,6 +490,7 @@ func (m *Meta) RestartSequenceValue(dbID int64, tableInfo *model.TableInfo, seqV return errors.Trace(m.txn.HSet(m.dbKey(dbID), m.sequenceKey(tableInfo.ID), []byte(strconv.FormatInt(seqValue, 10)))) } +// DropPolicy drops the specified policy. func (m *Meta) DropPolicy(policyID int64) error { // Check if policy exists. policyKey := m.policyKey(policyID) From 5109c462a2659b14cf90646a2a738070dfab8c62 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Thu, 26 Aug 2021 13:54:09 +0800 Subject: [PATCH 5/8] . Signed-off-by: ailinkid <314806019@qq.com> --- ddl/ddl_api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 77c375a47266f..f8fdd67223848 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -6166,7 +6166,7 @@ func buildPolicyInfo(stmt *ast.CreatePlacementPolicyStmt) (*placementpolicy.Poli case ast.PlacementOptionSchedule: policyInfo.Schedule = opt.StrValue case ast.PlacementOptionConstraints: - policyInfo.Schedule = opt.StrValue + policyInfo.Constraints = opt.StrValue case ast.PlacementOptionLearnerConstraints: policyInfo.LearnerConstraints = opt.StrValue case ast.PlacementOptionFollowerConstraints: From 602d1581526816103c57eb431260ad34de22851e Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Thu, 26 Aug 2021 14:20:12 +0800 Subject: [PATCH 6/8] make errdoc Signed-off-by: ailinkid <314806019@qq.com> --- ddl/placement_policy.go | 6 +++--- ddl/placement_policy_test.go | 2 ++ errno/errname.go | 2 +- errors.toml | 12 +++++++++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ddl/placement_policy.go b/ddl/placement_policy.go index e6651546a77e1..fd8e5043bca22 100644 --- a/ddl/placement_policy.go +++ b/ddl/placement_policy.go @@ -63,11 +63,11 @@ func getPolicyInfo(t *meta.Meta, policyID int64) (*placementpolicy.PolicyInfo, e policy, err := t.GetPolicy(policyID) if err != nil { if meta.ErrPolicyNotExists.Equal(err) { - return nil, errors.Trace(infoschema.ErrPlacementPolicyNotExists.GenWithStackByArgs( + return nil, infoschema.ErrPlacementPolicyNotExists.GenWithStackByArgs( fmt.Sprintf("(Policy ID %d)", policyID), - )) + ) } - return nil, errors.Trace(err) + return nil, err } return policy, nil } diff --git a/ddl/placement_policy_test.go b/ddl/placement_policy_test.go index 09be17d201a41..9836cc0bb63a4 100644 --- a/ddl/placement_policy_test.go +++ b/ddl/placement_policy_test.go @@ -97,10 +97,12 @@ func (s *testDBSuite6) TestPlacementPolicy(c *C) { tk.MustExec("create placement policy if not exists X " + "PRIMARY_REGION=\"cn-east-1\" " + "REGIONS=\"cn-east-1,cn-east-2\" ") + tk.MustQuery("show warnings").Check(testkit.Rows("Note 8238 Placement policy 'X' already exists")) tk.MustExec("drop placement policy x") tk.MustGetErrCode("drop placement policy x", mysql.ErrPlacementPolicyNotExists) tk.MustExec("drop placement policy if exists x") + tk.MustQuery("show warnings").Check(testkit.Rows("Note 8239 Unknown placement policy 'x'")) // TODO: privilege check & constraint syntax check. } diff --git a/errno/errname.go b/errno/errname.go index 025caa8f0e4dd..5ee1e470357bf 100644 --- a/errno/errname.go +++ b/errno/errname.go @@ -1055,7 +1055,7 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{ ErrMultiStatementDisabled: mysql.Message("client has multi-statement capability disabled. Run SET GLOBAL tidb_multi_statement_mode='ON' after you understand the security risk", nil), ErrAsOf: mysql.Message("invalid as of timestamp: %s", nil), ErrInvalidAttributesSpec: mysql.Message("Invalid attributes '%s': %s", nil), - ErrPlacementPolicyExists: mysql.Message("Can't create placement policy '%-.192s'; policy exists", nil), + ErrPlacementPolicyExists: mysql.Message("Placement policy '%-.192s' already exists", nil), ErrPlacementPolicyNotExists: mysql.Message("Unknown placement policy '%-.192s'", nil), // TiKV/PD errors. diff --git a/errors.toml b/errors.toml index a6143d74bcd2a..c9dfc9c1eda91 100644 --- a/errors.toml +++ b/errors.toml @@ -1063,7 +1063,7 @@ DDL reorg element does not exist ["meta:8238"] error = ''' -Can't create placement policy '%-.192s'; policy exists +Placement policy '%-.192s' already exists ''' ["meta:8239"] @@ -1616,6 +1616,16 @@ error = ''' Table '%s' was locked in %s by %v ''' +["schema:8238"] +error = ''' +Placement policy '%-.192s' already exists +''' + +["schema:8239"] +error = ''' +Unknown placement policy '%-.192s' +''' + ["session:8002"] error = ''' [%d] can not retry select for update statement From 4c7a32e1574fa8410861cc5d64ed4956d2878d9e Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Mon, 30 Aug 2021 10:45:56 +0800 Subject: [PATCH 7/8] add leaderConstraints Signed-off-by: ailinkid <314806019@qq.com> --- ddl/ddl_api.go | 2 ++ util/placementpolicy/policy.go | 1 + 2 files changed, 3 insertions(+) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 2ff32c896f47b..21b905979e2d4 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -6171,6 +6171,8 @@ func buildPolicyInfo(stmt *ast.CreatePlacementPolicyStmt) (*placementpolicy.Poli policyInfo.FollowerConstraints = opt.StrValue case ast.PlacementOptionVoterConstraints: policyInfo.VoterConstraints = opt.StrValue + case ast.PlacementOptionLearnerConstraints: + policyInfo.LeaderConstraints = opt.StrValue default: return nil, errors.Trace(errors.New("unknown placement policy option")) } diff --git a/util/placementpolicy/policy.go b/util/placementpolicy/policy.go index 4768e76ed43aa..c08b03ecd493f 100644 --- a/util/placementpolicy/policy.go +++ b/util/placementpolicy/policy.go @@ -29,6 +29,7 @@ type PolicyInfo struct { Voters uint64 `json:"voters"` Schedule string `json:"schedule"` Constraints string `json:"constraints"` + LeaderConstraints string `json:"leader_constraints"` LearnerConstraints string `json:"learner_constraints"` FollowerConstraints string `json:"follower_constraints"` VoterConstraints string `json:"voter_constraints"` From 5a3764ede81a52484a569d726ea5ddbad8917cc5 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Mon, 30 Aug 2021 10:51:42 +0800 Subject: [PATCH 8/8] . Signed-off-by: ailinkid <314806019@qq.com> --- ddl/ddl_api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 21b905979e2d4..134de306a345f 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -6171,7 +6171,7 @@ func buildPolicyInfo(stmt *ast.CreatePlacementPolicyStmt) (*placementpolicy.Poli policyInfo.FollowerConstraints = opt.StrValue case ast.PlacementOptionVoterConstraints: policyInfo.VoterConstraints = opt.StrValue - case ast.PlacementOptionLearnerConstraints: + case ast.PlacementOptionLeaderConstraints: policyInfo.LeaderConstraints = opt.StrValue default: return nil, errors.Trace(errors.New("unknown placement policy option"))