package main
import (
"hash/crc32"
"sort"
"strconv"
"sync"
)
type HashRing struct {
mu sync.RWMutex
vnodes int
ring []uint32
nodeMap map[uint32]string
}
func NewHashRing(vnodes int) *HashRing {
return &HashRing{
vnodes: vnodes,
ring: make([]uint32, 0),
nodeMap: make(map[uint32]string),
}
}
func (h *HashRing) AddNode(node string) {
h.mu.Lock()
defer h.mu.Unlock()
for i := 0; i < h.vnodes; i++ {
hash := crc32.ChecksumIEEE([]byte(node + "#" + strconv.Itoa(i)))
h.ring = append(h.ring, hash)
h.nodeMap[hash] = node
}
sort.Slice(h.ring, func(i, j int) bool { return h.ring[i] < h.ring[j] })
}
func (h *HashRing) GetNode(key string) string {
h.mu.RLock()
defer h.mu.RUnlock()
if len(h.ring) == 0 {
return ""
}
hash := crc32.ChecksumIEEE([]byte(key))
idx := sort.Search(len(h.ring), func(i int) bool {
return h.ring[i] >= hash
})
if idx == len(h.ring) {
idx = 0
}
return h.nodeMap[h.ring[idx]]
}