class RedisClient::HashRing

def binary_search(ary, value)

Find the closest index in HashRing with value <= the given value
def binary_search(ary, value)
  upper = ary.size
  lower = 0
  while lower < upper
    mid = (lower + upper) / 2
    if ary[mid] > value
      upper = mid
    else
      lower = mid + 1
    end
  end
  upper - 1
end

def digest

def digest
  @digest ||= begin
    require 'digest/md5'
    Digest::MD5
  end
end

def hash_for(key)

def hash_for(key)
  Zlib.crc32(key)
end

def initialize(nodes = [], replicas: POINTS_PER_SERVER, digest: self.class.digest)

def initialize(nodes = [], replicas: POINTS_PER_SERVER, digest: self.class.digest)
  @replicas = replicas
  @ring = {}
  @digest = digest
  ids = {}
  @nodes = nodes.dup.freeze
  nodes.each do |node|
    id = node.id || node.config.server_url
    if ids[id]
      raise ArgumentError, "duplicate node id: #{id.inspect}"
    end
    ids[id] = true
    replicas.times do |i|
      @ring[server_hash_for("#{id}:#{i}".freeze)] = node
    end
  end
  @sorted_keys = @ring.keys
  @sorted_keys.sort!
end

def node_for(key)

get the node in the hash ring for this key
def node_for(key)
  hash = hash_for(key)
  idx = binary_search(@sorted_keys, hash)
  @ring[@sorted_keys[idx]]
end

def nodes_for(*keys)

def nodes_for(*keys)
  keys.flatten!
  mapping = {}
  keys.each do |key|
    (mapping[node_for(key)] ||= []) << key
  end
  mapping
end

def server_hash_for(key)

def server_hash_for(key)
  @digest.digest(key).unpack1("L>")
end