mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-25 03:40:10 +01:00
59 lines
1.3 KiB
Go
59 lines
1.3 KiB
Go
package netstorage
|
|
|
|
import (
|
|
"github.com/cespare/xxhash/v2"
|
|
)
|
|
|
|
// See the following docs:
|
|
// - https://www.eecs.umich.edu/techreports/cse/96/CSE-TR-316-96.pdf
|
|
// - https://github.com/dgryski/go-rendezvous
|
|
// - https://dgryski.medium.com/consistent-hashing-algorithmic-tradeoffs-ef6b8e2fcae8
|
|
type consistentHash struct {
|
|
hashSeed uint64
|
|
nodeHashes []uint64
|
|
}
|
|
|
|
func newConsistentHash(nodes []string, hashSeed uint64) *consistentHash {
|
|
nodeHashes := make([]uint64, len(nodes))
|
|
for i, node := range nodes {
|
|
nodeHashes[i] = xxhash.Sum64([]byte(node))
|
|
}
|
|
return &consistentHash{
|
|
hashSeed: hashSeed,
|
|
nodeHashes: nodeHashes,
|
|
}
|
|
}
|
|
|
|
func (rh *consistentHash) getNodeIdx(h uint64, excludeIdxs []int) int {
|
|
var mMax uint64
|
|
var idx int
|
|
h ^= rh.hashSeed
|
|
|
|
if len(excludeIdxs) == len(rh.nodeHashes) {
|
|
// All the nodes are excluded. Treat this case as no nodes are excluded.
|
|
// This is better from load-balacning PoV than selecting some static node.
|
|
excludeIdxs = nil
|
|
}
|
|
|
|
next:
|
|
for i, nh := range rh.nodeHashes {
|
|
for _, j := range excludeIdxs {
|
|
if i == j {
|
|
continue next
|
|
}
|
|
}
|
|
if m := fastHashUint64(nh ^ h); m > mMax {
|
|
mMax = m
|
|
idx = i
|
|
}
|
|
}
|
|
return idx
|
|
}
|
|
|
|
func fastHashUint64(x uint64) uint64 {
|
|
x ^= x >> 12 // a
|
|
x ^= x << 25 // b
|
|
x ^= x >> 27 // c
|
|
return x * 2685821657736338717
|
|
}
|