Class: Dalli::Server

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

Defined Under Namespace

Classes: NilObject

Constant Summary collapse

DEFAULT_PORT =
11211
DEFAULT_WEIGHT =
1
DEFAULTS =
{
  # seconds between trying to contact a remote server
  down_retry_delay: 30,
  # connect/read/write timeout for socket operations
  socket_timeout: 1,
  # 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.1,
  # max size of value in bytes (default is 1 MB, can be overriden with "memcached -I <size>")
  value_max_bytes: 1024 * 1024,
  compress: true,
  compressor: Compressor,
  # min byte size to attempt compression
  compression_min_size: 4 * 1024,
  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.


42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/dalli/server.rb', line 42

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


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

def hostname
  @hostname
end

#optionsObject

Returns the value of attribute options


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

def options
  @options
end

#portObject

Returns the value of attribute port


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

def port
  @port
end

#sockObject (readonly)

Returns the value of attribute sock


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

def sock
  @sock
end

#socket_typeObject (readonly)

possible values: :unix, :tcp


13
14
15
# File 'lib/dalli/server.rb', line 13

def socket_type
  @socket_type
end

#weightObject

Returns the value of attribute weight


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

def weight
  @weight
end

Instance Method Details

#alive?Boolean

Returns:

  • (Boolean)

82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/dalli/server.rb', line 82

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


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

def close
  return unless @sock
  begin
    @sock.close
  rescue
    nil
  end
  @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).unpack1("N")
      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


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

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

#request(op, *args) ⇒ Object

Chokepoint method for instrumentation


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/dalli/server.rb', line 64

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::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."
    raise
  rescue Dalli::DalliError, Dalli::NetworkError, Dalli::ValueOverMaxSize, 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