2023-11-21 21:42:43 +01:00
|
|
|
package lib
|
|
|
|
|
|
|
|
import (
|
|
|
|
"hash/fnv"
|
|
|
|
"sort"
|
|
|
|
)
|
|
|
|
|
|
|
|
type consistentHashRecord[V any] struct {
|
|
|
|
record V
|
|
|
|
value int
|
|
|
|
}
|
|
|
|
|
|
|
|
func HashString(value string) int {
|
|
|
|
f := fnv.New32a()
|
|
|
|
f.Write([]byte(value))
|
|
|
|
return int(f.Sum32())
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConsistentHash implementation. Traverse the values until we find a key
|
|
|
|
// less than ours.
|
2023-11-27 16:56:30 +01:00
|
|
|
func ConsistentHash[V any, K any](values []V, client K, bucketFunc func(V) int, keyFunc func(K) int) V {
|
2023-11-21 21:42:43 +01:00
|
|
|
if len(values) == 0 {
|
|
|
|
panic("values is empty")
|
|
|
|
}
|
|
|
|
|
|
|
|
vs := Map(values, func(v V) consistentHashRecord[V] {
|
|
|
|
return consistentHashRecord[V]{
|
|
|
|
v,
|
2023-11-27 16:56:30 +01:00
|
|
|
bucketFunc(v),
|
2023-11-21 21:42:43 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
sort.SliceStable(vs, func(i, j int) bool {
|
|
|
|
return vs[i].value < vs[j].value
|
|
|
|
})
|
|
|
|
|
|
|
|
ourKey := keyFunc(client)
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
idx := sort.Search(len(vs), func(i int) bool {
|
|
|
|
return vs[i].value >= ourKey
|
|
|
|
})
|
|
|
|
|
|
|
|
if idx == len(vs) {
|
|
|
|
return vs[0].record
|
2023-11-21 21:42:43 +01:00
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
return vs[idx].record
|
2023-11-21 21:42:43 +01:00
|
|
|
}
|