func (f *StoreStateFilter) Target(opts *config.PersistOptions, store *core.StoreInfo) bool {
	if f.TransferLeader && f.anyConditionMatch(leaderTarget, opts, store) {
		return false
	}
	if f.MoveRegion && f.ScatterRegion && f.anyConditionMatch(scatterRegionTarget, opts, store) {
		return false
	}
	if f.MoveRegion && !f.ScatterRegion && f.anyConditionMatch(regionTarget, opts, store) {
		return false
	}
	return true
}
Target returns true when the store can be selected as the schedule
target.
package filter
import (
	"fmt"
	"strconv"
	"github.com/golang/protobuf/proto"
	"github.com/pingcap/kvproto/pkg/metapb"
	"github.com/pingcap/log"
	"github.com/tikv/pd/pkg/slice"
	"github.com/tikv/pd/server/config"
	"github.com/tikv/pd/server/core"
	"github.com/tikv/pd/server/core/storelimit"
	"github.com/tikv/pd/server/schedule/opt"
	"github.com/tikv/pd/server/schedule/placement"
	"go.uber.org/zap"
)
func SelectSourceStores(stores []*core.StoreInfo, filters []Filter, opt *config.PersistOptions) []*core.StoreInfo {
	return filterStoresBy(stores, func(s *core.StoreInfo) bool {
		return slice.AllOf(filters, func(i int) bool {
			if !filters[i].Source(opt, s) {
				sourceID := strconv.FormatUint(s.GetID(), 10)
				targetID := ""
				filterCounter.WithLabelValues("filter-source", s.GetAddress(),
					sourceID, filters[i].Scope(), filters[i].Type(), sourceID, targetID).Inc()
				return false
			}
			return true
		})
	})
}
func SelectTargetStores(stores []*core.StoreInfo, filters []Filter, opt *config.PersistOptions) []*core.StoreInfo {
	return filterStoresBy(stores, func(s *core.StoreInfo) bool {
		return slice.AllOf(filters, func(i int) bool {
			filter := filters[i]
			if !filter.Target(opt, s) {
				cfilter, ok := filter.(comparingFilter)
				targetID := strconv.FormatUint(s.GetID(), 10)
				sourceID := ""
				if ok {
					sourceID = strconv.FormatUint(cfilter.GetSourceStoreID(), 10)
				}
				filterCounter.WithLabelValues("filter-target", s.GetAddress(),
					targetID, filters[i].Scope(), filters[i].Type(), sourceID, targetID).Inc()
				return false
			}
			return true
		})
	})
}
func filterStoresBy(stores []*core.StoreInfo, keepPred func(*core.StoreInfo) bool) (selected []*core.StoreInfo) {
	for _, s := range stores {
		if keepPred(s) {
			selected = append(selected, s)
		}
	}
	return
}
type Filter interface {
	Scope() string
	Type() string
	Source(opt *config.PersistOptions, store *core.StoreInfo) bool
	Target(opt *config.PersistOptions, store *core.StoreInfo) bool
}
type comparingFilter interface {
	Filter
	GetSourceStoreID() uint64
}
func Source(opt *config.PersistOptions, store *core.StoreInfo, filters []Filter) bool {
	storeAddress := store.GetAddress()
	storeID := strconv.FormatUint(store.GetID(), 10)
	for _, filter := range filters {
		if !filter.Source(opt, store) {
			sourceID := storeID
			targetID := ""
			filterCounter.WithLabelValues("filter-source", storeAddress,
				sourceID, filter.Scope(), filter.Type(), sourceID, targetID).Inc()
			return false
		}
	}
	return true
}
func Target(opt *config.PersistOptions, store *core.StoreInfo, filters []Filter) bool {
	storeAddress := store.GetAddress()
	storeID := strconv.FormatUint(store.GetID(), 10)
	for _, filter := range filters {
		if !filter.Target(opt, store) {
			cfilter, ok := filter.(comparingFilter)
			targetID := storeID
			sourceID := ""
			if ok {
				sourceID = strconv.FormatUint(cfilter.GetSourceStoreID(), 10)
			}
			filterCounter.WithLabelValues("filter-target", storeAddress,
				targetID, filter.Scope(), filter.Type(), sourceID, targetID).Inc()
			return false
		}
	}
	return true
}
type excludedFilter struct {
	scope   string
	sources map[uint64]struct{}
	targets map[uint64]struct{}
}
func NewExcludedFilter(scope string, sources, targets map[uint64]struct{}) Filter {
	return &excludedFilter{
		scope:   scope,
		sources: sources,
		targets: targets,
	}
}
func (f *excludedFilter) Scope() string {
	return f.scope
}
func (f *excludedFilter) Type() string {
	return "exclude-filter"
}
func (f *excludedFilter) Source(opt *config.PersistOptions, store *core.StoreInfo) bool {
	_, ok := f.sources[store.GetID()]
	return !ok
}
func (f *excludedFilter) Target(opt *config.PersistOptions, store *core.StoreInfo) bool {
	_, ok := f.targets[store.GetID()]
	return !ok
}
type storageThresholdFilter struct{ scope string }
func NewStorageThresholdFilter(scope string) Filter {
	return &storageThresholdFilter{scope: scope}
}
func (f *storageThresholdFilter) Scope() string {
	return f.scope
}
func (f *storageThresholdFilter) Type() string {
	return "storage-threshold-filter"
}
func (f *storageThresholdFilter) Source(opt *config.PersistOptions, store *core.StoreInfo) bool {
	return true
}
func (f *storageThresholdFilter) Target(opt *config.PersistOptions, store *core.StoreInfo) bool {
	return !store.IsLowSpace(opt.GetLowSpaceRatio())
}
type distinctScoreFilter struct {
	scope     string
	labels    []string
	stores    []*core.StoreInfo
	policy    string
	safeScore float64
	srcStore  uint64
}
const (
	locationSafeguard = "safeguard"
	locationImprove   = "improve"
)
func NewLocationSafeguard(scope string, labels []string, stores []*core.StoreInfo, source *core.StoreInfo) Filter {
	return newDistinctScoreFilter(scope, labels, stores, source, locationSafeguard)
}
func NewLocationImprover(scope string, labels []string, stores []*core.StoreInfo, source *core.StoreInfo) Filter {
	return newDistinctScoreFilter(scope, labels, stores, source, locationImprove)
}
func newDistinctScoreFilter(scope string, labels []string, stores []*core.StoreInfo, source *core.StoreInfo, policy string) Filter {
	newStores := make([]*core.StoreInfo, 0, len(stores)-1)
	for _, s := range stores {
		if s.GetID() == source.GetID() {
			continue
		}
		newStores = append(newStores, s)
	}
	return &distinctScoreFilter{
		scope:     scope,
		labels:    labels,
		stores:    newStores,
		safeScore: core.DistinctScore(labels, newStores, source),
		policy:    policy,
		srcStore:  source.GetID(),
	}
}
func (f *distinctScoreFilter) Scope() string {
	return f.scope
}
func (f *distinctScoreFilter) Type() string {
	return "distinct-filter"
}
func (f *distinctScoreFilter) Source(opt *config.PersistOptions, store *core.StoreInfo) bool {
	return true
}
func (f *distinctScoreFilter) Target(opt *config.PersistOptions, store *core.StoreInfo) bool {
	score := core.DistinctScore(f.labels, f.stores, store)
	switch f.policy {
	case locationSafeguard:
		return score >= f.safeScore
	case locationImprove:
		return score > f.safeScore
	default:
		return false
	}
}
func (f *distinctScoreFilter) GetSourceStoreID() uint64 {
	return f.srcStore
}
type StoreStateFilter struct {
	ActionScope string
	TransferLeader bool
	MoveRegion bool
	ScatterRegion bool
	AllowTemporaryStates bool
	Reason string
}
func (f *StoreStateFilter) Scope() string {
	return f.ActionScope
}
func (f *StoreStateFilter) Type() string {
	return fmt.Sprintf("store-state-%s-filter", f.Reason)
}
type conditionFunc func(*config.PersistOptions, *core.StoreInfo) bool
func (f *StoreStateFilter) isTombstone(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "tombstone"
	return store.IsTombstone()
}
func (f *StoreStateFilter) isDown(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "down"
	return store.DownTime() > opt.GetMaxStoreDownTime()
}
func (f *StoreStateFilter) isOffline(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "offline"
	return store.IsOffline()
}
func (f *StoreStateFilter) pauseLeaderTransfer(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "pause-leader"
	return !store.AllowLeaderTransfer()
}
func (f *StoreStateFilter) slowStoreEvicted(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "slow-store"
	return store.EvictedAsSlowStore()
}
func (f *StoreStateFilter) isDisconnected(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "disconnected"
	return !f.AllowTemporaryStates && store.IsDisconnected()
}
func (f *StoreStateFilter) isBusy(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "busy"
	return !f.AllowTemporaryStates && store.IsBusy()
}
func (f *StoreStateFilter) exceedRemoveLimit(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "exceed-remove-limit"
	return !f.AllowTemporaryStates && !store.IsAvailable(storelimit.RemovePeer)
}
func (f *StoreStateFilter) exceedAddLimit(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "exceed-add-limit"
	return !f.AllowTemporaryStates && !store.IsAvailable(storelimit.AddPeer)
}
func (f *StoreStateFilter) tooManySnapshots(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "too-many-snapshot"
	return !f.AllowTemporaryStates && (uint64(store.GetSendingSnapCount()) > opt.GetMaxSnapshotCount() ||
		uint64(store.GetReceivingSnapCount()) > opt.GetMaxSnapshotCount())
}
func (f *StoreStateFilter) tooManyPendingPeers(opt *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "too-many-pending-peer"
	return !f.AllowTemporaryStates &&
		opt.GetMaxPendingPeerCount() > 0 &&
		store.GetPendingPeerCount() > int(opt.GetMaxPendingPeerCount())
}
func (f *StoreStateFilter) hasRejectLeaderProperty(opts *config.PersistOptions, store *core.StoreInfo) bool {
	f.Reason = "reject-leader"
	return opts.CheckLabelProperty(opt.RejectLeader, store.GetLabels())
}
const (
	leaderSource = iota
	regionSource
	leaderTarget
	regionTarget
	scatterRegionTarget
)
func (f *StoreStateFilter) anyConditionMatch(typ int, opt *config.PersistOptions, store *core.StoreInfo) bool {
	var funcs []conditionFunc
	switch typ {
	case leaderSource:
		funcs = []conditionFunc{f.isTombstone, f.isDown, f.pauseLeaderTransfer, f.isDisconnected}
	case regionSource:
		funcs = []conditionFunc{f.isBusy, f.exceedRemoveLimit, f.tooManySnapshots}
	case leaderTarget:
		funcs = []conditionFunc{f.isTombstone, f.isOffline, f.isDown, f.pauseLeaderTransfer,
			f.slowStoreEvicted, f.isDisconnected, f.isBusy, f.hasRejectLeaderProperty}
	case regionTarget:
		funcs = []conditionFunc{f.isTombstone, f.isOffline, f.isDown, f.isDisconnected, f.isBusy,
			f.exceedAddLimit, f.tooManySnapshots, f.tooManyPendingPeers}
	case scatterRegionTarget:
		funcs = []conditionFunc{f.isTombstone, f.isOffline, f.isDown, f.isDisconnected, f.isBusy}
	}
	for _, cf := range funcs {
		if cf(opt, store) {
			return true
		}
	}
	return false
}
func (f *StoreStateFilter) Source(opts *config.PersistOptions, store *core.StoreInfo) bool {
	if f.TransferLeader && f.anyConditionMatch(leaderSource, opts, store) {
		return false
	}
	if f.MoveRegion && f.anyConditionMatch(regionSource, opts, store) {
		return false
	}
	return true
}