vendor: github.com/serialx/hashring 22c0c7ab6b1b (master)

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2024-02-24 16:56:59 +01:00
parent ae0a5e495a
commit 625d90b983
7 changed files with 171 additions and 37 deletions

View File

@ -2,39 +2,75 @@ package hashring
import (
"crypto/md5"
"math"
"fmt"
"sort"
"strconv"
)
type HashKey uint32
var defaultHashFunc = func() HashFunc {
hashFunc, err := NewHash(md5.New).Use(NewInt64PairHashKey)
if err != nil {
panic(fmt.Sprintf("failed to create defaultHashFunc: %s", err.Error()))
}
return hashFunc
}()
type HashKey interface {
Less(other HashKey) bool
}
type HashKeyOrder []HashKey
func (h HashKeyOrder) Len() int { return len(h) }
func (h HashKeyOrder) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h HashKeyOrder) Less(i, j int) bool { return h[i] < h[j] }
func (h HashKeyOrder) Len() int { return len(h) }
func (h HashKeyOrder) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h HashKeyOrder) Less(i, j int) bool {
return h[i].Less(h[j])
}
type HashFunc func([]byte) HashKey
type HashRing struct {
ring map[HashKey]string
sortedKeys []HashKey
nodes []string
weights map[string]int
hashFunc HashFunc
}
type Uint32HashKey uint32
func (k Uint32HashKey) Less(other HashKey) bool {
return k < other.(Uint32HashKey)
}
func New(nodes []string) *HashRing {
return NewWithHash(nodes, defaultHashFunc)
}
func NewWithHash(
nodes []string,
hashKey HashFunc,
) *HashRing {
hashRing := &HashRing{
ring: make(map[HashKey]string),
sortedKeys: make([]HashKey, 0),
nodes: nodes,
weights: make(map[string]int),
hashFunc: hashKey,
}
hashRing.generateCircle()
return hashRing
}
func NewWithWeights(weights map[string]int) *HashRing {
return NewWithHashAndWeights(weights, defaultHashFunc)
}
func NewWithHashAndWeights(
weights map[string]int,
hashFunc HashFunc,
) *HashRing {
nodes := make([]string, 0, len(weights))
for node, _ := range weights {
for node := range weights {
nodes = append(nodes, node)
}
hashRing := &HashRing{
@ -42,6 +78,7 @@ func NewWithWeights(weights map[string]int) *HashRing {
sortedKeys: make([]HashKey, 0),
nodes: nodes,
weights: weights,
hashFunc: hashFunc,
}
hashRing.generateCircle()
return hashRing
@ -66,7 +103,7 @@ func (h *HashRing) UpdateWithWeights(weights map[string]int) {
}
if nodesChgFlg {
newhring := NewWithWeights(weights)
newhring := NewWithHashAndWeights(weights, h.hashFunc)
h.weights = newhring.weights
h.nodes = newhring.nodes
h.ring = newhring.ring
@ -88,17 +125,11 @@ func (h *HashRing) generateCircle() {
for _, node := range h.nodes {
weight := h.weights[node]
factor := math.Floor(float64(40*len(h.nodes)*weight) / float64(totalWeight))
for j := 0; j < int(factor); j++ {
for j := 0; j < weight; j++ {
nodeKey := node + "-" + strconv.FormatInt(int64(j), 10)
bKey := hashDigest(nodeKey)
for i := 0; i < 3; i++ {
key := hashVal(bKey[i*4 : i*4+4])
h.ring[key] = node
h.sortedKeys = append(h.sortedKeys, key)
}
key := h.hashFunc([]byte(nodeKey))
h.ring[key] = node
h.sortedKeys = append(h.sortedKeys, key)
}
}
@ -121,10 +152,10 @@ func (h *HashRing) GetNodePos(stringKey string) (pos int, ok bool) {
key := h.GenKey(stringKey)
nodes := h.sortedKeys
pos = sort.Search(len(nodes), func(i int) bool { return nodes[i] > key })
pos = sort.Search(len(nodes), func(i int) bool { return key.Less(nodes[i]) })
if pos == len(nodes) {
// Wrap the search, should return first node
// Wrap the search, should return First node
return 0, true
} else {
return pos, true
@ -132,10 +163,12 @@ func (h *HashRing) GetNodePos(stringKey string) (pos int, ok bool) {
}
func (h *HashRing) GenKey(key string) HashKey {
bKey := hashDigest(key)
return hashVal(bKey[0:4])
return h.hashFunc([]byte(key))
}
// GetNodes iterates over the hash ring and returns the nodes in the order
// which is determined by the key. GetNodes is thread safe if the hash
// which was used to configure the hash ring is thread safe.
func (h *HashRing) GetNodes(stringKey string, size int) (nodes []string, ok bool) {
pos, ok := h.GetNodePos(stringKey)
if !ok {
@ -193,6 +226,7 @@ func (h *HashRing) AddWeightedNode(node string, weight int) *HashRing {
sortedKeys: make([]HashKey, 0),
nodes: nodes,
weights: weights,
hashFunc: h.hashFunc,
}
hashRing.generateCircle()
return hashRing
@ -208,7 +242,7 @@ func (h *HashRing) UpdateWeightedNode(node string, weight int) *HashRing {
return h
}
nodes := make([]string, len(h.nodes), len(h.nodes))
nodes := make([]string, len(h.nodes))
copy(nodes, h.nodes)
weights := make(map[string]int)
@ -222,6 +256,7 @@ func (h *HashRing) UpdateWeightedNode(node string, weight int) *HashRing {
sortedKeys: make([]HashKey, 0),
nodes: nodes,
weights: weights,
hashFunc: h.hashFunc,
}
hashRing.generateCircle()
return hashRing
@ -251,18 +286,8 @@ func (h *HashRing) RemoveNode(node string) *HashRing {
sortedKeys: make([]HashKey, 0),
nodes: nodes,
weights: weights,
hashFunc: h.hashFunc,
}
hashRing.generateCircle()
return hashRing
}
func hashVal(bKey []byte) HashKey {
return ((HashKey(bKey[3]) << 24) |
(HashKey(bKey[2]) << 16) |
(HashKey(bKey[1]) << 8) |
(HashKey(bKey[0])))
}
func hashDigest(key string) [md5.Size]byte {
return md5.Sum([]byte(key))
}