This repository has been archived by the owner on Feb 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: support open shard concurrently
- Loading branch information
1 parent
741535c
commit 3e3cc45
Showing
11 changed files
with
342 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
server/coordinator/procedure/operation/transferleader/batch_transfer_leader.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2023 CeresDB Project Authors. Licensed under Apache-2.0. | ||
|
||
package transferleader | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"sync" | ||
|
||
"github.com/CeresDB/ceresmeta/pkg/log" | ||
"github.com/CeresDB/ceresmeta/server/coordinator/procedure" | ||
"github.com/CeresDB/ceresmeta/server/storage" | ||
"github.com/pkg/errors" | ||
"go.uber.org/zap" | ||
"golang.org/x/sync/errgroup" | ||
) | ||
|
||
// BatchTransferLeaderProcedure is a proxy procedure contains a batch of TransferLeaderProcedure. | ||
// It is used to support concurrent execution of a batch of TransferLeaderProcedure with same version. | ||
type BatchTransferLeaderProcedure struct { | ||
id uint64 | ||
batch []procedure.Procedure | ||
relatedVersionInfo procedure.RelatedVersionInfo | ||
|
||
// Protect the state. | ||
lock sync.RWMutex | ||
state procedure.State | ||
} | ||
|
||
func NewBatchTransferLeaderProcedure(id uint64, batch []procedure.Procedure) (procedure.Procedure, error) { | ||
if len(batch) == 0 { | ||
return nil, procedure.ErrEmptyBatchProcedure | ||
} | ||
|
||
relateVersionInfo, err := buildBatchRelatedVersionInfo(batch) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &BatchTransferLeaderProcedure{id: id, batch: batch, state: procedure.StateInit, relatedVersionInfo: relateVersionInfo}, nil | ||
} | ||
|
||
func buildBatchRelatedVersionInfo(batch []procedure.Procedure) (procedure.RelatedVersionInfo, error) { | ||
if len(batch) == 0 { | ||
return procedure.RelatedVersionInfo{}, nil | ||
} | ||
|
||
result := procedure.RelatedVersionInfo{ | ||
ClusterID: batch[0].RelatedVersionInfo().ClusterID, | ||
ShardWithVersion: map[storage.ShardID]uint64{}, | ||
ClusterVersion: batch[0].RelatedVersionInfo().ClusterVersion, | ||
} | ||
|
||
// The version of this batch of procedures must be the same. | ||
for _, p := range batch { | ||
if p.RelatedVersionInfo().ClusterID != result.ClusterID { | ||
return procedure.RelatedVersionInfo{}, errors.WithMessage(procedure.ErrMergeBatchProcedure, "procedure clusterID in the same batch is inconsistent") | ||
} | ||
if p.RelatedVersionInfo().ClusterVersion != result.ClusterVersion { | ||
return procedure.RelatedVersionInfo{}, errors.WithMessage(procedure.ErrMergeBatchProcedure, "procedure clusterVersion in the same batch is inconsistent") | ||
} | ||
// The ShardVersion of the same shard must be consistent. | ||
for shardID, version := range p.RelatedVersionInfo().ShardWithVersion { | ||
if resultVersion, exists := result.ShardWithVersion[shardID]; exists { | ||
if version != resultVersion { | ||
return procedure.RelatedVersionInfo{}, errors.WithMessage(procedure.ErrMergeBatchProcedure, "procedure shardVersion in the same batch is inconsistent") | ||
} | ||
} else { | ||
result.ShardWithVersion[shardID] = version | ||
} | ||
} | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) ID() uint64 { | ||
return p.id | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) Typ() procedure.Typ { | ||
return procedure.TransferLeader | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) Start(ctx context.Context) error { | ||
// Start procedures with multiple goroutine. | ||
g, _ := errgroup.WithContext(ctx) | ||
for _, p := range p.batch { | ||
p := p | ||
g.Go(func() error { | ||
err := p.Start(ctx) | ||
if err != nil { | ||
log.Error("procedure start failed", zap.Error(err), zap.String("procedure", fmt.Sprintf("%v", p))) | ||
} | ||
return err | ||
}) | ||
} | ||
|
||
if err := g.Wait(); err != nil { | ||
p.updateStateWithLock(procedure.StateFailed) | ||
return err | ||
} | ||
|
||
p.updateStateWithLock(procedure.StateFinished) | ||
return nil | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) Cancel(_ context.Context) error { | ||
p.updateStateWithLock(procedure.StateCancelled) | ||
return nil | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) State() procedure.State { | ||
return p.state | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) RelatedVersionInfo() procedure.RelatedVersionInfo { | ||
return p.relatedVersionInfo | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) Priority() procedure.Priority { | ||
return p.batch[0].Priority() | ||
} | ||
|
||
func (p *BatchTransferLeaderProcedure) updateStateWithLock(state procedure.State) { | ||
p.lock.Lock() | ||
defer p.lock.Unlock() | ||
|
||
p.state = state | ||
} |
118 changes: 118 additions & 0 deletions
118
server/coordinator/procedure/operation/transferleader/batch_transfer_leader_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright 2023 CeresDB Project Authors. Licensed under Apache-2.0. | ||
|
||
package transferleader_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/CeresDB/ceresmeta/server/coordinator/procedure" | ||
"github.com/CeresDB/ceresmeta/server/coordinator/procedure/operation/transferleader" | ||
"github.com/CeresDB/ceresmeta/server/storage" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
type mockProcedure struct { | ||
ClusterID storage.ClusterID | ||
clusterVersion uint64 | ||
typ procedure.Typ | ||
ShardWithVersion map[storage.ShardID]uint64 | ||
} | ||
|
||
func (m mockProcedure) ID() uint64 { | ||
return 0 | ||
} | ||
|
||
func (m mockProcedure) Typ() procedure.Typ { | ||
return m.typ | ||
} | ||
|
||
func (m mockProcedure) Start(_ context.Context) error { | ||
return nil | ||
} | ||
|
||
func (m mockProcedure) Cancel(_ context.Context) error { | ||
return nil | ||
} | ||
|
||
func (m mockProcedure) State() procedure.State { | ||
return procedure.StateInit | ||
} | ||
|
||
func (m mockProcedure) RelatedVersionInfo() procedure.RelatedVersionInfo { | ||
return procedure.RelatedVersionInfo{ | ||
ClusterID: m.ClusterID, | ||
ShardWithVersion: m.ShardWithVersion, | ||
ClusterVersion: m.clusterVersion, | ||
} | ||
} | ||
|
||
func (m mockProcedure) Priority() procedure.Priority { | ||
return procedure.PriorityLow | ||
} | ||
|
||
func TestBatchProcedure(t *testing.T) { | ||
re := require.New(t) | ||
|
||
var procedures []procedure.Procedure | ||
|
||
// Procedures with same type and version. | ||
for i := 0; i < 3; i++ { | ||
shardWithVersion := map[storage.ShardID]uint64{} | ||
shardWithVersion[storage.ShardID(i)] = 0 | ||
p := mockProcedure{ | ||
ClusterID: 0, | ||
clusterVersion: 0, | ||
typ: 0, | ||
ShardWithVersion: shardWithVersion, | ||
} | ||
procedures = append(procedures, p) | ||
} | ||
_, err := transferleader.NewBatchTransferLeaderProcedure(0, procedures) | ||
re.NoError(err) | ||
|
||
// Procedure with different clusterID | ||
for i := 0; i < 3; i++ { | ||
shardWithVersion := map[storage.ShardID]uint64{} | ||
shardWithVersion[storage.ShardID(i)] = 0 | ||
p := mockProcedure{ | ||
ClusterID: storage.ClusterID(i), | ||
clusterVersion: 0, | ||
typ: procedure.TransferLeader, | ||
ShardWithVersion: shardWithVersion, | ||
} | ||
procedures = append(procedures, p) | ||
} | ||
_, err = transferleader.NewBatchTransferLeaderProcedure(0, procedures) | ||
re.Error(err) | ||
|
||
// Procedures with different type. | ||
for i := 0; i < 3; i++ { | ||
shardWithVersion := map[storage.ShardID]uint64{} | ||
shardWithVersion[storage.ShardID(i)] = 0 | ||
p := mockProcedure{ | ||
ClusterID: 0, | ||
clusterVersion: 0, | ||
typ: procedure.Typ(i), | ||
ShardWithVersion: shardWithVersion, | ||
} | ||
procedures = append(procedures, p) | ||
} | ||
_, err = transferleader.NewBatchTransferLeaderProcedure(0, procedures) | ||
re.Error(err) | ||
|
||
// Procedures with different version. | ||
for i := 0; i < 3; i++ { | ||
shardWithVersion := map[storage.ShardID]uint64{} | ||
shardWithVersion[storage.ShardID(0)] = uint64(i) | ||
p := mockProcedure{ | ||
ClusterID: 0, | ||
clusterVersion: 0, | ||
typ: procedure.Typ(i), | ||
ShardWithVersion: shardWithVersion, | ||
} | ||
procedures = append(procedures, p) | ||
} | ||
_, err = transferleader.NewBatchTransferLeaderProcedure(0, procedures) | ||
re.Error(err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.