consistency_hash.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package utils
  2. import (
  3. "fmt"
  4. "hash/crc32"
  5. "sort"
  6. )
  7. type ConsistentHash struct {
  8. VirtualNodes int
  9. virtualNodesMap map[uint32]string
  10. actNodes map[string]string
  11. sortRing []uint32
  12. }
  13. func NewConsistentHash(virtualNodeNumber int) *ConsistentHash {
  14. return &ConsistentHash{
  15. VirtualNodes: virtualNodeNumber,
  16. virtualNodesMap: make(map[uint32]string),
  17. actNodes: make(map[string]string),
  18. sortRing: []uint32{},
  19. }
  20. }
  21. func (c *ConsistentHash) Add(node string) bool {
  22. if _, ok := c.actNodes[node]; ok {
  23. return false
  24. }
  25. for i := 0; i < c.VirtualNodes; i++ {
  26. c.virtualNodesMap[c.hashStr(fmt.Sprintf("%s#%d", node, i))] = node
  27. }
  28. c.actNodes[node] = node
  29. c.sortHashRing()
  30. return true
  31. }
  32. func (c *ConsistentHash) sortHashRing() {
  33. c.sortRing = []uint32{}
  34. for k := range c.virtualNodesMap {
  35. c.sortRing = append(c.sortRing, k)
  36. }
  37. sort.Slice(c.sortRing, func(i, j int) bool {
  38. return c.sortRing[i] < c.sortRing[j]
  39. })
  40. }
  41. func (c *ConsistentHash) Get(key string) string {
  42. hash := c.hashStr(key)
  43. if len(c.virtualNodesMap) == 0 {
  44. return ""
  45. }
  46. i := c.search(hash)
  47. return c.virtualNodesMap[c.sortRing[i]]
  48. }
  49. func (c *ConsistentHash) hashStr(key string) uint32 {
  50. return crc32.ChecksumIEEE([]byte(key))
  51. }
  52. func (c *ConsistentHash) search(hash uint32) int {
  53. i := sort.Search(len(c.sortRing), func(i int) bool { return c.sortRing[i] >= hash })
  54. if i < len(c.sortRing) {
  55. if i == len(c.sortRing)-1 {
  56. return 0
  57. } else {
  58. return i
  59. }
  60. } else {
  61. return len(c.sortRing) - 1
  62. }
  63. }