Class: Dalli::Server

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

Defined Under Namespace

Classes: USocket

Constant Summary

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,
  :username => nil,
  :password => nil,
  :async => false,
}
COMPRESSION_MIN_SIZE =
1024
FLAG_MARSHALLED =

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.

0x1
FLAG_COMPRESSED =
0x2
CAS_HEADER =
'@4CCnNNQ'
NORMAL_HEADER =
'@4CCnN'
KV_HEADER =
'@2n@6nN'
REQUEST =
0x80
RESPONSE =
0x81
RESPONSE_CODES =
{
  0 => 'No error',
  1 => 'Key not found',
  2 => 'Key exists',
  3 => 'Value too large',
  4 => 'Invalid arguments',
  5 => 'Item not stored',
  6 => 'Incr/decr on a non-numeric value',
  0x20 => 'Authentication required',
  0x81 => 'Unknown command',
  0x82 => 'Out of memory',
}
OPCODES =
{
  :get => 0x00,
  :set => 0x01,
  :add => 0x02,
  :replace => 0x03,
  :delete => 0x04,
  :incr => 0x05,
  :decr => 0x06,
  :flush => 0x08,
  :noop => 0x0A,
  :version => 0x0B,
  :getkq => 0x0D,
  :append => 0x0E,
  :prepend => 0x0F,
  :stat => 0x10,
  :setq => 0x11,
  :addq => 0x12,
  :replaceq => 0x13,
  :deleteq => 0x14,
  :incrq => 0x15,
  :decrq => 0x16,
  :auth_negotiation => 0x20,
  :auth_request => 0x21,
  :auth_continue => 0x22,
}
HEADER =
"CCnCCnNNQ"
OP_FORMAT =
{
  :get => 'a*',
  :set => 'NNa*a*',
  :add => 'NNa*a*',
  :replace => 'NNa*a*',
  :delete => 'a*',
  :incr => 'NNNNNa*',
  :decr => 'NNNNNa*',
  :flush => 'N',
  :noop => '',
  :getkq => 'a*',
  :version => '',
  :stat => 'a*',
  :append => 'a*a*',
  :prepend => 'a*a*',
  :auth_request => 'a*a*',
  :auth_continue => 'a*a*',
}
FORMAT =
OP_FORMAT.inject({}) { |memo, (k, v)| memo[k] = HEADER + v; memo }

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Server) initialize(attribs, options = {})

Returns a new instance of Server



28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/dalli/server.rb', line 28

def initialize(attribs, options = {})
  (@hostname, @port, @weight) = attribs.split(':')
  @port ||= 11211
  @port = Integer(@port)
  @weight ||= 1
  @weight = Integer(@weight)
  @fail_count = 0
  @down_at = nil
  @last_down_at = nil
  @options = DEFAULTS.merge(options)
  @sock = nil
  @msg = nil
end

Instance Attribute Details

- (Object) hostname

Returns the value of attribute hostname



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

def hostname
  @hostname
end

- (Object) options

Returns the value of attribute options



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

def options
  @options
end

- (Object) port

Returns the value of attribute port



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

def port
  @port
end

- (Object) weight

Returns the value of attribute weight



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

def weight
  @weight
end

Instance Method Details

- (Boolean) alive?

Returns:

  • (Boolean)


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

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 #{hostname}:#{port} (%.3f seconds left)" % time }
    return false
  end

  connect
  !!@sock
rescue Dalli::NetworkError
  false
end

- (Object) close



79
80
81
82
83
# File 'lib/dalli/server.rb', line 79

def close
  return unless @sock
  @sock.close rescue nil
  @sock = nil
end

- (Object) lock!



85
86
# File 'lib/dalli/server.rb', line 85

def lock!
end

- (Object) request(op, *args)

Chokepoint method for instrumentation



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/dalli/server.rb', line 43

def request(op, *args)
  raise Dalli::NetworkError, "#{hostname}:#{port} is down: #{@error} #{@msg}" 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 => ex
    Dalli.logger.error "Unexpected exception in Dalli: #{ex.class.name}: #{ex.message}"
    Dalli.logger.error "This is a bug in Dalli, please enter an issue in Github if it does not already exist."
    Dalli.logger.error ex.backtrace.join("\n\t")
    down!
  end
end

- (Object) unlock!



88
89
# File 'lib/dalli/server.rb', line 88

def unlock!
end