Spaces:
Sleeping
Sleeping
package utils | |
import ( | |
"errors" | |
"github.com/spaolacci/murmur3" | |
) | |
type Hasher = func(member string, key string) uint64 | |
type Member = string | |
type Members = []Member | |
type Key = string | |
// assign assigns a key to a member using the rendezvous hashing algorithm. | |
func Assign(key Key, members Members, hasher Hasher) (Member, error) { | |
if len(members) == 0 { | |
return "", errors.New("cannot assign key to empty member list") | |
} | |
if len(members) == 1 { | |
return members[0], nil | |
} | |
if key == "" { | |
return "", errors.New("cannot assign empty key") | |
} | |
maxScore := uint64(0) | |
var maxMember Member | |
for _, member := range members { | |
score := hasher(string(member), string(key)) | |
if score > maxScore { | |
maxScore = score | |
maxMember = member | |
} | |
} | |
return maxMember, nil | |
} | |
func mergeHashes(a uint64, b uint64) uint64 { | |
acc := a ^ b | |
acc ^= acc >> 33 | |
acc *= 0xff51afd7ed558ccd | |
acc ^= acc >> 33 | |
acc *= 0xc4ceb9fe1a85ec53 | |
acc ^= acc >> 33 | |
return acc | |
} | |
// NOTE: The python implementation of murmur3 may differ from the golang implementation. | |
// For now, this is fine since go and python don't need to agree on any hashing schemes | |
// but if we ever need to agree on a hashing scheme, we should verify that the implementations | |
// are the same. | |
func Murmur3Hasher(member string, key string) uint64 { | |
hasher := murmur3.New64() | |
hasher.Write([]byte(member)) | |
memberHash := hasher.Sum64() | |
hasher.Reset() | |
hasher.Write([]byte(key)) | |
keyHash := hasher.Sum64() | |
return mergeHashes(memberHash, keyHash) | |
} | |