func normalizeWeights(subConns map[resolver.Address]*subConn) (_ []subConnWithWeight, min float64, _ error) {
	if len(subConns) == 0 {
		return nil, 0, fmt.Errorf("number of subconns is 0")
	}
	var weightSum uint32
	for a := range subConns {
		weightSum += a.Metadata.(uint32)
	}
	if weightSum == 0 {
		return nil, 0, fmt.Errorf("total weight of all subconns is 0")
	}
	weightSumF := float64(weightSum)
	ret := make([]subConnWithWeight, 0, len(subConns))
	min = math.MaxFloat64
	for a, sc := range subConns {
		nw := float64(a.Metadata.(uint32)) / weightSumF
		ret = append(ret, subConnWithWeight{sc: sc, weight: nw})
		if nw < min {
			min = nw
		}
	}
	sort.Slice(ret, func(i, j int) bool { return ret[i].sc.addr < ret[j].sc.addr })
	return ret, min, nil
}
normalizeWeights divides all the weights by the sum, so that the total weight
is 1.
package ringhash
import (
	"fmt"
	"math"
	"sort"
	"strconv"
	xxhash "github.com/cespare/xxhash/v2"
	"google.golang.org/grpc/resolver"
)
type ring struct {
	items []*ringEntry
}
type subConnWithWeight struct {
	sc     *subConn
	weight float64
}
type ringEntry struct {
	idx  int
	hash uint64
	sc   *subConn
}
func newRing(subConns map[resolver.Address]*subConn, minRingSize, maxRingSize uint64) (*ring, error) {
	normalizedWeights, minWeight, err := normalizeWeights(subConns)
	if err != nil {
		return nil, err
	}
	scale := math.Min(math.Ceil(minWeight*float64(minRingSize))/minWeight, float64(maxRingSize))
	ringSize := math.Ceil(scale)
	items := make([]*ringEntry, 0, int(ringSize))
	var (
		idx       int
		targetIdx float64
	)
	for _, scw := range normalizedWeights {
		targetIdx += scale * scw.weight
		for float64(idx) < targetIdx {
			h := xxhash.Sum64String(scw.sc.addr + strconv.Itoa(len(items)))
			items = append(items, &ringEntry{idx: idx, hash: h, sc: scw.sc})
			idx++
		}
	}
	sort.Slice(items, func(i, j int) bool { return items[i].hash < items[j].hash })
	for i, ii := range items {
		ii.idx = i
	}
	return &ring{items: items}, nil
}