Class: Remix::Stash::Cluster

Inherits:
Object
  • Object
show all
Includes:
Socket::Constants
Defined in:
lib/remix/stash/cluster.rb

Constant Summary collapse

@@connections =
{}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hosts) ⇒ Cluster

Returns a new instance of Cluster.



11
12
13
14
15
16
# File 'lib/remix/stash/cluster.rb', line 11

def initialize(hosts)
  @hosts = hosts.map {|x|
    host, port = x.split(':')
    [x, host, (port || 11211).to_i]
  }.sort_by {|(_,h,p)| [h,p]}
end

Instance Attribute Details

#hostsObject (readonly)

Returns the value of attribute hosts.



9
10
11
# File 'lib/remix/stash/cluster.rb', line 9

def hosts
  @hosts
end

Instance Method Details

#eachObject



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/remix/stash/cluster.rb', line 18

def each
  @hosts.each do |h|
    begin
      io = host_to_io(*h)
      break yield(io)
    rescue Errno::EPIPE, Errno::ECONNRESET, Remix::Stash::ProtocolError
      io.close
      retry
    rescue Errno::EAGAIN, Errno::ECONNREFUSED
      next
    end
  end
end

#select(key) ⇒ Object

Note: Later, I’d like to support richer cluster definitions. This should do the trick for now… and it’s fast.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/remix/stash/cluster.rb', line 34

def select(key)
  count = @hosts.size
  hash = nil
  if count > 1
    digest = Digest::MD5.digest(key)
    hash = digest.unpack("L")[0]
  else
    hash = 0
  end
  count.times do |try|
    begin
      io = host_to_io(*@hosts[(hash + try) % count])
      return yield(io)
    rescue Errno::EPIPE, Errno::ECONNRESET, Remix::Stash::ProtocolError
      io.close
      retry
    rescue Errno::EAGAIN, Errno::ECONNREFUSED
      next
    end
  end
  raise Remix::Stash::ClusterError,
    "Unable to find suitable host to communicate with for #{key.inspect} (MD5-32=#{hash})"
end