func (s *StoreInfo) ResourceWeight(kind ResourceKind) float64 {
	switch kind {
	case LeaderKind:
		leaderWeight := s.GetLeaderWeight()
		if leaderWeight <= 0 {
			return minWeight
		}
		return leaderWeight
	case RegionKind:
		regionWeight := s.GetRegionWeight()
		if regionWeight <= 0 {
			return minWeight
		}
		return regionWeight
	default:
		return 0
	}
}
ResourceWeight returns weight of leader/region in the score
package core
import (
	"math"
	"strings"
	"time"
	"github.com/gogo/protobuf/proto"
	"github.com/pingcap/kvproto/pkg/metapb"
	"github.com/pingcap/log"
	"github.com/tikv/pd/pkg/errs"
	"github.com/tikv/pd/server/core/storelimit"
	"go.uber.org/zap"
)
const (
	storePersistInterval   = 5 * time.Minute
	mb                     = 1 << 20  
	gb                     = 1 << 30  
	initialMaxRegionCounts = 30       
	initialMinSpace        = 1 << 33  
	slowStoreThreshold     = 80
	EngineKey = "engine"
	EngineTiFlash = "tiflash"
	EngineTiKV = "tikv"
)
type StoreInfo struct {
	meta *metapb.Store
	*storeStats
	pauseLeaderTransfer bool  
	slowStoreEvicted    bool  
	leaderCount         int
	regionCount         int
	leaderSize          int64
	regionSize          int64
	pendingPeerCount    int
	lastPersistTime     time.Time
	leaderWeight        float64
	regionWeight        float64
	limiter             map[storelimit.Type]*storelimit.StoreLimit
}
func NewStoreInfo(store *metapb.Store, opts ...StoreCreateOption) *StoreInfo {
	storeInfo := &StoreInfo{
		meta:         store,
		storeStats:   newStoreStats(),
		leaderWeight: 1.0,
		regionWeight: 1.0,
		limiter:      make(map[storelimit.Type]*storelimit.StoreLimit),
	}
	for _, opt := range opts {
		opt(storeInfo)
	}
	return storeInfo
}
func (s *StoreInfo) Clone(opts ...StoreCreateOption) *StoreInfo {
	meta := proto.Clone(s.meta).(*metapb.Store)
	store := &StoreInfo{
		meta:                meta,
		storeStats:          s.storeStats,
		pauseLeaderTransfer: s.pauseLeaderTransfer,
		slowStoreEvicted:    s.slowStoreEvicted,
		leaderCount:         s.leaderCount,
		regionCount:         s.regionCount,
		leaderSize:          s.leaderSize,
		regionSize:          s.regionSize,
		pendingPeerCount:    s.pendingPeerCount,
		lastPersistTime:     s.lastPersistTime,
		leaderWeight:        s.leaderWeight,
		regionWeight:        s.regionWeight,
		limiter:             s.limiter,
	}
	for _, opt := range opts {
		opt(store)
	}
	return store
}
func (s *StoreInfo) ShallowClone(opts ...StoreCreateOption) *StoreInfo {
	store := &StoreInfo{
		meta:                s.meta,
		storeStats:          s.storeStats,
		pauseLeaderTransfer: s.pauseLeaderTransfer,
		slowStoreEvicted:    s.slowStoreEvicted,
		leaderCount:         s.leaderCount,
		regionCount:         s.regionCount,
		leaderSize:          s.leaderSize,
		regionSize:          s.regionSize,
		pendingPeerCount:    s.pendingPeerCount,
		lastPersistTime:     s.lastPersistTime,
		leaderWeight:        s.leaderWeight,
		regionWeight:        s.regionWeight,
		limiter:             s.limiter,
	}
	for _, opt := range opts {
		opt(store)
	}
	return store
}
func (s *StoreInfo) AllowLeaderTransfer() bool {
	return !s.pauseLeaderTransfer
}
func (s *StoreInfo) EvictedAsSlowStore() bool {
	return s.slowStoreEvicted
}
func (s *StoreInfo) IsAvailable(limitType storelimit.Type) bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	if s.limiter != nil && s.limiter[limitType] != nil {
		return s.limiter[limitType].Available() >= storelimit.RegionInfluence[limitType]
	}
	return true
}
func (s *StoreInfo) IsUp() bool {
	return s.GetState() == metapb.StoreState_Up
}
func (s *StoreInfo) IsOffline() bool {
	return s.GetState() == metapb.StoreState_Offline
}
func (s *StoreInfo) IsTombstone() bool {
	return s.GetState() == metapb.StoreState_Tombstone
}
func (s *StoreInfo) GetSlowScore() uint64 {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.rawStats.GetSlowScore()
}
func (s *StoreInfo) IsSlow() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.rawStats.GetSlowScore() >= slowStoreThreshold
}
func (s *StoreInfo) IsPhysicallyDestroyed() bool {
	return s.GetMeta().GetPhysicallyDestroyed()
}
func (s *StoreInfo) DownTime() time.Duration {
	return time.Since(s.GetLastHeartbeatTS())
}
func (s *StoreInfo) GetMeta() *metapb.Store {
	return s.meta
}
func (s *StoreInfo) GetState() metapb.StoreState {
	return s.meta.GetState()
}
func (s *StoreInfo) GetAddress() string {
	return s.meta.GetAddress()
}
func (s *StoreInfo) GetVersion() string {
	return s.meta.GetVersion()
}
func (s *StoreInfo) GetLabels() []*metapb.StoreLabel {
	return s.meta.GetLabels()
}
func (s *StoreInfo) GetID() uint64 {
	return s.meta.GetId()
}
func (s *StoreInfo) GetLeaderCount() int {
	return s.leaderCount
}
func (s *StoreInfo) GetRegionCount() int {
	return s.regionCount
}
func (s *StoreInfo) GetLeaderSize() int64 {
	return s.leaderSize
}
func (s *StoreInfo) GetRegionSize() int64 {
	return s.regionSize
}
func (s *StoreInfo) GetPendingPeerCount() int {
	return s.pendingPeerCount
}
func (s *StoreInfo) GetLeaderWeight() float64 {
	return s.leaderWeight
}
func (s *StoreInfo) GetRegionWeight() float64 {
	return s.regionWeight
}
func (s *StoreInfo) GetLastHeartbeatTS() time.Time {
	return time.Unix(0, s.meta.GetLastHeartbeat())
}
func (s *StoreInfo) NeedPersist() bool {
	return s.GetLastHeartbeatTS().Sub(s.lastPersistTime) > storePersistInterval
}
func (s *StoreInfo) GetStoreLimit(limitType storelimit.Type) *storelimit.StoreLimit {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.limiter[limitType]
}
const minWeight = 1e-6
const maxScore = 1024 * 1024 * 1024
func (s *StoreInfo) LeaderScore(policy SchedulePolicy, delta int64) float64 {
	switch policy {
	case BySize:
		return float64(s.GetLeaderSize()+delta) / math.Max(s.GetLeaderWeight(), minWeight)
	case ByCount:
		return float64(int64(s.GetLeaderCount())+delta) / math.Max(s.GetLeaderWeight(), minWeight)
	default:
		return 0
	}
}
func (s *StoreInfo) RegionScore(version string, highSpaceRatio, lowSpaceRatio float64, delta int64) float64 {
	switch version {
	case "v2":
		return s.regionScoreV2(delta, lowSpaceRatio)
	case "v1":
		fallthrough
	default:
		return s.regionScoreV1(highSpaceRatio, lowSpaceRatio, delta)
	}
}
func (s *StoreInfo) regionScoreV1(highSpaceRatio, lowSpaceRatio float64, delta int64) float64 {
	var score float64
	var amplification float64
	available := float64(s.GetAvailable()) / mb
	used := float64(s.GetUsedSize()) / mb
	capacity := float64(s.GetCapacity()) / mb
	if s.GetRegionSize() == 0 || used == 0 {
		amplification = 1
	} else {
		amplification = float64(s.GetRegionSize()) / used
	}
	highSpaceBound := (1 - highSpaceRatio) * capacity
	lowSpaceBound := (1 - lowSpaceRatio) * capacity
	if available-float64(delta)/amplification >= highSpaceBound {
		score = float64(s.GetRegionSize() + delta)
	} else if available-float64(delta)/amplification <= lowSpaceBound {
		score = maxScore - (available - float64(delta)/amplification)
	} else {
		x1, y1 := (used+available-highSpaceBound)*amplification, (used+available-highSpaceBound)*amplification
		x2, y2 := (used+available-lowSpaceBound)*amplification, maxScore-lowSpaceBound
		k := (y2 - y1) / (x2 - x1)
		b := y1 - k*x1
		score = k*float64(s.GetRegionSize()+delta) + b
	}
	return score / math.Max(s.GetRegionWeight(), minWeight)
}
func (s *StoreInfo) regionScoreV2(delta int64, lowSpaceRatio float64) float64 {
	A := float64(s.GetAvgAvailable())
	C := float64(s.GetCapacity()) / gb
	R := float64(s.GetRegionSize() + delta)
	if R < 0 {
		R = float64(s.GetRegionSize())
	}
	U := C - A
	if s.GetRegionSize() != 0 {
		U = U + U*(float64(delta))/float64(s.GetRegionSize())
		if U < C && U > 0 {
			A = C - U
		}
	}
	var (
		K, M float64 = 1, 256  
		F    float64 = 50      
		B            = 1e7
	)
	F = math.Max(F, C*(1-lowSpaceRatio))
	var score float64
	if A >= C || C < 1 {
		score = R
	} else if A > F {
		score = (K + M*(math.Log(C)-math.Log(A-F+1))/(C-A+F-1)) * R
	} else {
		score = (K+M*math.Log(C)/C)*R + B*(F-A)/F
	}
	return score / math.Max(s.GetRegionWeight(), minWeight)
}
func (s *StoreInfo) StorageSize() uint64 {
	return s.GetUsedSize()
}
func (s *StoreInfo) AvailableRatio() float64 {
	if s.GetCapacity() == 0 {
		return 0
	}
	return float64(s.GetAvailable()) / float64(s.GetCapacity())
}
func (s *StoreInfo) IsLowSpace(lowSpaceRatio float64) bool {
	if s.GetStoreStats() == nil {
		return false
	}
	if s.regionCount < initialMaxRegionCounts && s.GetAvailable() > initialMinSpace {
		return false
	}
	return s.AvailableRatio() < 1-lowSpaceRatio
}
func (s *StoreInfo) ResourceCount(kind ResourceKind) uint64 {
	switch kind {
	case LeaderKind:
		return uint64(s.GetLeaderCount())
	case RegionKind:
		return uint64(s.GetRegionCount())
	default:
		return 0
	}
}
func (s *StoreInfo) ResourceSize(kind ResourceKind) int64 {
	switch kind {
	case LeaderKind:
		return s.GetLeaderSize()
	case RegionKind:
		return s.GetRegionSize()
	default:
		return 0
	}
}