Class: Redis::HashRing

Inherits:
Object
  • Object
show all
Defined in:
lib/redis/hash_ring.rb

Constant Summary collapse

POINTS_PER_SERVER =

this is the default in libmemcached

160

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(nodes = [], replicas = POINTS_PER_SERVER) ⇒ HashRing

nodes is a list of objects that have a proper to_s representation. replicas indicates how many virtual points should be used pr. node, replicas are required to improve the distribution.


14
15
16
17
18
19
20
21
22
# File 'lib/redis/hash_ring.rb', line 14

def initialize(nodes = [], replicas = POINTS_PER_SERVER)
  @replicas = replicas
  @ring = {}
  @nodes = []
  @sorted_keys = []
  nodes.each do |node|
    add_node(node)
  end
end

Instance Attribute Details

#nodesObject (readonly)

Returns the value of attribute nodes.


9
10
11
# File 'lib/redis/hash_ring.rb', line 9

def nodes
  @nodes
end

#replicasObject (readonly)

Returns the value of attribute replicas.


9
10
11
# File 'lib/redis/hash_ring.rb', line 9

def replicas
  @replicas
end

#ringObject (readonly)

Returns the value of attribute ring.


9
10
11
# File 'lib/redis/hash_ring.rb', line 9

def ring
  @ring
end

#sorted_keysObject (readonly)

Returns the value of attribute sorted_keys.


9
10
11
# File 'lib/redis/hash_ring.rb', line 9

def sorted_keys
  @sorted_keys
end

Class Method Details

.binary_search(ary, value) ⇒ Object

Find the closest index in HashRing with value <= the given value


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/redis/hash_ring.rb', line 67

def self.binary_search(ary, value)
  upper = ary.size - 1
  lower = 0
  idx = 0

  while lower <= upper
    idx = (lower + upper) / 2
    comp = ary[idx] <=> value

    if comp == 0
      return idx
    elsif comp > 0
      upper = idx - 1
    else
      lower = idx + 1
    end
  end

  upper = ary.size - 1 if upper < 0
  upper
end

Instance Method Details

#add_node(node) ⇒ Object

Adds a node to the hash ring (including a number of replicas).


25
26
27
28
29
30
31
32
33
# File 'lib/redis/hash_ring.rb', line 25

def add_node(node)
  @nodes << node
  @replicas.times do |i|
    key = Zlib.crc32("#{node.id}:#{i}")
    @ring[key] = node
    @sorted_keys << key
  end
  @sorted_keys.sort!
end

#get_node(key) ⇒ Object

get the node in the hash ring for this key


45
46
47
# File 'lib/redis/hash_ring.rb', line 45

def get_node(key)
  get_node_pos(key)[0]
end

#get_node_pos(key) ⇒ Object


49
50
51
52
53
54
55
# File 'lib/redis/hash_ring.rb', line 49

def get_node_pos(key)
  return [nil, nil] if @ring.empty?

  crc = Zlib.crc32(key)
  idx = HashRing.binary_search(@sorted_keys, crc)
  [@ring[@sorted_keys[idx]], idx]
end

#iter_nodes(key) ⇒ Object


57
58
59
60
61
62
63
64
# File 'lib/redis/hash_ring.rb', line 57

def iter_nodes(key)
  return [nil, nil] if @ring.empty?

  _, pos = get_node_pos(key)
  @ring.size.times do |n|
    yield @ring[@sorted_keys[(pos + n) % @ring.size]]
  end
end

#remove_node(node) ⇒ Object


35
36
37
38
39
40
41
42
# File 'lib/redis/hash_ring.rb', line 35

def remove_node(node)
  @nodes.reject! { |n| n.id == node.id }
  @replicas.times do |i|
    key = Zlib.crc32("#{node.id}:#{i}")
    @ring.delete(key)
    @sorted_keys.reject! { |k| k == key }
  end
end