Class: Dalli::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/dalli/server.rb

Defined Under Namespace

Modules: TCPSocketOptions Classes: NilObject

Constant Summary collapse

DEFAULT_PORT =
11211
DEFAULT_WEIGHT =
1
DEFAULTS =
{
  # seconds between trying to contact a remote server
  :down_retry_delay => 1,
  # connect/read/write timeout for socket operations
  :socket_timeout => 0.5,
  # times a socket operation may fail before considering the server dead
  :socket_max_failures => 2,
  # amount of time to sleep between retries when a failure occurs
  :socket_failure_delay => 0.01,
  # max size of value in bytes (default is 1 MB, can be overriden with "memcached -I <size>")
  :value_max_bytes => 1024 * 1024,
  :compressor => Compressor,
  # min byte size to attempt compression
  :compression_min_size => 1024,
  # max byte size for compression
  :compression_max_size => false,
  :serializer => Marshal,
  :username => nil,
  :password => nil,
  :keepalive => true,
  # max byte size for SO_SNDBUF
  :sndbuf => nil,
  # max byte size for SO_RCVBUF
  :rcvbuf => nil
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attribs, options = {}) ⇒ Server

Returns a new instance of Server.



41
42
43
44
45
46
47
48
49
50
51
52
# 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

Instance Attribute Details

#hostnameObject

Returns the value of attribute hostname.



6
7
8
# File 'lib/dalli/server.rb', line 6

def hostname
  @hostname
end

#optionsObject

Returns the value of attribute options.



9
10
11
# File 'lib/dalli/server.rb', line 9

def options
  @options
end

#portObject

Returns the value of attribute port.



7
8
9
# File 'lib/dalli/server.rb', line 7

def port
  @port
end

#sockObject (readonly)

Returns the value of attribute sock.



10
11
12
# File 'lib/dalli/server.rb', line 10

def sock
  @sock
end

#socket_typeObject (readonly)

possible values: :unix, :tcp



11
12
13
# File 'lib/dalli/server.rb', line 11

def socket_type
  @socket_type
end

#weightObject

Returns the value of attribute weight.



8
9
10
# File 'lib/dalli/server.rb', line 8

def weight
  @weight
end

Instance Method Details

#alive?Boolean

Returns:

  • (Boolean)


86
87
88
89
90
91
92
93
94
95
96
97
98
99
# 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

#closeObject



101
102
103
104
105
106
107
# File 'lib/dalli/server.rb', line 101

def close
  return unless @sock
  @sock.close rescue nil
  @sock = nil
  @pid = nil
  @inprogress = false
end

#compressorObject



119
120
121
# File 'lib/dalli/server.rb', line 119

def compressor
  @options[:compressor]
end

#lock!Object



109
110
# File 'lib/dalli/server.rb', line 109

def lock!
end

#multi_response_abortObject

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

Returns nothing.



195
196
197
198
199
200
201
202
# 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?Boolean

Did the last call to #multi_response_start complete successfully?

Returns:

  • (Boolean)


137
138
139
# File 'lib/dalli/server.rb', line 137

def multi_response_completed?
  @multi_buffer.nil?
end

#multi_response_nonblockObject

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.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# 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_startObject

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.



128
129
130
131
132
133
134
# File 'lib/dalli/server.rb', line 128

def multi_response_start
  verify_state
  write_noop
  @multi_buffer = ''
  @position = 0
  @inprogress = true
end

#nameObject



54
55
56
57
58
59
60
# File 'lib/dalli/server.rb', line 54

def name
  if socket_type == :unix
    hostname
  else
    "#{hostname}:#{port}"
  end
end

#request(op, *args) ⇒ Object

Chokepoint method for instrumentation



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 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

#serializerObject



115
116
117
# File 'lib/dalli/server.rb', line 115

def serializer
  @options[:serializer]
end

#unlock!Object



112
113
# File 'lib/dalli/server.rb', line 112

def unlock!
end