diff --git a/server/schedule/filter/filters.go b/server/schedule/filter/filters.go index bcac4c4aff7..631b1338ef9 100644 --- a/server/schedule/filter/filters.go +++ b/server/schedule/filter/filters.go @@ -543,12 +543,51 @@ func (f *ruleFitFilter) Target(opt opt.Options, store *core.StoreInfo) bool { return placement.CompareRegionFit(f.oldFit, newFit) <= 0 } +type engineFilter struct { + scope string + constraint placement.LabelConstraint +} + +// NewEngineFilter creates a filter that filters out default engine stores. +// By default, all stores that are not marked with a special engine will be filtered out. +// Specify the special engine label if you want to include the special stores. +func NewEngineFilter(scope string, allowEngines ...string) Filter { + var values []string + for _, v := range allSpeicalEngines { + if slice.NoneOf(allowEngines, func(i int) bool { return allowEngines[i] == v }) { + values = append(values, v) + } + } + return &engineFilter{ + scope: scope, + constraint: placement.LabelConstraint{Key: "engine", Op: "notIn", Values: values}, + } +} + +func (f *engineFilter) Scope() string { + return f.scope +} + +func (f *engineFilter) Type() string { + return "engine-filter" +} + +func (f *engineFilter) Source(opt opt.Options, store *core.StoreInfo) bool { + return f.constraint.MatchStore(store) +} + +func (f *engineFilter) Target(opt opt.Options, store *core.StoreInfo) bool { + return f.constraint.MatchStore(store) +} + type specialUseFilter struct { scope string constraint placement.LabelConstraint } -// NewSpecialUseFilter creates a filter that filters stores for special use. +// NewSpecialUseFilter creates a filter that filters out normal stores. +// By default, all stores that are not marked with a special use will be filtered out. +// Specify the special use label if you want to include the special stores. func NewSpecialUseFilter(scope string, allowUses ...string) Filter { var values []string for _, v := range allSpecialUses { @@ -558,7 +597,7 @@ func NewSpecialUseFilter(scope string, allowUses ...string) Filter { } return &specialUseFilter{ scope: scope, - constraint: placement.LabelConstraint{Key: specialUseKey, Op: "in", Values: values}, + constraint: placement.LabelConstraint{Key: SpecialUseKey, Op: "in", Values: values}, } } @@ -582,11 +621,18 @@ func (f *specialUseFilter) Target(opt opt.Options, store *core.StoreInfo) bool { } const ( - specialUseKey = "specialUse" + // SpecialUseKey is the label used to indicate special use storage. + SpecialUseKey = "specialUse" // SpecialUseHotRegion is the hot region value of special use label SpecialUseHotRegion = "hotRegion" // SpecialUseReserved is the reserved value of special use label SpecialUseReserved = "reserved" + + // EngineKey is the label key used to indicate engine. + EngineKey = "engine" + // EngineTiFlash is the tiflash value of the engine label. + EngineTiFlash = "tiflash" ) var allSpecialUses = []string{SpecialUseHotRegion, SpecialUseReserved} +var allSpeicalEngines = []string{EngineTiFlash} diff --git a/server/schedule/region_scatterer.go b/server/schedule/region_scatterer.go index d12aad0b904..a7759dbbf0c 100644 --- a/server/schedule/region_scatterer.go +++ b/server/schedule/region_scatterer.go @@ -82,6 +82,7 @@ func NewRegionScatterer(cluster opt.Cluster) *RegionScatterer { cluster: cluster, filters: []filter.Filter{ filter.StoreStateFilter{ActionScope: regionScatterName}, + filter.NewEngineFilter(regionScatterName), }, selected: newSelectedStores(), } diff --git a/server/schedulers/scheduler_test.go b/server/schedulers/scheduler_test.go index b6f50709acc..da54e478115 100644 --- a/server/schedulers/scheduler_test.go +++ b/server/schedulers/scheduler_test.go @@ -189,11 +189,13 @@ var _ = Suite(&testScatterRegionSuite{}) type testScatterRegionSuite struct{} func (s *testScatterRegionSuite) TestSixStores(c *C) { - s.scatter(c, 6, 4) + s.scatter(c, 6, 4, false) + s.scatter(c, 6, 4, true) } func (s *testScatterRegionSuite) TestFiveStores(c *C) { - s.scatter(c, 5, 5) + s.scatter(c, 5, 5, false) + s.scatter(c, 5, 5, true) } func (s *testScatterRegionSuite) checkOperator(op *operator.Operator, c *C) { @@ -209,7 +211,7 @@ func (s *testScatterRegionSuite) checkOperator(op *operator.Operator, c *C) { } } -func (s *testScatterRegionSuite) scatter(c *C, numStores, numRegions uint64) { +func (s *testScatterRegionSuite) scatter(c *C, numStores, numRegions uint64, useRules bool) { opt := mockoption.NewScheduleOptions() tc := mockcluster.NewCluster(opt) @@ -217,6 +219,8 @@ func (s *testScatterRegionSuite) scatter(c *C, numStores, numRegions uint64) { for i := uint64(1); i <= numStores; i++ { tc.AddRegionStore(i, 0) } + tc.AddLabelsStore(numStores+1, 0, map[string]string{"engine": "tiflash"}) + tc.EnablePlacementRules = useRules // Add regions 1~4. seq := newSequencer(3) diff --git a/server/util.go b/server/util.go index 564eb872d77..45e11a706ff 100644 --- a/server/util.go +++ b/server/util.go @@ -183,6 +183,8 @@ func checkBootstrapRequest(clusterID uint64, req *pdpb.BootstrapRequest) error { return nil } +// isTiFlashStore used to judge flash store. +// FIXME: remove the hack way func isTiFlashStore(store *metapb.Store) bool { for _, l := range store.GetLabels() { if l.GetKey() == "engine" && l.GetValue() == "tiflash" {