You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

80 lines
1.4 KiB

  1. package rendezvous
  2. type Rendezvous struct {
  3. nodes map[string]int
  4. nstr []string
  5. nhash []uint64
  6. hash Hasher
  7. }
  8. type Hasher func(s string) uint64
  9. func New(nodes []string, hash Hasher) *Rendezvous {
  10. r := &Rendezvous{
  11. nodes: make(map[string]int, len(nodes)),
  12. nstr: make([]string, len(nodes)),
  13. nhash: make([]uint64, len(nodes)),
  14. hash: hash,
  15. }
  16. for i, n := range nodes {
  17. r.nodes[n] = i
  18. r.nstr[i] = n
  19. r.nhash[i] = hash(n)
  20. }
  21. return r
  22. }
  23. func (r *Rendezvous) Lookup(k string) string {
  24. // short-circuit if we're empty
  25. if len(r.nodes) == 0 {
  26. return ""
  27. }
  28. khash := r.hash(k)
  29. var midx int
  30. var mhash = xorshiftMult64(khash ^ r.nhash[0])
  31. for i, nhash := range r.nhash[1:] {
  32. if h := xorshiftMult64(khash ^ nhash); h > mhash {
  33. midx = i + 1
  34. mhash = h
  35. }
  36. }
  37. return r.nstr[midx]
  38. }
  39. func (r *Rendezvous) Add(node string) {
  40. r.nodes[node] = len(r.nstr)
  41. r.nstr = append(r.nstr, node)
  42. r.nhash = append(r.nhash, r.hash(node))
  43. }
  44. func (r *Rendezvous) Remove(node string) {
  45. // find index of node to remove
  46. nidx := r.nodes[node]
  47. // remove from the slices
  48. l := len(r.nstr)
  49. r.nstr[nidx] = r.nstr[l]
  50. r.nstr = r.nstr[:l]
  51. r.nhash[nidx] = r.nhash[l]
  52. r.nhash = r.nhash[:l]
  53. // update the map
  54. delete(r.nodes, node)
  55. moved := r.nstr[nidx]
  56. r.nodes[moved] = nidx
  57. }
  58. func xorshiftMult64(x uint64) uint64 {
  59. x ^= x >> 12 // a
  60. x ^= x << 25 // b
  61. x ^= x >> 27 // c
  62. return x * 2685821657736338717
  63. }