require 'redis/hash_ring' module RedisRb class DistRedis attr_reader :ring def initialize(opts={}) hosts = [] db = opts[:db] || nil timeout = opts[:timeout] || nil raise "No hosts given" unless opts[:hosts] opts[:hosts].each do |h| host, port = h.split(':') hosts << Client.new(:host => host, :port => port, :db => db, :timeout => timeout) end @ring = HashRing.new hosts end def node_for_key(key) key = $1 if key =~ /\{(.*)?\}/ @ring.get_node(key) end def add_server(server) server, port = server.split(':') @ring.add_node Client.new(:host => server, :port => port) end def method_missing(sym, *args, &blk) if redis = node_for_key(args.first.to_s) redis.send sym, *args, &blk else super end end def node_keys(glob) @ring.nodes.map do |red| red.keys(glob) end end def keys(glob) node_keys(glob).flatten end def save on_each_node :save end def bgsave on_each_node :bgsave end def quit on_each_node :quit end def flush_all on_each_node :flush_all end alias_method :flushall, :flush_all def flush_db on_each_node :flush_db end alias_method :flushdb, :flush_db def delete_cloud! @ring.nodes.each do |red| red.keys("*").each do |key| red.delete key end end end def on_each_node(command, *args) @ring.nodes.each do |red| red.send(command, *args) end end def mset() end def mget(*keyz) results = {} kbn = keys_by_node(keyz) kbn.each do |node, node_keyz| node.mapped_mget(*node_keyz).each do |k, v| results[k] = v end end keyz.flatten.map { |k| results[k] } end def keys_by_node(*keyz) keyz.flatten.inject({}) do |kbn, k| node = node_for_key(k) next if kbn[node] && kbn[node].include?(k) kbn[node] ||= [] kbn[node] << k kbn end end end end # For backwards compatibility DistRedis = RedisRb::DistRedis