crushkv/crush/selector_hashing.go

116 lines
2.4 KiB
Go
Raw Permalink Normal View History

package crush
import (
"bytes"
"crypto/sha1"
"encoding/binary"
"sort"
)
type HashingSelector struct {
tokenList tokenList
tokenMap map[uint32]Node
}
func NewHashingSelector(n Node) *HashingSelector {
var h = new(HashingSelector)
var nodes = n.GetChildren()
var maxWeight float32
for _, node := range nodes {
maxWeight = Max64(maxWeight, node.GetWeight())
}
h.tokenMap = make(map[uint32]Node)
for _, node := range nodes {
count := 500 * node.GetWeight() / maxWeight
var hash []byte
for i := float32(0); i < count; i++ {
var input []byte
if len(hash) == 0 {
input = []byte(node.GetID())
} else {
input = hash
}
hash = digestBytes(input)
token := Btoi(hash)
if _, ok := h.tokenMap[token]; !ok {
h.tokenMap[token] = node
}
}
}
h.tokenList = make([]uint32, 0, len(h.tokenMap))
for k := range h.tokenMap {
h.tokenList = append(h.tokenList, k)
}
sort.Sort(h.tokenList)
return h
}
type tokenList []uint32
func (t tokenList) Len() int {
return len(t)
}
func (t tokenList) Less(i, j int) bool {
return t[i] < t[j]
}
func (t tokenList) Swap(i, j int) {
t[i], t[j] = t[j], t[i]
}
func Max64(a float32, b float32) float32 {
if a > b {
return a
}
return b
}
func digestInt64(input int64) []byte {
buf := new(bytes.Buffer)
binary.Write(buf, binary.LittleEndian, input)
bytes := buf.Bytes()
result := sha1.Sum(bytes)
hash := make([]byte, 20)
copy(hash[:], result[:20])
return hash
}
func digestBytes(input []byte) []byte {
result := sha1.Sum(input)
hash := make([]byte, 20)
copy(hash[:], result[:20])
return hash
}
func digestString(input string) []byte {
result := sha1.Sum([]byte(input))
hash := make([]byte, 20)
copy(hash[:], result[:20])
return hash
}
func Btoi(b []byte) uint32 {
var result uint32
buf := bytes.NewReader(b)
binary.Read(buf, binary.LittleEndian, &result)
return result
}
func (s *HashingSelector) Select(input uint32, round uint32) Node {
buf := new(bytes.Buffer)
binary.Write(buf, binary.LittleEndian, input)
binary.Write(buf, binary.LittleEndian, round)
bytes := buf.Bytes()
hash := digestBytes(bytes)
token := Btoi(hash)
return s.tokenMap[s.findToken(token)]
}
func (s *HashingSelector) findToken(token uint32) uint32 {
i := sort.Search(len(s.tokenList), func(i int) bool { return s.tokenList[i] >= token })
if i == len(s.tokenList) {
return s.tokenList[i-1]
}
return s.tokenList[i]
}