Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

keyspace: refine the split and merge details #6707

Merged
merged 2 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions pkg/keyspace/keyspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,9 +515,9 @@ func (manager *Manager) UpdateKeyspaceState(name string, newState keyspacepb.Key
// Changing the state of default keyspace is not allowed.
if name == utils.DefaultKeyspaceName {
log.Warn("[keyspace] failed to update keyspace config",
zap.Error(errModifyDefault),
zap.Error(ErrModifyDefaultKeyspace),
)
return nil, errModifyDefault
return nil, ErrModifyDefaultKeyspace
}
var meta *keyspacepb.KeyspaceMeta
err := manager.store.RunInTxn(manager.ctx, func(txn kv.Txn) error {
Expand Down Expand Up @@ -567,9 +567,9 @@ func (manager *Manager) UpdateKeyspaceStateByID(id uint32, newState keyspacepb.K
// Changing the state of default keyspace is not allowed.
if id == utils.DefaultKeyspaceID {
log.Warn("[keyspace] failed to update keyspace config",
zap.Error(errModifyDefault),
zap.Error(ErrModifyDefaultKeyspace),
)
return nil, errModifyDefault
return nil, ErrModifyDefaultKeyspace
}
var meta *keyspacepb.KeyspaceMeta
var err error
Expand Down
65 changes: 40 additions & 25 deletions pkg/keyspace/tso_keyspace_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,16 @@ func (m *GroupManager) SplitKeyspaceGroupByID(
if splitSourceKg.IsMerging() {
return ErrKeyspaceGroupInMerging(splitSourceID)
}
// Build the new keyspace groups for split source and target.
var startKeyspaceID, endKeyspaceID uint32
if len(keyspaceIDRange) >= 2 {
startKeyspaceID, endKeyspaceID = keyspaceIDRange[0], keyspaceIDRange[1]
}
splitSourceKeyspaces, splitTargetKeyspaces, err := buildSplitKeyspaces(
splitSourceKg.Keyspaces, keyspaces, startKeyspaceID, endKeyspaceID)
if err != nil {
return err
}
Comment on lines +539 to +548
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why move this block?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adjusted the block to let some errors that could be returned earlier to make the unit test easier to write.

// Check if the source keyspace group has enough replicas.
if len(splitSourceKg.Members) < utils.DefaultKeyspaceGroupReplicaCount {
return ErrKeyspaceGroupNotEnoughReplicas
Expand All @@ -548,15 +558,6 @@ func (m *GroupManager) SplitKeyspaceGroupByID(
if splitTargetKg != nil {
return ErrKeyspaceGroupExists
}
var startKeyspaceID, endKeyspaceID uint32
if len(keyspaceIDRange) >= 2 {
startKeyspaceID, endKeyspaceID = keyspaceIDRange[0], keyspaceIDRange[1]
}
splitSourceKeyspaces, splitTargetKeyspaces, err := buildSplitKeyspaces(
splitSourceKg.Keyspaces, keyspaces, startKeyspaceID, endKeyspaceID)
if err != nil {
return err
}
// Update the old keyspace group.
splitSourceKg.Keyspaces = splitSourceKeyspaces
splitSourceKg.SplitState = &endpoint.SplitState{
Expand Down Expand Up @@ -606,6 +607,9 @@ func buildSplitKeyspaces(
oldKeyspaceMap[keyspace] = struct{}{}
}
for _, keyspace := range new {
if keyspace == utils.DefaultKeyspaceID {
return nil, nil, ErrModifyDefaultKeyspace
}
if _, ok := oldKeyspaceMap[keyspace]; !ok {
return nil, nil, ErrKeyspaceNotInKeyspaceGroup
}
Expand All @@ -618,15 +622,7 @@ func buildSplitKeyspaces(
oldSplit = append(oldSplit, keyspace)
}
}
// Dedup new keyspaces if it's necessary.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need this check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that newNum is always equal to len(newKeyspaceMap), so we can directly return new as the result here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't remove this check. I specifically add this block to fix issue #6687.

root@serverless-cluster-pd-0:/# ./pd-ctl keyspace-group split 0 2 2 2
Success!

{"id":2,"user-kind":"basic","members":[{"address":"http://pd-tso-server-0.tso-service.tidb-serverless.svc:2379","priority":200},{"address":"http://pd-tso-server-1.tso-service.tidb-serverless.svc:2379","priority":300}],"keyspaces":[2,2]}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's my fault, since I signed off this change and previous change didn't add unittest.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll reopen #6687.

if newNum == len(newKeyspaceMap) {
return oldSplit, new, nil
}
newSplit := make([]uint32, 0, len(newKeyspaceMap))
for keyspace := range newKeyspaceMap {
newSplit = append(newSplit, keyspace)
}
return oldSplit, newSplit, nil
return oldSplit, new, nil
}
// Split according to the start and end keyspace ID.
if startKeyspaceID == 0 && endKeyspaceID == 0 {
Expand All @@ -637,6 +633,9 @@ func buildSplitKeyspaces(
newKeyspaceMap = make(map[uint32]struct{}, newNum)
)
for _, keyspace := range old {
if keyspace == utils.DefaultKeyspaceID {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't add this check, because it means that we can't split default keyspace group now.

return nil, nil, ErrModifyDefaultKeyspace
}
if startKeyspaceID <= keyspace && keyspace <= endKeyspaceID {
newSplit = append(newSplit, keyspace)
newKeyspaceMap[keyspace] = struct{}{}
Expand Down Expand Up @@ -770,7 +769,9 @@ func (m *GroupManager) AllocNodesForKeyspaceGroup(id uint32, desiredReplicaCount
return nil, err
}
m.groups[endpoint.StringUserKind(kg.UserKind)].Put(kg)
log.Info("alloc nodes for keyspace group", zap.Uint32("keyspace-group-id", id), zap.Reflect("nodes", nodes))
log.Info("alloc nodes for keyspace group",
zap.Uint32("keyspace-group-id", id),
zap.Reflect("nodes", nodes))
return nodes, nil
}

Expand Down Expand Up @@ -906,20 +907,17 @@ func (m *GroupManager) MergeKeyspaceGroups(mergeTargetID uint32, mergeList []uin
}
groups[kgID] = kg
}
// Build the new keyspaces for the merge target keyspace group.
mergeTargetKg = groups[mergeTargetID]
keyspaces := make(map[uint32]struct{})
for _, keyspace := range mergeTargetKg.Keyspaces {
keyspaces[keyspace] = struct{}{}
}
// Delete the keyspace groups in merge list and move the keyspaces in it to the target keyspace group.
for _, kgID := range mergeList {
kg := groups[kgID]
for _, keyspace := range kg.Keyspaces {
keyspaces[keyspace] = struct{}{}
}
if err := m.store.DeleteKeyspaceGroup(txn, kg.ID); err != nil {
return err
}
}
mergedKeyspaces := make([]uint32, 0, len(keyspaces))
for keyspace := range keyspaces {
Expand All @@ -933,7 +931,17 @@ func (m *GroupManager) MergeKeyspaceGroups(mergeTargetID uint32, mergeList []uin
mergeTargetKg.MergeState = &endpoint.MergeState{
MergeList: mergeList,
}
return m.store.SaveKeyspaceGroup(txn, mergeTargetKg)
err = m.store.SaveKeyspaceGroup(txn, mergeTargetKg)
if err != nil {
return err
}
// Delete the keyspace groups in merge list and move the keyspaces in it to the target keyspace group.
for _, kgID := range mergeList {
if err := m.store.DeleteKeyspaceGroup(txn, kgID); err != nil {
return err
}
}
return nil
}); err != nil {
return err
}
Expand All @@ -948,7 +956,10 @@ func (m *GroupManager) MergeKeyspaceGroups(mergeTargetID uint32, mergeList []uin

// FinishMergeKeyspaceByID finishes the merging keyspace group by the merge target ID.
func (m *GroupManager) FinishMergeKeyspaceByID(mergeTargetID uint32) error {
var mergeTargetKg *endpoint.KeyspaceGroup
var (
mergeTargetKg *endpoint.KeyspaceGroup
mergeList []uint32
)
m.Lock()
defer m.Unlock()
if err := m.store.RunInTxn(m.ctx, func(txn kv.Txn) (err error) {
Expand All @@ -974,12 +985,16 @@ func (m *GroupManager) FinishMergeKeyspaceByID(mergeTargetID uint32) error {
return ErrKeyspaceGroupNotInMerging(kgID)
}
}
mergeList = mergeTargetKg.MergeState.MergeList
mergeTargetKg.MergeState = nil
return m.store.SaveKeyspaceGroup(txn, mergeTargetKg)
}); err != nil {
return err
}
// Update the keyspace group cache.
m.groups[endpoint.StringUserKind(mergeTargetKg.UserKind)].Put(mergeTargetKg)
log.Info("finish merge keyspace group",
zap.Uint32("merge-target-id", mergeTargetKg.ID),
zap.Reflect("merge-list", mergeList))
return nil
}
12 changes: 8 additions & 4 deletions pkg/keyspace/tso_keyspace_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,9 @@ func (suite *keyspaceGroupTestSuite) TestKeyspaceGroupSplit() {

keyspaceGroups := []*endpoint.KeyspaceGroup{
{
ID: uint32(1),
UserKind: endpoint.Basic.String(),
ID: uint32(1),
UserKind: endpoint.Basic.String(),
Keyspaces: []uint32{444},
},
{
ID: uint32(2),
Expand All @@ -250,8 +251,11 @@ func (suite *keyspaceGroupTestSuite) TestKeyspaceGroupSplit() {
}
err := suite.kgm.CreateKeyspaceGroups(keyspaceGroups)
re.NoError(err)
// split the default keyspace
err = suite.kgm.SplitKeyspaceGroupByID(0, 4, []uint32{utils.DefaultKeyspaceID})
re.ErrorIs(err, ErrModifyDefaultKeyspace)
// split the keyspace group 1 to 4
err = suite.kgm.SplitKeyspaceGroupByID(1, 4, []uint32{333})
err = suite.kgm.SplitKeyspaceGroupByID(1, 4, []uint32{444})
re.ErrorIs(err, ErrKeyspaceGroupNotEnoughReplicas)
// split the keyspace group 2 to 4 without giving any keyspace
err = suite.kgm.SplitKeyspaceGroupByID(2, 4, []uint32{})
Expand Down Expand Up @@ -316,7 +320,7 @@ func (suite *keyspaceGroupTestSuite) TestKeyspaceGroupSplit() {
err = suite.kgm.SplitKeyspaceGroupByID(3, 5, nil)
re.ErrorContains(err, ErrKeyspaceGroupNotExists(3).Error())
// split into an existing keyspace group
err = suite.kgm.SplitKeyspaceGroupByID(2, 4, nil)
err = suite.kgm.SplitKeyspaceGroupByID(2, 4, []uint32{111})
re.ErrorIs(err, ErrKeyspaceGroupExists)
// split with the wrong keyspaces.
err = suite.kgm.SplitKeyspaceGroupByID(2, 5, []uint32{111, 222, 444})
Expand Down
5 changes: 3 additions & 2 deletions pkg/keyspace/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ var (
ErrNoAvailableNode = errors.New("no available node")
// ErrExceedMaxEtcdTxnOps is used to indicate the number of etcd txn operations exceeds the limit.
ErrExceedMaxEtcdTxnOps = errors.New("exceed max etcd txn operations")
errModifyDefault = errors.New("cannot modify default keyspace's state")
errIllegalOperation = errors.New("unknown operation")
// ErrModifyDefaultKeyspace is used to indicate that default keyspace cannot be modified.
ErrModifyDefaultKeyspace = errors.New("cannot modify default keyspace's state")
errIllegalOperation = errors.New("unknown operation")

// stateTransitionTable lists all allowed next state for the given current state.
// Note that transit from any state to itself is allowed for idempotence.
Expand Down