class Dalli::Server

Constants

CAS_HEADER
DEFAULTS
DEFAULT_PORT
DEFAULT_WEIGHT
FLAG_COMPRESSED
FLAG_SERIALIZED

www.hjp.at/zettel/m/memcached_flags.rxml Looks like most clients use bit 0 to indicate native language serialization and bit 1 to indicate gzip compression.

FORMAT
KV_HEADER
MAX_ACCEPTABLE_EXPIRATION_INTERVAL

code.google.com/p/memcached/wiki/NewCommands#Standard_Protocol > An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a unix timestamp of an exact date.

NORMAL_HEADER
NOT_FOUND
OPCODES
OP_FORMAT
REQUEST
RESPONSE
RESPONSE_CODES

Response codes taken from: code.google.com/p/memcached/wiki/BinaryProtocolRevamped#Response_Status

Attributes

hostname[RW]
options[RW]
port[RW]
sock[R]
socket_type[R]
weight[RW]

Public Class Methods

new(attribs, options = {}) click to toggle source
# File lib/dalli/server.rb, line 41
def initialize(attribs, options = {})
  @hostname, @port, @weight, @socket_type = parse_hostname(attribs)
  @fail_count = 0
  @down_at = nil
  @last_down_at = nil
  @options = DEFAULTS.merge(options)
  @sock = nil
  @msg = nil
  @error = nil
  @pid = nil
  @inprogress = nil
end

Public Instance Methods

alive?() click to toggle source
# File lib/dalli/server.rb, line 86
def alive?
  return true if @sock

  if @last_down_at && @last_down_at + options[:down_retry_delay] >= Time.now
    time = @last_down_at + options[:down_retry_delay] - Time.now
    Dalli.logger.debug { "down_retry_delay not reached for #{name} (%.3f seconds left)" % time }
    return false
  end

  connect
  !!@sock
rescue Dalli::NetworkError
  false
end
close() click to toggle source
# File lib/dalli/server.rb, line 101
def close
  return unless @sock
  @sock.close rescue nil
  @sock = nil
  @pid = nil
  @inprogress = false
end
compressor() click to toggle source
# File lib/dalli/server.rb, line 119
def compressor
  @options[:compressor]
end
lock!() click to toggle source
# File lib/dalli/server.rb, line 109
def lock!
end
multi_response_abort() click to toggle source

Abort an earlier multi_response_start. Used to signal an external timeout. The underlying socket is disconnected, and the exception is swallowed.

Returns nothing.

# File lib/dalli/server.rb, line 195
def multi_response_abort
  @multi_buffer = nil
  @position = nil
  @inprogress = false
  failure!(RuntimeError.new('External timeout'))
rescue NetworkError
  true
end
multi_response_completed?() click to toggle source

Did the last call to multi_response_start complete successfully?

# File lib/dalli/server.rb, line 137
def multi_response_completed?
  @multi_buffer.nil?
end
multi_response_nonblock() click to toggle source

Attempt to receive and parse as many key/value pairs as possible from this server. After multi_response_start, this should be invoked repeatedly whenever this server’s socket is readable until multi_response_completed?.

Returns a Hash of kv pairs received.

# File lib/dalli/server.rb, line 147
def multi_response_nonblock
  raise 'multi_response has completed' if @multi_buffer.nil?

  @multi_buffer << @sock.read_available
  buf = @multi_buffer
  pos = @position
  values = {}

  while buf.bytesize - pos >= 24
    header = buf.slice(pos, 24)
    (key_length, _, body_length, cas) = header.unpack(KV_HEADER)

    if key_length == 0
      # all done!
      @multi_buffer = nil
      @position = nil
      @inprogress = false
      break

    elsif buf.bytesize - pos >= 24 + body_length
      flags = buf.slice(pos + 24, 4).unpack('N')[0]
      key = buf.slice(pos + 24 + 4, key_length)
      value = buf.slice(pos + 24 + 4 + key_length, body_length - key_length - 4) if body_length - key_length - 4 > 0

      pos = pos + 24 + body_length

      begin
        values[key] = [deserialize(value, flags), cas]
      rescue DalliError
      end

    else
      # not enough data yet, wait for more
      break
    end
  end
  @position = pos

  values
rescue SystemCallError, Timeout::Error, EOFError => e
  failure!(e)
end
multi_response_start() click to toggle source

Start reading key/value pairs from this connection. This is usually called after a series of GETKQ commands. A NOOP is sent, and the server begins flushing responses for kv pairs that were found.

Returns nothing.

# File lib/dalli/server.rb, line 128
def multi_response_start
  verify_state
  write_noop
  @multi_buffer = ''
  @position = 0
  @inprogress = true
end
name() click to toggle source
# File lib/dalli/server.rb, line 54
def name
  if socket_type == :unix
    hostname
  else
    "#{hostname}:#{port}"
  end
end
request(op, *args) click to toggle source

Chokepoint method for instrumentation

# File lib/dalli/server.rb, line 63
def request(op, *args)
  verify_state
  raise Dalli::NetworkError, "#{name} is down: #{@error} #{@msg}. If you are sure it is running, ensure memcached version is > 1.4." unless alive?
  begin
    send(op, *args)
  rescue Dalli::NetworkError
    raise
  rescue Dalli::MarshalError => ex
    Dalli.logger.error "Marshalling error for key '#{args.first}': #{ex.message}"
    Dalli.logger.error "You are trying to cache a Ruby object which cannot be serialized to memcached."
    Dalli.logger.error ex.backtrace.join("\n\t")
    false
  rescue Dalli::DalliError
    raise
  rescue Timeout::Error
    raise
  rescue => ex
    Dalli.logger.error "Unexpected exception during Dalli request: #{ex.class.name}: #{ex.message}"
    Dalli.logger.error ex.backtrace.join("\n\t")
    down!
  end
end
serializer() click to toggle source
# File lib/dalli/server.rb, line 115
def serializer
  @options[:serializer]
end
unlock!() click to toggle source
# File lib/dalli/server.rb, line 112
def unlock!
end