forked from JointCloud/pcm-coordinator
79 lines
1.2 KiB
Go
79 lines
1.2 KiB
Go
package weightDistributing
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
)
|
|
|
|
type Weight struct {
|
|
Id string
|
|
Weight int32
|
|
Replica int32
|
|
}
|
|
|
|
func DistributeReplicas(weights []*Weight, replicas int32) error {
|
|
|
|
var weightSum int32
|
|
weightSum = 0
|
|
for _, w := range weights {
|
|
weightSum += w.Weight
|
|
}
|
|
|
|
if weightSum == 0 {
|
|
return errors.New("static weights are empty")
|
|
}
|
|
|
|
weightRatio := make([]float64, len(weights))
|
|
for i, w := range weights {
|
|
weightRatio[i] = float64(w.Weight) / float64(weightSum)
|
|
}
|
|
|
|
var rest = replicas
|
|
|
|
for i := 0; i < len(weights); i++ {
|
|
|
|
var n = math.Round(float64(replicas) * weightRatio[i])
|
|
rest -= int32(n)
|
|
|
|
weights[i].Replica = int32(n)
|
|
}
|
|
|
|
for {
|
|
if rest == 0 {
|
|
break
|
|
}
|
|
|
|
maxIdx := 0
|
|
minIdx := 0
|
|
|
|
if rest > 0 {
|
|
for i, ratio := range weightRatio {
|
|
if ratio > weightRatio[maxIdx] {
|
|
maxIdx = i
|
|
}
|
|
}
|
|
} else {
|
|
for i, ratio := range weightRatio {
|
|
if ratio < weightRatio[minIdx] {
|
|
minIdx = i
|
|
}
|
|
}
|
|
}
|
|
|
|
if rest > 0 {
|
|
weights[maxIdx].Replica++
|
|
weightRatio[maxIdx]--
|
|
rest--
|
|
} else {
|
|
if weights[minIdx].Replica == 0 {
|
|
weightRatio[minIdx]++
|
|
continue
|
|
}
|
|
weights[minIdx].Replica--
|
|
weightRatio[minIdx]++
|
|
rest++
|
|
}
|
|
}
|
|
return nil
|
|
}
|