in pkg/scheduler/framework/plugins/clusteraffinity/types.go [215:283]
func interpolateWeightFor(cluster *clusterv1beta1.MemberCluster, property string, sortOrder placementv1beta1.PropertySortOrder, weight int32, state *pluginState) (int32, error) {
q, err := retrievePropertyValueFrom(cluster, property)
if err != nil {
return 0, fmt.Errorf("failed to perform weight interpolation based on %s for cluster %s: %w", property, cluster.Name, err)
}
if q == nil {
// The property is not available for the cluster.
return 0, nil
}
// Read the pre-prepared min/max values from the state, calculated in the PreScore stage.
mm, ok := state.minMaxValuesByProperty[property]
if !ok {
return 0, fmt.Errorf("failed to look up extremums for property %s, no state is prepared", property)
}
if mm.min == nil || mm.max == nil {
// The extremums are not available; this can happen when none of the clusters support
// the property.
//
// Normally this will never occur as the check before has guaranteed that at least
// observation has been made.
return 0, fmt.Errorf("extremums for property %s are not available, yet a reading can be found from cluster %s", property, cluster.Name)
}
minQ, maxQ := mm.min, mm.max
// Cast the quantities as floats to allow ratio estimation.
//
// This conversion will incur precision loss, though in most cases such loss has very limited
// impact.
f := q.AsApproximateFloat64()
minF := minQ.AsApproximateFloat64()
maxF := maxQ.AsApproximateFloat64()
// Do a sanity check to ensure correctness.
//
// Normally this check would never fail.
isInvalid := (math.IsInf(minF, 0) ||
math.IsInf(maxF, 0) ||
minF > maxF ||
f < minF ||
f > maxF)
if isInvalid {
return 0, fmt.Errorf("cannot interpolate weight, observed value %v, observed min %v, observed max %v", f, minF, maxF)
}
if minF == maxF {
// Process a corner case where the specified property is of the same value across all
// clusters. This is not an invalid case, however, it would result in a NaN output in
// the weight interpolation step if left unchecked (as the value is the minimum and
// the maximum at the same time), which might lead to confusion on the user end.
//
// In this case, we would assign a weight of 0.
return 0, nil
}
switch sortOrder {
case placementv1beta1.Descending:
w := ((f - minF) / (maxF - minF)) * float64(weight)
// Round the value.
return int32(math.Round(w)), nil
case placementv1beta1.Ascending:
w := (1 - (f-minF)/(maxF-minF)) * float64(weight)
// Round the value.
return int32(math.Round(w)), nil
default:
// An invalid sort order is present. Normally this should never occur.
return 0, fmt.Errorf("cannot interpolate weight as sort order %s is invalid", sortOrder)
}
}