Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

136 lines (107 sloc) 3.395 kb
require "redis/connection/registry"
require "redis/connection/command_helper"
require "socket"
class Redis
module Connection
class Ruby
include Redis::Connection::CommandHelper
MINUS = "-".freeze
PLUS = "+".freeze
COLON = ":".freeze
DOLLAR = "$".freeze
ASTERISK = "*".freeze
def initialize
@sock = nil
end
def connected?
!! @sock
end
def connect(host, port, timeout)
with_timeout(timeout.to_f / 1_000_000) do
@sock = TCPSocket.new(host, port)
@sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
end
end
def connect_unix(path, timeout)
with_timeout(timeout.to_f / 1_000_000) do
@sock = UNIXSocket.new(path)
end
end
def disconnect
@sock.close
rescue
ensure
@sock = nil
end
def timeout=(usecs)
secs = Integer(usecs / 1_000_000)
usecs = Integer(usecs - (secs * 1_000_000)) # 0 - 999_999
optval = [secs, usecs].pack("l_2")
begin
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
rescue Errno::ENOPROTOOPT
end
end
def write(command)
@sock.write(build_command(command))
end
def read
# We read the first byte using read() mainly because gets() is
# immune to raw socket timeouts.
reply_type = @sock.read(1)
raise Errno::ECONNRESET unless reply_type
format_reply(reply_type, @sock.gets)
end
def format_reply(reply_type, line)
case reply_type
when MINUS then format_error_reply(line)
when PLUS then format_status_reply(line)
when COLON then format_integer_reply(line)
when DOLLAR then format_bulk_reply(line)
when ASTERISK then format_multi_bulk_reply(line)
else raise ProtocolError.new(reply_type)
end
end
def format_error_reply(line)
RuntimeError.new(line.strip)
end
def format_status_reply(line)
line.strip
end
def format_integer_reply(line)
line.to_i
end
def format_bulk_reply(line)
bulklen = line.to_i
return if bulklen == -1
reply = encode(@sock.read(bulklen))
@sock.read(2) # Discard CRLF.
reply
end
def format_multi_bulk_reply(line)
n = line.to_i
return if n == -1
Array.new(n) { read }
end
protected
begin
require "system_timer"
def with_timeout(seconds, &block)
SystemTimer.timeout_after(seconds, &block)
end
rescue LoadError
if ! defined?(RUBY_ENGINE)
# MRI 1.8, all other interpreters define RUBY_ENGINE, JRuby and
# Rubinius should have no issues with timeout.
warn "WARNING: using the built-in Timeout class which is known to have issues when used for opening connections. Install the SystemTimer gem if you want to make sure the Redis client will not hang."
end
require "timeout"
def with_timeout(seconds, &block)
Timeout.timeout(seconds, &block)
end
end
end
end
end
Redis::Connection.drivers << Redis::Connection::Ruby
Jump to Line
Something went wrong with that request. Please try again.