lib/memcache.rb in memcache-client-1.7.5 vs lib/memcache.rb in memcache-client-1.7.6
- old
+ new
@@ -4,20 +4,43 @@
require 'thread'
require 'zlib'
require 'digest/sha1'
require 'net/protocol'
+begin
+ # Try to use the SystemTimer gem instead of Ruby's timeout library
+ # when running on something that looks like Ruby 1.8.x. See:
+ # http://ph7spot.com/articles/system_timer
+ # We don't want to bother trying to load SystemTimer on jruby and
+ # ruby 1.9+
+ if defined?(JRUBY_VERSION) || (RUBY_VERSION >= '1.9')
+ require 'timeout'
+ MemCacheTimer = Timeout
+ else
+ require 'system_timer'
+ MemCacheTimer = SystemTimer
+ end
+rescue LoadError => e
+ puts "[memcache-client] Could not load SystemTimer gem, falling back to Ruby's slower/unsafe timeout library: #{e.message}"
+ require 'timeout'
+ MemCacheTimer = Timeout
+end
+
+
##
# A Ruby client library for memcached.
#
class MemCache
##
# The version of MemCache you are using.
- VERSION = '1.7.5'
+ VERSION = begin
+ config = YAML.load(File.read(File.dirname(__FILE__) + '/../VERSION.yml'))
+ "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
+ end
##
# Default options for the cache object.
DEFAULT_OPTIONS = {
@@ -27,11 +50,12 @@
:failover => true,
:timeout => 0.5,
:logger => nil,
:no_reply => false,
:check_size => true,
- :autofix_keys => false
+ :autofix_keys => false,
+ :namespace_separator => ':',
}
##
# Default memcached port.
@@ -144,10 +168,11 @@
@timeout = opts[:timeout]
@failover = opts[:failover]
@logger = opts[:logger]
@no_reply = opts[:no_reply]
@check_size = opts[:check_size]
+ @namespace_separator = opts[:namespace_separator]
@mutex = Mutex.new if @multithread
logger.info { "memcache-client #{VERSION} #{Array(servers).inspect}" } if logger
Thread.current[:memcache_client] = self.object_id if !@multithread
@@ -646,11 +671,11 @@
end
if namespace.nil? then
key
else
- "#{@namespace}:#{key}"
+ "#{@namespace}#{@namespace_separator}#{key}"
end
end
##
# Returns an interoperable hash value for +key+. (I think, docs are
@@ -864,11 +889,11 @@
##
# Handles +error+ from +server+.
def handle_error(server, error)
raise error if error.is_a?(MemCacheError)
- server.close if server
+ server.close if server && server.status == "CONNECTED"
new_error = MemCacheError.new error.message
new_error.set_backtrace error.backtrace
raise new_error
end
@@ -1014,20 +1039,44 @@
begin
@sock = connect_to(@host, @port, @timeout)
@sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
@retry = nil
@status = 'CONNECTED'
- rescue SocketError, SystemCallError, IOError => err
+ rescue SocketError, SystemCallError, IOError, Timeout::Error => err
logger.warn { "Unable to open socket: #{err.class.name}, #{err.message}" } if logger
mark_dead err
end
return @sock
end
def connect_to(host, port, timeout=nil)
- io = MemCache::BufferedIO.new(TCPSocket.new(host, port))
+ sock = nil
+ if timeout
+ MemCacheTimer.timeout(timeout) do
+ sock = TCPSocket.new(host, port)
+ end
+ else
+ sock = TCPSocket.new(host, port)
+ end
+
+ io = MemCache::BufferedIO.new(sock)
io.read_timeout = timeout
+ # Getting reports from several customers, including 37signals,
+ # that the non-blocking timeouts in 1.7.5 don't seem to be reliable.
+ # It can't hurt to set the underlying socket timeout also, if possible.
+ if timeout
+ secs = Integer(timeout)
+ usecs = Integer((timeout - secs) * 1_000_000)
+ optval = [secs, usecs].pack("l_2")
+ begin
+ io.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
+ io.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
+ rescue Exception => ex
+ # Solaris, for one, does not like/support socket timeouts.
+ @logger.info "[memcache-client] Unable to use raw socket timeouts: #{ex.class.name}: #{ex.message}" if @logger
+ end
+ end
io
end
##
# Close the connection to the memcached server targeted by this