From c5efcdd16f528a46ee5877d9e25511d55f688beb Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Mon, 16 Aug 2021 17:07:53 +0800 Subject: [PATCH 01/18] support storing placement policy in meta Signed-off-by: ailinkid <314806019@qq.com> --- ddl/placement/policy.go | 32 +++++++++++++ errno/errcode.go | 2 + errno/errname.go | 12 +++-- infoschema/builder.go | 9 ++++ infoschema/infoschema.go | 38 +++++++++++++++ meta/meta.go | 99 ++++++++++++++++++++++++++++++++++++++++ meta/meta_test.go | 99 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 286 insertions(+), 5 deletions(-) create mode 100644 ddl/placement/policy.go diff --git a/ddl/placement/policy.go b/ddl/placement/policy.go new file mode 100644 index 0000000000000..7eeaf0458edba --- /dev/null +++ b/ddl/placement/policy.go @@ -0,0 +1,32 @@ +// Copyright 2021 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package placement + +import "github.com/pingcap/parser/model" + +// Policy is the struct to store the placement policy. +type Policy struct { + ID int64 `json:"id"` + Name model.CIStr `json:"name"` + PrimaryRegion string `json:"primary_region"` + Regions string `json:"regions"` + Leaders int64 `json:"leaders"` + Followers int64 `json:"followers"` + Voters int64 `json:"voters"` + Schedule string `json:"schedule"` + Constraints Constraints `json:"constraints"` + LeaderConstraints Constraints `json:"leader_constraints"` + FollowerConstraints Constraints `json:"follower_constraints"` + VoterConstraints Constraints `json:"voter_constraints"` +} diff --git a/errno/errcode.go b/errno/errcode.go index 15b78afbe8d59..ff9e011cb03cf 100644 --- a/errno/errcode.go +++ b/errno/errcode.go @@ -1047,6 +1047,8 @@ const ( ErrDDLReorgElementNotExist = 8235 ErrPlacementPolicyCheck = 8236 ErrInvalidAttributesSpec = 8237 + ErrPlacementPolicyExists = 8238 + ErrPlacementPolicyNotExists = 8239 // TiKV/PD/TiFlash errors. ErrPDServerTimeout = 9001 diff --git a/errno/errname.go b/errno/errname.go index be242bbcb14b7..9862d88a9b599 100644 --- a/errno/errname.go +++ b/errno/errname.go @@ -1049,11 +1049,13 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{ ErrPartitionStatsMissing: mysql.Message("Build table: %s global-level stats failed due to missing partition-level stats", nil), ErrNotSupportedWithSem: mysql.Message("Feature '%s' is not supported when security enhanced mode is enabled", nil), - ErrInvalidPlacementSpec: mysql.Message("Invalid placement policy '%s': %s", nil), - ErrPlacementPolicyCheck: mysql.Message("Placement policy didn't meet the constraint, reason: %s", nil), - 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), + ErrInvalidPlacementSpec: mysql.Message("Invalid placement policy '%s': %s", nil), + ErrPlacementPolicyCheck: mysql.Message("Placement policy didn't meet the constraint, reason: %s", nil), + 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), + ErrPlacementPolicyNotExists: mysql.Message("Unknown placement policy '%-.192s'", nil), // TiKV/PD errors. ErrPDServerTimeout: mysql.Message("PD server timeout", nil), diff --git a/infoschema/builder.go b/infoschema/builder.go index 88e8b71add319..f35f48a28e44f 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -484,6 +484,7 @@ func (b *Builder) InitWithOldInfoSchema(oldSchema InfoSchema) *Builder { b.is.schemaMetaVersion = oldIS.schemaMetaVersion b.copySchemasMap(oldIS) b.copyBundlesMap(oldIS) + b.copyPoliciesMap(oldIS) copy(b.is.sortedTablesBuckets, oldIS.sortedTablesBuckets) return b } @@ -501,6 +502,13 @@ func (b *Builder) copyBundlesMap(oldIS *infoSchema) { } } +func (b *Builder) copyPoliciesMap(oldIS *infoSchema) { + is := b.is + for _, v := range oldIS.PlacementPolicies() { + is.SetPolicy(v) + } +} + // copySchemaTables creates a new schemaTables instance when a table in the database has changed. // It also does modifications on the new one because old schemaTables must be read-only. // Note: please make sure the dbName is in lowercase. @@ -588,6 +596,7 @@ func NewBuilder(store kv.Storage) *Builder { store: store, is: &infoSchema{ schemaMap: map[string]*schemaTables{}, + policyMap: map[string]*placement.Policy{}, ruleBundleMap: map[string]*placement.Bundle{}, sortedTablesBuckets: make([]sortedTables, bucketCount), }, diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index 41b5b2c2f6e7c..a6f810cebfc73 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -93,6 +93,10 @@ type infoSchema struct { ruleBundleMutex sync.RWMutex ruleBundleMap map[string]*placement.Bundle + // policyMap stores all placement policies. + policyMutex sync.RWMutex + policyMap map[string]*placement.Policy + schemaMap map[string]*schemaTables // sortedTablesBuckets is a slice of sortedTables, a table's bucket index is (tableID % bucketCount). @@ -106,6 +110,7 @@ type infoSchema struct { func MockInfoSchema(tbList []*model.TableInfo) InfoSchema { result := &infoSchema{} result.schemaMap = make(map[string]*schemaTables) + result.policyMap = make(map[string]*placement.Policy) result.ruleBundleMap = make(map[string]*placement.Bundle) result.sortedTablesBuckets = make([]sortedTables, bucketCount) dbInfo := &model.DBInfo{ID: 0, Name: model.NewCIStr("test"), Tables: tbList} @@ -130,6 +135,7 @@ func MockInfoSchema(tbList []*model.TableInfo) InfoSchema { func MockInfoSchemaWithSchemaVer(tbList []*model.TableInfo, schemaVer int64) InfoSchema { result := &infoSchema{} result.schemaMap = make(map[string]*schemaTables) + result.policyMap = make(map[string]*placement.Policy) result.ruleBundleMap = make(map[string]*placement.Bundle) result.sortedTablesBuckets = make([]sortedTables, bucketCount) dbInfo := &model.DBInfo{ID: 0, Name: model.NewCIStr("test"), Tables: tbList} @@ -346,6 +352,38 @@ func HasAutoIncrementColumn(tbInfo *model.TableInfo) (bool, string) { return false, "" } +// PolicyByName is used to find the policy. +func (is *infoSchema) PolicyByName(name string) (*placement.Policy, bool) { + is.policyMutex.RLock() + defer is.policyMutex.RUnlock() + t, r := is.policyMap[name] + return t, r +} + +// SetPolicy is used to set the policy. +func (is *infoSchema) SetPolicy(policy *placement.Policy) { + is.policyMutex.Lock() + defer is.policyMutex.Unlock() + is.policyMap[policy.Name.L] = policy +} + +// DeletePolicy is used to delete the policy. +func (is *infoSchema) DeletePolicy(name string) { + is.policyMutex.Lock() + defer is.policyMutex.Unlock() + delete(is.policyMap, name) +} + +func (is *infoSchema) PlacementPolicies() []*placement.Policy { + is.policyMutex.RLock() + defer is.policyMutex.RUnlock() + policies := make([]*placement.Policy, 0, len(is.policyMap)) + for _, policy := range is.policyMap { + policies = append(policies, policy) + } + return policies +} + func (is *infoSchema) BundleByName(name string) (*placement.Bundle, bool) { is.ruleBundleMutex.RLock() defer is.ruleBundleMutex.RUnlock() diff --git a/meta/meta.go b/meta/meta.go index e52bc41290b68..170b95116fcde 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -17,6 +17,7 @@ import ( "encoding/binary" "encoding/json" "fmt" + "github.com/pingcap/tidb/ddl/placement" "math" "sort" "strconv" @@ -39,6 +40,7 @@ import ( var ( globalIDMutex sync.Mutex + policyIDMutex sync.Mutex ) // Meta structure: @@ -69,6 +71,9 @@ var ( mRandomIDPrefix = "TARID" mBootstrapKey = []byte("BootstrapKey") mSchemaDiffPrefix = "Diff" + mPolicies = []byte("Policies") + mPolicyPrefix = "Policy" + mPolicyGlobalID = []byte("PolicyGlobalID") ) var ( @@ -76,6 +81,10 @@ var ( ErrDBExists = dbterror.ClassMeta.NewStd(mysql.ErrDBCreateExists) // ErrDBNotExists is the error for db not exists. ErrDBNotExists = dbterror.ClassMeta.NewStd(mysql.ErrBadDB) + // ErrPolicyExists is the error for policy exists. + ErrPolicyExists = dbterror.ClassMeta.NewStd(errno.ErrPlacementPolicyExists) + // ErrPolicyNotExists is the error for policy not exists. + ErrPolicyNotExists = dbterror.ClassMeta.NewStd(errno.ErrPlacementPolicyNotExists) // ErrTableExists is the error for table exists. ErrTableExists = dbterror.ClassMeta.NewStd(mysql.ErrTableExists) // ErrTableNotExists is the error for table not exists. @@ -144,6 +153,21 @@ func (m *Meta) GetGlobalID() (int64, error) { return m.txn.GetInt64(mNextGlobalIDKey) } +func (m *Meta) GenPolicyID() (int64, error) { + policyIDMutex.Lock() + defer policyIDMutex.Unlock() + + return m.txn.Inc(mPolicyGlobalID, 1) +} + +func (m *Meta) GetPolicyID() (int64, error) { + return m.txn.GetInt64(mPolicyGlobalID) +} + +func (m *Meta) policyKey(policyID int64) []byte { + return []byte(fmt.Sprintf("%s:%d", mPolicyPrefix, policyID)) +} + func (m *Meta) dbKey(dbID int64) []byte { return []byte(fmt.Sprintf("%s:%d", mDBPrefix, dbID)) } @@ -267,6 +291,22 @@ func (m *Meta) GenSchemaVersion() (int64, error) { return m.txn.Inc(mSchemaVersionKey, 1) } +func (m *Meta) checkPolicyExists(policyKey []byte) error { + v, err := m.txn.HGet(mPolicies, policyKey) + if err == nil && v == nil { + err = ErrPolicyNotExists.GenWithStack("policy doesn't exist") + } + return errors.Trace(err) +} + +func (m *Meta) checkPolicyNotExists(policyKey []byte) error { + v, err := m.txn.HGet(mPolicies, policyKey) + if err == nil && v != nil { + err = ErrPolicyExists.GenWithStack("policy already exists") + } + return errors.Trace(err) +} + func (m *Meta) checkDBExists(dbKey []byte) error { v, err := m.txn.HGet(mDBs, dbKey) if err == nil && v == nil { @@ -299,6 +339,33 @@ func (m *Meta) checkTableNotExists(dbKey []byte, tableKey []byte) error { return errors.Trace(err) } +func (m *Meta) CreatePolicy(policy *placement.Policy) error { + policyKey := m.policyKey(policy.ID) + + if err := m.checkPolicyNotExists(policyKey); err != nil { + return errors.Trace(err) + } + data, err := json.Marshal(policy) + if err != nil { + return errors.Trace(err) + } + return m.txn.HSet(mPolicies, policyKey, data) +} + +func (m *Meta) UpdatePolicy(policy *placement.Policy) error { + policyKey := m.policyKey(policy.ID) + + if err := m.checkPolicyExists(policyKey); err != nil { + return errors.Trace(err) + } + + data, err := json.Marshal(policy) + if err != nil { + return errors.Trace(err) + } + return m.txn.HSet(mPolicies, policyKey, data) +} + // CreateDatabase creates a database with db info. func (m *Meta) CreateDatabase(dbInfo *model.DBInfo) error { dbKey := m.dbKey(dbInfo.ID) @@ -551,6 +618,38 @@ func (m *Meta) GetDatabase(dbID int64) (*model.DBInfo, error) { return dbInfo, errors.Trace(err) } +// ListPolicies shows all policies. +func (m *Meta) ListPolicies() ([]*placement.Policy, error) { + res, err := m.txn.HGetAll(mPolicies) + if err != nil { + return nil, errors.Trace(err) + } + + policies := make([]*placement.Policy, 0, len(res)) + for _, r := range res { + policy := &placement.Policy{} + err = json.Unmarshal(r.Value, policy) + if err != nil { + return nil, errors.Trace(err) + } + policies = append(policies, policy) + } + return policies, nil +} + +// GetPolicy gets the database value with ID. +func (m *Meta) GetPolicy(policyID int64) (*placement.Policy, error) { + policyKey := m.policyKey(policyID) + value, err := m.txn.HGet(mPolicies, policyKey) + if err != nil || value == nil { + return nil, errors.Trace(err) + } + + policy := &placement.Policy{} + err = json.Unmarshal(value, policy) + return policy, errors.Trace(err) +} + // GetTable gets the table value in database with tableID. func (m *Meta) GetTable(dbID int64, tableID int64) (*model.TableInfo, error) { // Check if db exists. diff --git a/meta/meta_test.go b/meta/meta_test.go index 341b15981188e..0be8e86941471 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -16,6 +16,7 @@ package meta_test import ( "context" "fmt" + "github.com/pingcap/tidb/ddl/placement" "math" "strconv" "sync" @@ -31,6 +32,104 @@ import ( "github.com/stretchr/testify/require" ) +func TestPlacementPolicy(t *testing.T) { + t.Parallel() + + store, err := mockstore.NewMockStore() + require.NoError(t, err) + + defer func() { + err := store.Close() + require.NoError(t, err) + }() + + txn, err := store.Begin() + require.NoError(t, err) + + // test the independent policy ID allocation. + m := meta.NewMeta(txn) + id, err := m.GenPolicyID() + require.NoError(t, err) + require.Equal(t, int64(1), id) + + id, err = m.GetPolicyID() + require.NoError(t, err) + require.Equal(t, int64(1), id) + + id, err = m.GenPolicyID() + require.NoError(t, err) + require.Equal(t, int64(2), id) + + // test the meta storage of placemnt policy. + policy := &placement.Policy{ + ID: 1, + Name: model.NewCIStr("aa"), + PrimaryRegion: "my primary", + Regions: "my regions", + Leaders: 1, + Followers: 2, + Voters: 3, + Schedule: "even", + Constraints: placement.Constraints{ + { + Key: "disk", + Op: placement.In, + Values: []string{"ssd"}, + }, + }, + LeaderConstraints: placement.Constraints{ + { + Key: "zone", + Op: placement.In, + Values: []string{"shanghai"}, + }, + }, + } + err = m.CreatePolicy(policy) + require.NoError(t, err) + + err = m.CreatePolicy(policy) + require.NotNil(t, err) + require.True(t, meta.ErrPolicyExists.Equal(err)) + + val, err := m.GetPolicy(1) + require.NoError(t, err) + require.Equal(t, policy, val) + + // mock updating the placement policy. + policy.Name = model.NewCIStr("bb") + policy.LeaderConstraints = placement.Constraints{ + { + Key: "zone", + Op: placement.In, + Values: []string{"nanjing"}, + }} + err = m.UpdatePolicy(policy) + require.NoError(t, err) + + val, err = m.GetPolicy(1) + require.NoError(t, err) + require.Equal(t, policy, val) + + ps, err := m.ListPolicies() + require.NoError(t, err) + require.Equal(t, []*placement.Policy{policy}, ps) + + err = txn.Commit(context.Background()) + require.NoError(t, err) + + // fetch the stored value after committing. + txn, err = store.Begin() + require.NoError(t, err) + + m = meta.NewMeta(txn) + val, err = m.GetPolicy(1) + require.NoError(t, err) + require.Equal(t, policy, val) + err = txn.Commit(context.Background()) + require.NoError(t, err) +} + func TestMeta(t *testing.T) { t.Parallel() From f982dcbc6ff8574c3aff0d1bc2c47dace61fa615 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Mon, 16 Aug 2021 17:15:28 +0800 Subject: [PATCH 02/18] solve the import problem Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 2 +- meta/meta_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meta/meta.go b/meta/meta.go index 170b95116fcde..40f7499a5cb64 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -17,7 +17,6 @@ import ( "encoding/binary" "encoding/json" "fmt" - "github.com/pingcap/tidb/ddl/placement" "math" "sort" "strconv" @@ -29,6 +28,7 @@ import ( "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/parser/model" "github.com/pingcap/parser/mysql" + "github.com/pingcap/tidb/ddl/placement" "github.com/pingcap/tidb/errno" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/metrics" diff --git a/meta/meta_test.go b/meta/meta_test.go index 0be8e86941471..d19b22a6b462d 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -16,7 +16,6 @@ package meta_test import ( "context" "fmt" - "github.com/pingcap/tidb/ddl/placement" "math" "strconv" "sync" @@ -25,6 +24,7 @@ import ( "github.com/pingcap/errors" "github.com/pingcap/parser/model" + "github.com/pingcap/tidb/ddl/placement" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/meta" "github.com/pingcap/tidb/store/mockstore" From fa317e4fabbb275776c71bf902018e95b00e8b21 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Tue, 17 Aug 2021 10:59:15 +0800 Subject: [PATCH 03/18] address commnet Signed-off-by: ailinkid <314806019@qq.com> --- ddl/placement/policy.go | 11 +++++++---- infoschema/infoschema.go | 7 ------- meta/meta_test.go | 40 ++++++++++++---------------------------- 3 files changed, 19 insertions(+), 39 deletions(-) diff --git a/ddl/placement/policy.go b/ddl/placement/policy.go index 7eeaf0458edba..573c530e7418e 100644 --- a/ddl/placement/policy.go +++ b/ddl/placement/policy.go @@ -15,8 +15,11 @@ package placement import "github.com/pingcap/parser/model" +const DefaultPolicyMagicVer uint32 = 0 + // Policy is the struct to store the placement policy. type Policy struct { + MagicVer uint32 `json:"magic_ver"` ID int64 `json:"id"` Name model.CIStr `json:"name"` PrimaryRegion string `json:"primary_region"` @@ -25,8 +28,8 @@ type Policy struct { Followers int64 `json:"followers"` Voters int64 `json:"voters"` Schedule string `json:"schedule"` - Constraints Constraints `json:"constraints"` - LeaderConstraints Constraints `json:"leader_constraints"` - FollowerConstraints Constraints `json:"follower_constraints"` - VoterConstraints Constraints `json:"voter_constraints"` + Constraints string `json:"constraints"` + LeaderConstraints string `json:"leader_constraints"` + FollowerConstraints string `json:"follower_constraints"` + VoterConstraints string `json:"voter_constraints"` } diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index 6e2688305a130..794961229173f 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -368,13 +368,6 @@ func (is *infoSchema) SetPolicy(policy *placement.Policy) { is.policyMap[policy.Name.L] = policy } -// DeletePolicy is used to delete the policy. -func (is *infoSchema) DeletePolicy(name string) { - is.policyMutex.Lock() - defer is.policyMutex.Unlock() - delete(is.policyMap, name) -} - func (is *infoSchema) PlacementPolicies() []*placement.Policy { is.policyMutex.RLock() defer is.policyMutex.RUnlock() diff --git a/meta/meta_test.go b/meta/meta_test.go index df7819fd54d7e..fc9d50413a11d 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -63,28 +63,17 @@ func TestPlacementPolicy(t *testing.T) { // test the meta storage of placemnt policy. policy := &placement.Policy{ - ID: 1, - Name: model.NewCIStr("aa"), - PrimaryRegion: "my primary", - Regions: "my regions", - Leaders: 1, - Followers: 2, - Voters: 3, - Schedule: "even", - Constraints: placement.Constraints{ - { - Key: "disk", - Op: placement.In, - Values: []string{"ssd"}, - }, - }, - LeaderConstraints: placement.Constraints{ - { - Key: "zone", - Op: placement.In, - Values: []string{"shanghai"}, - }, - }, + MagicVer: placement.DefaultPolicyMagicVer, + ID: 1, + Name: model.NewCIStr("aa"), + PrimaryRegion: "my primary", + Regions: "my regions", + Leaders: 1, + Followers: 2, + Voters: 3, + Schedule: "even", + Constraints: "+disk=ssd", + LeaderConstraints: "+zone=shanghai", } err = m.CreatePolicy(policy) require.NoError(t, err) @@ -99,12 +88,7 @@ func TestPlacementPolicy(t *testing.T) { // mock updating the placement policy. policy.Name = model.NewCIStr("bb") - policy.LeaderConstraints = placement.Constraints{ - { - Key: "zone", - Op: placement.In, - Values: []string{"nanjing"}, - }} + policy.LeaderConstraints = "+zone=nanjing" err = m.UpdatePolicy(policy) require.NoError(t, err) From 91f1d793da2f322ae23b0550e2d180d8d1fa2061 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Tue, 17 Aug 2021 14:54:26 +0800 Subject: [PATCH 04/18] add magic number for policy Signed-off-by: ailinkid <314806019@qq.com> --- ddl/placement/policy.go | 3 --- meta/meta.go | 54 ++++++++++++++++++++++++++++++++++++++--- meta/meta_test.go | 1 - 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/ddl/placement/policy.go b/ddl/placement/policy.go index 573c530e7418e..2c5104212e32b 100644 --- a/ddl/placement/policy.go +++ b/ddl/placement/policy.go @@ -15,11 +15,8 @@ package placement import "github.com/pingcap/parser/model" -const DefaultPolicyMagicVer uint32 = 0 - // Policy is the struct to store the placement policy. type Policy struct { - MagicVer uint32 `json:"magic_ver"` ID int64 `json:"id"` Name model.CIStr `json:"name"` PrimaryRegion string `json:"primary_region"` diff --git a/meta/meta.go b/meta/meta.go index bbcfd297c23fc..afc6d8db5ae8b 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -75,6 +75,21 @@ var ( mPolicies = []byte("Policies") mPolicyPrefix = "Policy" mPolicyGlobalID = []byte("PolicyGlobalID") + mPolicyMagicByte = CurrentMagicByteVer +) + +const ( + CurrentMagicByteVer byte = 0x00 + // PolicyMagicByte handler + // 0x00 - 0x3F: Json Handler + // 0x40 - 0x7F: Reserved + // 0x80 - 0xBF: Reserved + // 0xC0 - 0xFF: Reserved + + // type means how to handle the serialized data. + typeJson int = 1 + typeUnknown int = 2 + // todo: customized handler. ) var ( @@ -350,7 +365,7 @@ func (m *Meta) CreatePolicy(policy *placement.Policy) error { if err != nil { return errors.Trace(err) } - return m.txn.HSet(mPolicies, policyKey, data) + return m.txn.HSet(mPolicies, policyKey, attachMagicByte(data)) } func (m *Meta) UpdatePolicy(policy *placement.Policy) error { @@ -364,7 +379,7 @@ func (m *Meta) UpdatePolicy(policy *placement.Policy) error { if err != nil { return errors.Trace(err) } - return m.txn.HSet(mPolicies, policyKey, data) + return m.txn.HSet(mPolicies, policyKey, attachMagicByte(data)) } // CreateDatabase creates a database with db info. @@ -628,8 +643,12 @@ func (m *Meta) ListPolicies() ([]*placement.Policy, error) { policies := make([]*placement.Policy, 0, len(res)) for _, r := range res { + value, err := detachMagicByte(r.Value) + if err != nil { + return nil, errors.Trace(err) + } policy := &placement.Policy{} - err = json.Unmarshal(r.Value, policy) + err = json.Unmarshal(value, policy) if err != nil { return nil, errors.Trace(err) } @@ -645,12 +664,41 @@ func (m *Meta) GetPolicy(policyID int64) (*placement.Policy, error) { if err != nil || value == nil { return nil, errors.Trace(err) } + value, err = detachMagicByte(value) + if err != nil { + return nil, errors.Trace(err) + } policy := &placement.Policy{} err = json.Unmarshal(value, policy) return policy, errors.Trace(err) } +func attachMagicByte(data []byte) []byte { + dataWithHeader := make([]byte, 0, len(data)+1) + dataWithHeader = append(dataWithHeader, mPolicyMagicByte) + dataWithHeader = append(dataWithHeader, data...) + return dataWithHeader +} + +func detachMagicByte(value []byte) ([]byte, error) { + magic, data := value[:1], value[1:] + switch whichMagicType(magic[0]) { + case typeJson: + return data, nil + default: + // + return nil, errors.New("unknown magic type handling module") + } +} + +func whichMagicType(b byte) int { + if b < 0x3F { + return typeJson + } + return typeUnknown +} + // GetTable gets the table value in database with tableID. func (m *Meta) GetTable(dbID int64, tableID int64) (*model.TableInfo, error) { // Check if db exists. diff --git a/meta/meta_test.go b/meta/meta_test.go index fc9d50413a11d..e5e754d76592e 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -63,7 +63,6 @@ func TestPlacementPolicy(t *testing.T) { // test the meta storage of placemnt policy. policy := &placement.Policy{ - MagicVer: placement.DefaultPolicyMagicVer, ID: 1, Name: model.NewCIStr("aa"), PrimaryRegion: "my primary", From 643499de065e42465ea65b099abbfbc301d75469 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Tue, 17 Aug 2021 14:57:08 +0800 Subject: [PATCH 05/18] . Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta/meta.go b/meta/meta.go index afc6d8db5ae8b..bdd13f4411f78 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -693,7 +693,7 @@ func detachMagicByte(value []byte) ([]byte, error) { } func whichMagicType(b byte) int { - if b < 0x3F { + if b <= 0x3F { return typeJson } return typeUnknown From bd193699cdc66f865644c5bb910d09a739bca098 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 18 Aug 2021 13:56:16 +0800 Subject: [PATCH 06/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/meta/meta.go b/meta/meta.go index bdd13f4411f78..9cf60cbde7f19 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -675,10 +675,10 @@ func (m *Meta) GetPolicy(policyID int64) (*placement.Policy, error) { } func attachMagicByte(data []byte) []byte { - dataWithHeader := make([]byte, 0, len(data)+1) - dataWithHeader = append(dataWithHeader, mPolicyMagicByte) - dataWithHeader = append(dataWithHeader, data...) - return dataWithHeader + data = append(data, 0) + copy(data[1:], data) + data[0] = mPolicyMagicByte + return data } func detachMagicByte(value []byte) ([]byte, error) { From 3896af73df3ea96514c1e5455ec0e341186e968a Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 18 Aug 2021 14:09:32 +0800 Subject: [PATCH 07/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/meta/meta.go b/meta/meta.go index 9cf60cbde7f19..ef3208f325f38 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -79,6 +79,7 @@ var ( ) const ( + // CurrentMagicByteVer is the current magic byte version. CurrentMagicByteVer byte = 0x00 // PolicyMagicByte handler // 0x00 - 0x3F: Json Handler @@ -87,7 +88,7 @@ const ( // 0xC0 - 0xFF: Reserved // type means how to handle the serialized data. - typeJson int = 1 + typeJSON int = 1 typeUnknown int = 2 // todo: customized handler. ) @@ -169,6 +170,7 @@ func (m *Meta) GetGlobalID() (int64, error) { return m.txn.GetInt64(mNextGlobalIDKey) } +// GenPolicyID generates the next policy global id. func (m *Meta) GenPolicyID() (int64, error) { policyIDMutex.Lock() defer policyIDMutex.Unlock() @@ -176,6 +178,7 @@ func (m *Meta) GenPolicyID() (int64, error) { return m.txn.Inc(mPolicyGlobalID, 1) } +// GetPolicyID gets current policy global id. func (m *Meta) GetPolicyID() (int64, error) { return m.txn.GetInt64(mPolicyGlobalID) } @@ -355,6 +358,7 @@ func (m *Meta) checkTableNotExists(dbKey []byte, tableKey []byte) error { return errors.Trace(err) } +// CreatePolicy creates a policy. func (m *Meta) CreatePolicy(policy *placement.Policy) error { policyKey := m.policyKey(policy.ID) @@ -368,6 +372,7 @@ func (m *Meta) CreatePolicy(policy *placement.Policy) error { return m.txn.HSet(mPolicies, policyKey, attachMagicByte(data)) } +// UpdatePolicy updates a policy. func (m *Meta) UpdatePolicy(policy *placement.Policy) error { policyKey := m.policyKey(policy.ID) @@ -684,7 +689,7 @@ func attachMagicByte(data []byte) []byte { func detachMagicByte(value []byte) ([]byte, error) { magic, data := value[:1], value[1:] switch whichMagicType(magic[0]) { - case typeJson: + case typeJSON: return data, nil default: // From 70aab7ae53bb484e62b7615772f08b7a78e456f2 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 18 Aug 2021 14:17:48 +0800 Subject: [PATCH 08/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta/meta.go b/meta/meta.go index ef3208f325f38..1e00979c2aefb 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -699,7 +699,7 @@ func detachMagicByte(value []byte) ([]byte, error) { func whichMagicType(b byte) int { if b <= 0x3F { - return typeJson + return typeJSON } return typeUnknown } From 2e64f19eb380520953cbfbe01a718c3522a9cb5a Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 18 Aug 2021 15:15:44 +0800 Subject: [PATCH 09/18] error Signed-off-by: ailinkid <314806019@qq.com> --- errors.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/errors.toml b/errors.toml index cd2bdd0b89abc..a6143d74bcd2a 100644 --- a/errors.toml +++ b/errors.toml @@ -1061,6 +1061,16 @@ error = ''' DDL reorg element does not exist ''' +["meta:8238"] +error = ''' +Can't create placement policy '%-.192s'; policy exists +''' + +["meta:8239"] +error = ''' +Unknown placement policy '%-.192s' +''' + ["planner:1044"] error = ''' Access denied for user '%-.48s'@'%-.64s' to database '%-.192s' From 9c931ebdd5009309ff0bef68c9ab35903c461ebd Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Wed, 18 Aug 2021 16:16:33 +0800 Subject: [PATCH 10/18] . Signed-off-by: ailinkid <314806019@qq.com> --- ddl/placement/policy.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ddl/placement/policy.go b/ddl/placement/policy.go index 2c5104212e32b..51849542dc78a 100644 --- a/ddl/placement/policy.go +++ b/ddl/placement/policy.go @@ -8,6 +8,7 @@ // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. From bcb66cb1f844e38508675fc04edc56d47f84047a Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Thu, 19 Aug 2021 11:48:55 +0800 Subject: [PATCH 11/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- infoschema/builder.go | 4 +++- infoschema/infoschema.go | 7 ------- meta/meta.go | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/infoschema/builder.go b/infoschema/builder.go index 90b6f7d3e3b22..db70f2b2b1fcb 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -505,8 +505,10 @@ func (b *Builder) copyBundlesMap(oldIS *infoSchema) { func (b *Builder) copyPoliciesMap(oldIS *infoSchema) { is := b.is + is.policyMutex.Lock() + defer is.policyMutex.Unlock() for _, v := range oldIS.PlacementPolicies() { - is.SetPolicy(v) + is.policyMap[v.Name.L] = v } } diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index 794961229173f..78fc4f40663e8 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -361,13 +361,6 @@ func (is *infoSchema) PolicyByName(name string) (*placement.Policy, bool) { return t, r } -// SetPolicy is used to set the policy. -func (is *infoSchema) SetPolicy(policy *placement.Policy) { - is.policyMutex.Lock() - defer is.policyMutex.Unlock() - is.policyMap[policy.Name.L] = policy -} - func (is *infoSchema) PlacementPolicies() []*placement.Policy { is.policyMutex.RLock() defer is.policyMutex.RUnlock() diff --git a/meta/meta.go b/meta/meta.go index 1e00979c2aefb..6677fbdfbaf2b 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -79,7 +79,7 @@ var ( ) const ( - // CurrentMagicByteVer is the current magic byte version. + // CurrentMagicByteVer is the current magic byte version, used for future meta compatibility. CurrentMagicByteVer byte = 0x00 // PolicyMagicByte handler // 0x00 - 0x3F: Json Handler From ffb8605c08870392af880048005187d5883d4771 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Fri, 20 Aug 2021 17:08:42 +0800 Subject: [PATCH 12/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- ddl/placement/policy.go | 33 ------------------------------- infoschema/builder.go | 3 ++- infoschema/infoschema.go | 13 ++++++------ meta/meta.go | 33 ++++++++++++++++--------------- util/placement_policy/policy.go | 35 +++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 56 deletions(-) delete mode 100644 ddl/placement/policy.go create mode 100644 util/placement_policy/policy.go diff --git a/ddl/placement/policy.go b/ddl/placement/policy.go deleted file mode 100644 index 51849542dc78a..0000000000000 --- a/ddl/placement/policy.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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 placement - -import "github.com/pingcap/parser/model" - -// Policy is the struct to store the placement policy. -type Policy struct { - ID int64 `json:"id"` - Name model.CIStr `json:"name"` - PrimaryRegion string `json:"primary_region"` - Regions string `json:"regions"` - Leaders int64 `json:"leaders"` - Followers int64 `json:"followers"` - Voters int64 `json:"voters"` - Schedule string `json:"schedule"` - Constraints string `json:"constraints"` - LeaderConstraints string `json:"leader_constraints"` - FollowerConstraints string `json:"follower_constraints"` - VoterConstraints string `json:"voter_constraints"` -} diff --git a/infoschema/builder.go b/infoschema/builder.go index db70f2b2b1fcb..f4fb99032e2ed 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -26,6 +26,7 @@ import ( "github.com/pingcap/parser/model" "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/ddl/placement" + "github.com/pingcap/tidb/util/placement_policy" "github.com/pingcap/tidb/domain/infosync" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/meta" @@ -599,7 +600,7 @@ func NewBuilder(store kv.Storage) *Builder { store: store, is: &infoSchema{ schemaMap: map[string]*schemaTables{}, - policyMap: map[string]*placement.Policy{}, + policyMap: map[string]*placement_policy.PolicyInfo{}, ruleBundleMap: map[string]*placement.Bundle{}, sortedTablesBuckets: make([]sortedTables, bucketCount), }, diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index 78fc4f40663e8..98959db30bcc9 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -25,6 +25,7 @@ import ( "github.com/pingcap/tidb/meta/autoid" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/util" + "github.com/pingcap/tidb/util/placement_policy" ) // InfoSchema is the interface used to retrieve the schema information. @@ -96,7 +97,7 @@ type infoSchema struct { // policyMap stores all placement policies. policyMutex sync.RWMutex - policyMap map[string]*placement.Policy + policyMap map[string]*placement_policy.PolicyInfo schemaMap map[string]*schemaTables @@ -111,7 +112,7 @@ type infoSchema struct { func MockInfoSchema(tbList []*model.TableInfo) InfoSchema { result := &infoSchema{} result.schemaMap = make(map[string]*schemaTables) - result.policyMap = make(map[string]*placement.Policy) + result.policyMap = make(map[string]*placement_policy.PolicyInfo) result.ruleBundleMap = make(map[string]*placement.Bundle) result.sortedTablesBuckets = make([]sortedTables, bucketCount) dbInfo := &model.DBInfo{ID: 0, Name: model.NewCIStr("test"), Tables: tbList} @@ -136,7 +137,7 @@ func MockInfoSchema(tbList []*model.TableInfo) InfoSchema { func MockInfoSchemaWithSchemaVer(tbList []*model.TableInfo, schemaVer int64) InfoSchema { result := &infoSchema{} result.schemaMap = make(map[string]*schemaTables) - result.policyMap = make(map[string]*placement.Policy) + result.policyMap = make(map[string]*placement_policy.PolicyInfo) result.ruleBundleMap = make(map[string]*placement.Bundle) result.sortedTablesBuckets = make([]sortedTables, bucketCount) dbInfo := &model.DBInfo{ID: 0, Name: model.NewCIStr("test"), Tables: tbList} @@ -354,17 +355,17 @@ func HasAutoIncrementColumn(tbInfo *model.TableInfo) (bool, string) { } // PolicyByName is used to find the policy. -func (is *infoSchema) PolicyByName(name string) (*placement.Policy, bool) { +func (is *infoSchema) PolicyByName(name string) (*placement_policy.PolicyInfo, bool) { is.policyMutex.RLock() defer is.policyMutex.RUnlock() t, r := is.policyMap[name] return t, r } -func (is *infoSchema) PlacementPolicies() []*placement.Policy { +func (is *infoSchema) PlacementPolicies() []*placement_policy.PolicyInfo { is.policyMutex.RLock() defer is.policyMutex.RUnlock() - policies := make([]*placement.Policy, 0, len(is.policyMap)) + policies := make([]*placement_policy.PolicyInfo, 0, len(is.policyMap)) for _, policy := range is.policyMap { policies = append(policies, policy) } diff --git a/meta/meta.go b/meta/meta.go index 6677fbdfbaf2b..51a300a5bc684 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -29,13 +29,13 @@ import ( "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/parser/model" "github.com/pingcap/parser/mysql" - "github.com/pingcap/tidb/ddl/placement" "github.com/pingcap/tidb/errno" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/metrics" "github.com/pingcap/tidb/structure" "github.com/pingcap/tidb/util/dbterror" "github.com/pingcap/tidb/util/logutil" + placement "github.com/pingcap/tidb/util/placement_policy" "go.uber.org/zap" ) @@ -170,14 +170,6 @@ func (m *Meta) GetGlobalID() (int64, error) { return m.txn.GetInt64(mNextGlobalIDKey) } -// GenPolicyID generates the next policy global id. -func (m *Meta) GenPolicyID() (int64, error) { - policyIDMutex.Lock() - defer policyIDMutex.Unlock() - - return m.txn.Inc(mPolicyGlobalID, 1) -} - // GetPolicyID gets current policy global id. func (m *Meta) GetPolicyID() (int64, error) { return m.txn.GetInt64(mPolicyGlobalID) @@ -359,7 +351,16 @@ func (m *Meta) checkTableNotExists(dbKey []byte, tableKey []byte) error { } // CreatePolicy creates a policy. -func (m *Meta) CreatePolicy(policy *placement.Policy) error { +func (m *Meta) CreatePolicy(policy *placement.PolicyInfo) error { + // Autofill the policy ID. + policyIDMutex.Lock() + genID, err := m.txn.Inc(mPolicyGlobalID, 1) + if err != nil { + return errors.Trace(err) + } + policyIDMutex.Unlock() + + policy.ID = genID policyKey := m.policyKey(policy.ID) if err := m.checkPolicyNotExists(policyKey); err != nil { @@ -373,7 +374,7 @@ func (m *Meta) CreatePolicy(policy *placement.Policy) error { } // UpdatePolicy updates a policy. -func (m *Meta) UpdatePolicy(policy *placement.Policy) error { +func (m *Meta) UpdatePolicy(policy *placement.PolicyInfo) error { policyKey := m.policyKey(policy.ID) if err := m.checkPolicyExists(policyKey); err != nil { @@ -640,19 +641,19 @@ func (m *Meta) GetDatabase(dbID int64) (*model.DBInfo, error) { } // ListPolicies shows all policies. -func (m *Meta) ListPolicies() ([]*placement.Policy, error) { +func (m *Meta) ListPolicies() ([]*placement.PolicyInfo, error) { res, err := m.txn.HGetAll(mPolicies) if err != nil { return nil, errors.Trace(err) } - policies := make([]*placement.Policy, 0, len(res)) + policies := make([]*placement.PolicyInfo, 0, len(res)) for _, r := range res { value, err := detachMagicByte(r.Value) if err != nil { return nil, errors.Trace(err) } - policy := &placement.Policy{} + policy := &placement.PolicyInfo{} err = json.Unmarshal(value, policy) if err != nil { return nil, errors.Trace(err) @@ -663,7 +664,7 @@ func (m *Meta) ListPolicies() ([]*placement.Policy, error) { } // GetPolicy gets the database value with ID. -func (m *Meta) GetPolicy(policyID int64) (*placement.Policy, 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 { @@ -674,7 +675,7 @@ func (m *Meta) GetPolicy(policyID int64) (*placement.Policy, error) { return nil, errors.Trace(err) } - policy := &placement.Policy{} + policy := &placement.PolicyInfo{} err = json.Unmarshal(value, policy) return policy, errors.Trace(err) } diff --git a/util/placement_policy/policy.go b/util/placement_policy/policy.go new file mode 100644 index 0000000000000..f86323c63a1da --- /dev/null +++ b/util/placement_policy/policy.go @@ -0,0 +1,35 @@ +// Copyright 2021 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package placement_policy + +import ( + "github.com/pingcap/parser/model" +) + +// PolicyInfo is the struct to store the placement_policy policy. +type PolicyInfo struct { + ID int64 `json:"id"` + Name model.CIStr `json:"name"` + PrimaryRegion string `json:"primary_region"` + Regions string `json:"regions"` + Learners uint64 `json:"learners"` + Followers uint64 `json:"followers"` + Voters uint64 `json:"voters"` + Schedule string `json:"schedule"` + Constraints string `json:"constraints"` + LearnerConstraints string `json:"learner_constraints"` + FollowerConstraints string `json:"follower_constraints"` + VoterConstraints string `json:"voter_constraints"` + State model.SchemaState `json:"state"` +} From 3be7de87dbcc203c2692fbd18f1b5987b2ccf3f2 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Fri, 20 Aug 2021 17:17:16 +0800 Subject: [PATCH 13/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- util/placement_policy/policy.go | 1 + 1 file changed, 1 insertion(+) diff --git a/util/placement_policy/policy.go b/util/placement_policy/policy.go index f86323c63a1da..84a5ab73f3d22 100644 --- a/util/placement_policy/policy.go +++ b/util/placement_policy/policy.go @@ -8,6 +8,7 @@ // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. From dae2b36136445d833ae7be1e3737d695f66cdfb6 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Fri, 20 Aug 2021 17:20:50 +0800 Subject: [PATCH 14/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- infoschema/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infoschema/builder.go b/infoschema/builder.go index f4fb99032e2ed..e95b3f3e25cee 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -26,7 +26,6 @@ import ( "github.com/pingcap/parser/model" "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/ddl/placement" - "github.com/pingcap/tidb/util/placement_policy" "github.com/pingcap/tidb/domain/infosync" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/meta" @@ -34,6 +33,7 @@ import ( "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/table/tables" "github.com/pingcap/tidb/util/domainutil" + "github.com/pingcap/tidb/util/placement_policy" ) // Builder builds a new InfoSchema. From 2c7e5a3e9193c74049563147d09afcabb477087a Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Fri, 20 Aug 2021 17:36:50 +0800 Subject: [PATCH 15/18] address comment Signed-off-by: ailinkid <314806019@qq.com> --- infoschema/builder.go | 4 ++-- infoschema/infoschema.go | 14 +++++++------- meta/meta.go | 2 +- .../policy.go | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) rename util/{placement_policy => placementpolicy}/policy.go (94%) diff --git a/infoschema/builder.go b/infoschema/builder.go index e95b3f3e25cee..d86ef74e3ddce 100644 --- a/infoschema/builder.go +++ b/infoschema/builder.go @@ -33,7 +33,7 @@ import ( "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/table/tables" "github.com/pingcap/tidb/util/domainutil" - "github.com/pingcap/tidb/util/placement_policy" + "github.com/pingcap/tidb/util/placementpolicy" ) // Builder builds a new InfoSchema. @@ -600,7 +600,7 @@ func NewBuilder(store kv.Storage) *Builder { store: store, is: &infoSchema{ schemaMap: map[string]*schemaTables{}, - policyMap: map[string]*placement_policy.PolicyInfo{}, + policyMap: map[string]*placementpolicy.PolicyInfo{}, ruleBundleMap: map[string]*placement.Bundle{}, sortedTablesBuckets: make([]sortedTables, bucketCount), }, diff --git a/infoschema/infoschema.go b/infoschema/infoschema.go index 98959db30bcc9..b13d0ede1fdbe 100644 --- a/infoschema/infoschema.go +++ b/infoschema/infoschema.go @@ -25,7 +25,7 @@ import ( "github.com/pingcap/tidb/meta/autoid" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/util" - "github.com/pingcap/tidb/util/placement_policy" + "github.com/pingcap/tidb/util/placementpolicy" ) // InfoSchema is the interface used to retrieve the schema information. @@ -97,7 +97,7 @@ type infoSchema struct { // policyMap stores all placement policies. policyMutex sync.RWMutex - policyMap map[string]*placement_policy.PolicyInfo + policyMap map[string]*placementpolicy.PolicyInfo schemaMap map[string]*schemaTables @@ -112,7 +112,7 @@ type infoSchema struct { func MockInfoSchema(tbList []*model.TableInfo) InfoSchema { result := &infoSchema{} result.schemaMap = make(map[string]*schemaTables) - result.policyMap = make(map[string]*placement_policy.PolicyInfo) + result.policyMap = make(map[string]*placementpolicy.PolicyInfo) result.ruleBundleMap = make(map[string]*placement.Bundle) result.sortedTablesBuckets = make([]sortedTables, bucketCount) dbInfo := &model.DBInfo{ID: 0, Name: model.NewCIStr("test"), Tables: tbList} @@ -137,7 +137,7 @@ func MockInfoSchema(tbList []*model.TableInfo) InfoSchema { func MockInfoSchemaWithSchemaVer(tbList []*model.TableInfo, schemaVer int64) InfoSchema { result := &infoSchema{} result.schemaMap = make(map[string]*schemaTables) - result.policyMap = make(map[string]*placement_policy.PolicyInfo) + result.policyMap = make(map[string]*placementpolicy.PolicyInfo) result.ruleBundleMap = make(map[string]*placement.Bundle) result.sortedTablesBuckets = make([]sortedTables, bucketCount) dbInfo := &model.DBInfo{ID: 0, Name: model.NewCIStr("test"), Tables: tbList} @@ -355,17 +355,17 @@ func HasAutoIncrementColumn(tbInfo *model.TableInfo) (bool, string) { } // PolicyByName is used to find the policy. -func (is *infoSchema) PolicyByName(name string) (*placement_policy.PolicyInfo, bool) { +func (is *infoSchema) PolicyByName(name string) (*placementpolicy.PolicyInfo, bool) { is.policyMutex.RLock() defer is.policyMutex.RUnlock() t, r := is.policyMap[name] return t, r } -func (is *infoSchema) PlacementPolicies() []*placement_policy.PolicyInfo { +func (is *infoSchema) PlacementPolicies() []*placementpolicy.PolicyInfo { is.policyMutex.RLock() defer is.policyMutex.RUnlock() - policies := make([]*placement_policy.PolicyInfo, 0, len(is.policyMap)) + policies := make([]*placementpolicy.PolicyInfo, 0, len(is.policyMap)) for _, policy := range is.policyMap { policies = append(policies, policy) } diff --git a/meta/meta.go b/meta/meta.go index 51a300a5bc684..34bd78f4fca11 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -35,7 +35,7 @@ import ( "github.com/pingcap/tidb/structure" "github.com/pingcap/tidb/util/dbterror" "github.com/pingcap/tidb/util/logutil" - placement "github.com/pingcap/tidb/util/placement_policy" + placement "github.com/pingcap/tidb/util/placementpolicy" "go.uber.org/zap" ) diff --git a/util/placement_policy/policy.go b/util/placementpolicy/policy.go similarity index 94% rename from util/placement_policy/policy.go rename to util/placementpolicy/policy.go index 84a5ab73f3d22..4768e76ed43aa 100644 --- a/util/placement_policy/policy.go +++ b/util/placementpolicy/policy.go @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package placement_policy +package placementpolicy import ( "github.com/pingcap/parser/model" ) -// PolicyInfo is the struct to store the placement_policy policy. +// PolicyInfo is the struct to store the placement policy. type PolicyInfo struct { ID int64 `json:"id"` Name model.CIStr `json:"name"` From 5dd879875e687c6b57420128915622e95f2c03de Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Fri, 20 Aug 2021 19:44:12 +0800 Subject: [PATCH 16/18] fix test Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 26 ++++++++++++++------------ meta/meta_test.go | 39 ++++++++++++++------------------------- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/meta/meta.go b/meta/meta.go index 34bd78f4fca11..3d218b5177281 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -352,20 +352,22 @@ func (m *Meta) checkTableNotExists(dbKey []byte, tableKey []byte) error { // CreatePolicy creates a policy. func (m *Meta) CreatePolicy(policy *placement.PolicyInfo) error { - // Autofill the policy ID. - policyIDMutex.Lock() - genID, err := m.txn.Inc(mPolicyGlobalID, 1) - if err != nil { - return errors.Trace(err) + if policy.ID != 0 { + policyKey := m.policyKey(policy.ID) + if err := m.checkPolicyNotExists(policyKey); err != nil { + return errors.Trace(err) + } + } else { + // Autofill the policy ID. + policyIDMutex.Lock() + genID, err := m.txn.Inc(mPolicyGlobalID, 1) + if err != nil { + return errors.Trace(err) + } + policyIDMutex.Unlock() + policy.ID = genID } - policyIDMutex.Unlock() - - policy.ID = genID policyKey := m.policyKey(policy.ID) - - if err := m.checkPolicyNotExists(policyKey); err != nil { - return errors.Trace(err) - } data, err := json.Marshal(policy) if err != nil { return errors.Trace(err) diff --git a/meta/meta_test.go b/meta/meta_test.go index e5e754d76592e..d5512a1145ced 100644 --- a/meta/meta_test.go +++ b/meta/meta_test.go @@ -25,11 +25,11 @@ import ( "github.com/pingcap/errors" "github.com/pingcap/parser/model" - "github.com/pingcap/tidb/ddl/placement" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/meta" "github.com/pingcap/tidb/store/mockstore" "github.com/pingcap/tidb/testkit" + "github.com/pingcap/tidb/util/placementpolicy" "github.com/stretchr/testify/require" ) @@ -49,33 +49,22 @@ func TestPlacementPolicy(t *testing.T) { // test the independent policy ID allocation. m := meta.NewMeta(txn) - id, err := m.GenPolicyID() - require.NoError(t, err) - require.Equal(t, int64(1), id) - - id, err = m.GetPolicyID() - require.NoError(t, err) - require.Equal(t, int64(1), id) - - id, err = m.GenPolicyID() - require.NoError(t, err) - require.Equal(t, int64(2), id) // test the meta storage of placemnt policy. - policy := &placement.Policy{ - ID: 1, - Name: model.NewCIStr("aa"), - PrimaryRegion: "my primary", - Regions: "my regions", - Leaders: 1, - Followers: 2, - Voters: 3, - Schedule: "even", - Constraints: "+disk=ssd", - LeaderConstraints: "+zone=shanghai", + policy := &placementpolicy.PolicyInfo{ + Name: model.NewCIStr("aa"), + PrimaryRegion: "my primary", + Regions: "my regions", + Learners: 1, + Followers: 2, + Voters: 3, + Schedule: "even", + Constraints: "+disk=ssd", + LearnerConstraints: "+zone=shanghai", } err = m.CreatePolicy(policy) require.NoError(t, err) + require.Equal(t, policy.ID, int64(1)) err = m.CreatePolicy(policy) require.NotNil(t, err) @@ -87,7 +76,7 @@ func TestPlacementPolicy(t *testing.T) { // mock updating the placement policy. policy.Name = model.NewCIStr("bb") - policy.LeaderConstraints = "+zone=nanjing" + policy.LearnerConstraints = "+zone=nanjing" err = m.UpdatePolicy(policy) require.NoError(t, err) @@ -97,7 +86,7 @@ func TestPlacementPolicy(t *testing.T) { ps, err := m.ListPolicies() require.NoError(t, err) - require.Equal(t, []*placement.Policy{policy}, ps) + require.Equal(t, []*placementpolicy.PolicyInfo{policy}, ps) err = txn.Commit(context.Background()) require.NoError(t, err) From f1f392443e7f132e8e6a7e268dd80fa94e4806a9 Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Sat, 21 Aug 2021 09:57:09 +0800 Subject: [PATCH 17/18] change typeUnknow to 0 Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta/meta.go b/meta/meta.go index 3d218b5177281..21e8558aab2f9 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -88,8 +88,8 @@ const ( // 0xC0 - 0xFF: Reserved // type means how to handle the serialized data. + typeUnknown int = 0 typeJSON int = 1 - typeUnknown int = 2 // todo: customized handler. ) From 9df17d00ddc9d5484cf227bfa177bac6366b741e Mon Sep 17 00:00:00 2001 From: ailinkid <314806019@qq.com> Date: Mon, 23 Aug 2021 16:50:16 +0800 Subject: [PATCH 18/18] add magic byte compatibility check Signed-off-by: ailinkid <314806019@qq.com> --- meta/meta.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meta/meta.go b/meta/meta.go index 21e8558aab2f9..e4872e7d08740 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -693,9 +693,11 @@ func detachMagicByte(value []byte) ([]byte, error) { magic, data := value[:1], value[1:] switch whichMagicType(magic[0]) { case typeJSON: + if magic[0] != CurrentMagicByteVer { + return nil, errors.New("incompatible magic type handling module") + } return data, nil default: - // return nil, errors.New("unknown magic type handling module") } }