diff --git a/server/schedule/filter/filters.go b/server/schedule/filter/filters.go index 8c2fa586e920..93f4631092cd 100644 --- a/server/schedule/filter/filters.go +++ b/server/schedule/filter/filters.go @@ -16,6 +16,7 @@ package filter import ( "fmt" + "github.com/pingcap/kvproto/pkg/metapb" "github.com/pingcap/log" "github.com/tikv/pd/pkg/slice" "github.com/tikv/pd/server/core" @@ -425,7 +426,9 @@ func (f *ruleFitFilter) Source(opt opt.Options, store *core.StoreInfo) bool { } func (f *ruleFitFilter) Target(opt opt.Options, store *core.StoreInfo) bool { - region := f.region.Clone(core.WithReplacePeerStore(f.oldStore, store.GetID())) + region := createRegionForRuleFit(f.region.GetStartKey(), f.region.GetEndKey(), + f.region.GetPeers(), f.region.GetLeader(), + core.WithReplacePeerStore(f.oldStore, store.GetID())) newFit := f.fitter.FitRegion(region) return placement.CompareRegionFit(f.oldFit, newFit) <= 0 } @@ -468,8 +471,10 @@ func (f *ruleLeaderFitFilter) Target(opt opt.Options, store *core.StoreInfo) boo log.Warn("ruleLeaderFitFilter couldn't find peer on target Store", zap.Uint64("target-store", store.GetID())) return false } - region := f.region.Clone(core.WithLeader(targetPeer)) - newFit := f.fitter.FitRegion(region) + copyRegion := createRegionForRuleFit(f.region.GetStartKey(), f.region.GetEndKey(), + f.region.GetPeers(), f.region.GetLeader(), + core.WithLeader(targetPeer)) + newFit := f.fitter.FitRegion(copyRegion) return placement.CompareRegionFit(f.oldFit, newFit) <= 0 } @@ -672,3 +677,29 @@ func (f *isolationFilter) Target(opt opt.Options, store *core.StoreInfo) bool { } return true } + +// createRegionForRuleFit is used to create a clone region with RegionCreateOptions which is only used for +// FitRegion in filter +func createRegionForRuleFit(startKey, endKey []byte, + peers []*metapb.Peer, leader *metapb.Peer, opts ...core.RegionCreateOption) *core.RegionInfo { + copyLeader := &metapb.Peer{ + Id: leader.Id, + StoreId: leader.StoreId, + Role: leader.Role, + } + copyPeers := make([]*metapb.Peer, 0, len(peers)) + for _, p := range peers { + peer := &metapb.Peer{ + Id: p.Id, + StoreId: p.StoreId, + Role: p.Role, + } + copyPeers = append(copyPeers, peer) + } + cloneRegion := core.NewRegionInfo(&metapb.Region{ + StartKey: startKey, + EndKey: endKey, + Peers: copyPeers, + }, copyLeader, opts...) + return cloneRegion +} diff --git a/server/schedule/filter/filters_test.go b/server/schedule/filter/filters_test.go index 2fcc99fbfc4a..3672ca76e989 100644 --- a/server/schedule/filter/filters_test.go +++ b/server/schedule/filter/filters_test.go @@ -272,3 +272,28 @@ func (s *testFiltersSuite) TestPlacementGuard(c *C) { FitsTypeOf, newRuleFitFilter("", testCluster, region, 1)) } + +func BenchmarkCloneRegionTest(b *testing.B) { + epoch := &metapb.RegionEpoch{ + ConfVer: 1, + Version: 1, + } + region := core.NewRegionInfo( + &metapb.Region{ + Id: 4, + StartKey: []byte("x"), + EndKey: []byte(""), + Peers: []*metapb.Peer{ + {Id: 108, StoreId: 4}, + }, + RegionEpoch: epoch, + }, + &metapb.Peer{Id: 108, StoreId: 4}, + core.SetApproximateSize(50), + core.SetApproximateKeys(20), + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = createRegionForRuleFit(region.GetStartKey(), region.GetEndKey(), region.GetPeers(), region.GetLeader()) + } +}