memcached 0.11 → 0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +3 -1
- data/COMPATIBILITY +1 -0
- data/README +3 -5
- data/ext/extconf.rb +14 -10
- data/ext/rlibmemcached.i +1 -1
- data/ext/rlibmemcached_wrap.c +1417 -379
- data/lib/memcached/behaviors.rb +1 -1
- data/lib/memcached/exceptions.rb +6 -13
- data/lib/memcached/memcached.rb +149 -115
- data/lib/memcached/rails.rb +34 -13
- data/memcached.gemspec +34 -104
- data/test/unit/memcached_test.rb +249 -163
- data/test/unit/rails_test.rb +1 -1
- metadata +4 -4
- metadata.gz.sig +1 -2
data/lib/memcached/behaviors.rb
CHANGED
@@ -23,7 +23,7 @@ class Memcached
|
|
23
23
|
DISTRIBUTION_VALUES = {}
|
24
24
|
BEHAVIOR_VALUES.merge!(load_constants("MEMCACHED_DISTRIBUTION_", DISTRIBUTION_VALUES))
|
25
25
|
|
26
|
-
DIRECT_VALUE_BEHAVIORS = [:retry_timeout, :connect_timeout, :socket_recv_size, :poll_timeout, :socket_send_size]
|
26
|
+
DIRECT_VALUE_BEHAVIORS = [:retry_timeout, :connect_timeout, :rcv_timeout, :socket_recv_size, :poll_timeout, :socket_send_size]
|
27
27
|
|
28
28
|
#:startdoc:
|
29
29
|
|
data/lib/memcached/exceptions.rb
CHANGED
@@ -66,21 +66,14 @@ Subclasses correspond one-to-one with server response strings or libmemcached er
|
|
66
66
|
end
|
67
67
|
|
68
68
|
class NotFound
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
69
|
+
attr_accessor :no_backtrace
|
70
|
+
|
71
|
+
def set_backtrace(*args)
|
72
|
+
@no_backtrace ? [] : super
|
74
73
|
end
|
75
74
|
|
76
|
-
def
|
77
|
-
|
78
|
-
begin
|
79
|
-
remove_method :set_backtrace
|
80
|
-
remove_method :backtrace
|
81
|
-
rescue NameError
|
82
|
-
end
|
83
|
-
end
|
75
|
+
def backtrace(*args)
|
76
|
+
@no_backtrace ? [] : super
|
84
77
|
end
|
85
78
|
end
|
86
79
|
|
data/lib/memcached/memcached.rb
CHANGED
@@ -9,46 +9,58 @@ class Memcached
|
|
9
9
|
DEFAULTS = {
|
10
10
|
:hash => :default,
|
11
11
|
:no_block => false,
|
12
|
-
:distribution => :
|
12
|
+
:distribution => :consistent_ketama,
|
13
|
+
:ketama_weighted => true,
|
13
14
|
:buffer_requests => false,
|
14
15
|
:cache_lookups => true,
|
15
16
|
:support_cas => false,
|
16
17
|
:tcp_nodelay => false,
|
17
|
-
:
|
18
|
+
:show_backtraces => false,
|
18
19
|
:retry_timeout => 60,
|
19
|
-
|
20
|
+
:timeout => 0.5,
|
20
21
|
:connect_timeout => 5,
|
21
22
|
:prefix_key => nil,
|
23
|
+
:hash_with_prefix_key => true,
|
24
|
+
:default_ttl => 604800,
|
25
|
+
:default_weight => 8,
|
22
26
|
:sort_hosts => false,
|
23
27
|
:failover => false,
|
24
28
|
:verify_key => true
|
25
|
-
}
|
26
|
-
|
29
|
+
}
|
30
|
+
|
27
31
|
#:stopdoc:
|
28
32
|
IGNORED = 0
|
29
|
-
|
30
|
-
NOTFOUND_INSTANCE = NotFound.new
|
31
33
|
#:startdoc:
|
32
|
-
|
34
|
+
|
33
35
|
attr_reader :options # Return the options Hash used to configure this instance.
|
34
36
|
|
35
37
|
###### Configuration
|
36
38
|
|
37
|
-
=begin rdoc
|
38
|
-
Create a new Memcached instance. Accepts
|
39
|
+
=begin rdoc
|
40
|
+
Create a new Memcached instance. Accepts string or array of server strings, as well an an optional configuration hash.
|
41
|
+
|
42
|
+
Memcached.new('localhost', ...) # A single server
|
43
|
+
Memcached.new(['web001:11212', 'web002:11212'], ...) # Two servers with custom ports
|
44
|
+
Memcached.new(['web001:11211:2', 'web002:11211:8'], ...) # Two servers with default ports and explicit weights
|
45
|
+
|
46
|
+
Weights only affect Ketama hashing. If you use Ketama hashing and don't specify a weight, the client will poll each server's stats and use its size as the weight.
|
39
47
|
|
40
48
|
Valid option parameters are:
|
41
49
|
|
42
|
-
<tt>:prefix_key</tt>:: A string to prepend to every key, for namespacing. Max length is
|
50
|
+
<tt>:prefix_key</tt>:: A string to prepend to every key, for namespacing. Max length is 127.
|
43
51
|
<tt>:hash</tt>:: The name of a hash function to use. Possible values are: <tt>:crc</tt>, <tt>:default</tt>, <tt>:fnv1_32</tt>, <tt>:fnv1_64</tt>, <tt>:fnv1a_32</tt>, <tt>:fnv1a_64</tt>, <tt>:hsieh</tt>, <tt>:md5</tt>, and <tt>:murmur</tt>. <tt>:default</tt> is the fastest. Use <tt>:md5</tt> for compatibility with other ketama clients.
|
44
|
-
<tt>:distribution</tt>:: Either <tt>:modula</tt>, <tt>:
|
52
|
+
<tt>:distribution</tt>:: Either <tt>:modula</tt>, <tt>:consistent_ketama</tt>, <tt>:consistent_wheel</tt>, or <tt>:ketama</tt>. Defaults to <tt>:ketama</tt>.
|
45
53
|
<tt>:failover</tt>:: Whether to permanently eject failed hosts from the pool. Defaults to <tt>false</tt>. Note that in the event of a server failure, <tt>:failover</tt> will remap the entire pool unless <tt>:distribution</tt> is set to <tt>:consistent</tt>.
|
46
54
|
<tt>:cache_lookups</tt>:: Whether to cache hostname lookups for the life of the instance. Defaults to <tt>true</tt>.
|
47
55
|
<tt>:support_cas</tt>:: Flag CAS support in the client. Accepts <tt>true</tt> or <tt>false</tt>. Defaults to <tt>false</tt> because it imposes a slight performance penalty. Note that your server must also support CAS or you will trigger <b>Memcached::ProtocolError</b> exceptions.
|
48
56
|
<tt>:tcp_nodelay</tt>:: Turns on the no-delay feature for connecting sockets. Accepts <tt>true</tt> or <tt>false</tt>. Performance may or may not change, depending on your system.
|
49
57
|
<tt>:no_block</tt>:: Whether to use non-blocking, asynchronous IO for writes. Accepts <tt>true</tt> or <tt>false</tt>.
|
50
58
|
<tt>:buffer_requests</tt>:: Whether to use an internal write buffer. Accepts <tt>true</tt> or <tt>false</tt>. Calling <tt>get</tt> or closing the connection will force the buffer to flush. Note that <tt>:buffer_requests</tt> might not work well without <tt>:no_block</tt> also enabled.
|
51
|
-
<tt>:
|
59
|
+
<tt>:show_backtraces</tt>:: Whether <b>Memcached::NotFound</b> exceptions should include backtraces. Generating backtraces is slow, so this is off by default. Turn it on to ease debugging.
|
60
|
+
<tt>:timeout</tt>:: How long to wait for a response from the server. Defaults to 0.5 seconds. Set to <tt>0</tt> if you want to wait forever.
|
61
|
+
<tt>:default_ttl</tt>:: The <tt>ttl</tt> to use on set if no <tt>ttl</tt> is specified, in seconds. Defaults to one week. Set to <tt>0</tt> if you want things to never expire.
|
62
|
+
<tt>:default_weight</tt>:: The weight to use if <tt>:ketama_weighted</tt> is <tt>true</tt>, but no weight is specified for a server.
|
63
|
+
<tt>:hash_with_prefix_key</tt>:: Whether to include the prefix when calculating which server a key falls on. Defaults to <tt>true</tt>.
|
52
64
|
<tt>:sort_hosts</tt>:: Whether to force the server list to stay sorted. This defeats consistent hashing and is rarely useful.
|
53
65
|
<tt>:verify_key</tt>:: Validate keys before accepting them. Never disable this.
|
54
66
|
|
@@ -57,25 +69,42 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
57
69
|
=end
|
58
70
|
|
59
71
|
def initialize(servers, opts = {})
|
60
|
-
@struct = Lib::MemcachedSt.new
|
72
|
+
@struct = Lib::MemcachedSt.new
|
61
73
|
Lib.memcached_create(@struct)
|
62
74
|
|
63
|
-
# Merge option defaults
|
64
|
-
@options = DEFAULTS.
|
65
|
-
|
75
|
+
# Merge option defaults and discard meaningless keys
|
76
|
+
@options = Hash[*DEFAULTS.map do |key, default|
|
77
|
+
[key, opts[key] || default]
|
78
|
+
end.flatten]
|
79
|
+
|
66
80
|
# Force :buffer_requests to use :no_block
|
67
81
|
# XXX Deleting the :no_block key should also work, but libmemcached doesn't seem to set it
|
68
82
|
# consistently
|
69
|
-
options[:no_block] = true if options[:buffer_requests]
|
70
|
-
|
83
|
+
options[:no_block] = true if options[:buffer_requests]
|
84
|
+
|
85
|
+
# Disallow weights without ketama
|
86
|
+
options.delete(:ketama_weighted) if options[:distribution] != :consistent_ketama
|
87
|
+
|
71
88
|
# Legacy accessor
|
72
89
|
options[:prefix_key] = options.delete(:namespace) if options[:namespace]
|
73
|
-
|
90
|
+
|
74
91
|
# Disallow :sort_hosts with consistent hashing
|
75
92
|
if options[:sort_hosts] and options[:distribution] == :consistent
|
76
93
|
raise ArgumentError, ":sort_hosts defeats :consistent hashing"
|
77
94
|
end
|
78
|
-
|
95
|
+
|
96
|
+
# Set timeouts
|
97
|
+
if options[:timeout] > 0
|
98
|
+
if options[:no_block]
|
99
|
+
options[:poll_timeout] = (options[:timeout] * 1_000).to_i
|
100
|
+
else
|
101
|
+
options[:poll_timeout] = 1
|
102
|
+
options[:rcv_timeout] = (options[:timeout] * 1_000_000).to_i
|
103
|
+
end
|
104
|
+
elsif options[:no_block]
|
105
|
+
raise ArgumentError, "Can't set :timeout => 0 when :no_block => true."
|
106
|
+
end
|
107
|
+
|
79
108
|
# Set the behaviors on the struct
|
80
109
|
set_behaviors
|
81
110
|
set_callbacks
|
@@ -84,46 +113,43 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
84
113
|
options.freeze
|
85
114
|
|
86
115
|
# Set the servers on the struct
|
87
|
-
set_servers(servers)
|
88
|
-
|
116
|
+
set_servers(servers)
|
117
|
+
|
89
118
|
# Not found exceptions
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
else
|
95
|
-
NotFound.remove_backtraces
|
96
|
-
end
|
119
|
+
unless options[:show_backtraces]
|
120
|
+
@not_found_instance = NotFound.new
|
121
|
+
@not_found_instance.no_backtrace = true
|
122
|
+
end
|
97
123
|
end
|
98
124
|
|
99
125
|
# Return the array of server strings used to configure this instance.
|
100
126
|
def servers
|
101
127
|
server_structs.map do |server|
|
102
|
-
|
128
|
+
inspect_server(server)
|
103
129
|
end
|
104
130
|
end
|
105
|
-
|
106
|
-
# Safely copy this instance. Returns a Memcached instance.
|
131
|
+
|
132
|
+
# Safely copy this instance. Returns a Memcached instance.
|
107
133
|
#
|
108
|
-
# <tt>clone</tt> is useful for threading, since each thread must have its own unshared Memcached
|
109
|
-
# object.
|
134
|
+
# <tt>clone</tt> is useful for threading, since each thread must have its own unshared Memcached
|
135
|
+
# object.
|
110
136
|
#
|
111
137
|
def clone
|
112
138
|
memcached = super
|
113
139
|
memcached.instance_variable_set('@struct', Lib.memcached_clone(nil, @struct))
|
114
140
|
memcached
|
115
141
|
end
|
116
|
-
|
142
|
+
|
117
143
|
# Reset the state of the libmemcached struct. This is useful for changing the server list at runtime.
|
118
144
|
def reset(current_servers = nil)
|
119
145
|
current_servers ||= servers
|
120
|
-
@struct = Lib::MemcachedSt.new
|
146
|
+
@struct = Lib::MemcachedSt.new
|
121
147
|
Lib.memcached_create(@struct)
|
122
148
|
set_behaviors
|
123
149
|
set_callbacks
|
124
150
|
set_servers(current_servers)
|
125
|
-
end
|
126
|
-
|
151
|
+
end
|
152
|
+
|
127
153
|
#:stopdoc:
|
128
154
|
alias :dup :clone #:nodoc:
|
129
155
|
#:startdoc:
|
@@ -131,44 +157,46 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
131
157
|
### Configuration helpers
|
132
158
|
|
133
159
|
private
|
134
|
-
|
160
|
+
|
135
161
|
# Return an array of raw <tt>memcached_host_st</tt> structs for this instance.
|
136
162
|
def server_structs
|
137
163
|
array = []
|
138
|
-
@struct.hosts
|
139
|
-
|
164
|
+
if @struct.hosts
|
165
|
+
@struct.hosts.count.times do |i|
|
166
|
+
array << Lib.memcached_select_server_at(@struct, i)
|
167
|
+
end
|
140
168
|
end
|
141
169
|
array
|
142
|
-
end
|
143
|
-
|
170
|
+
end
|
171
|
+
|
144
172
|
###### Operations
|
145
|
-
|
173
|
+
|
146
174
|
public
|
147
|
-
|
175
|
+
|
148
176
|
### Setters
|
149
|
-
|
177
|
+
|
150
178
|
# Set a key/value pair. Accepts a String <tt>key</tt> and an arbitrary Ruby object. Overwrites any existing value on the server.
|
151
179
|
#
|
152
|
-
# Accepts an optional <tt>
|
180
|
+
# Accepts an optional <tt>ttl</tt> value to specify the maximum lifetime of the key on the server. <tt>ttl</tt> can be either an integer number of seconds, or a Time elapsed time object. <tt>0</tt> means no ttl. Note that there is no guarantee that the key will persist as long as the <tt>ttl</tt>, but it will not persist longer.
|
153
181
|
#
|
154
|
-
# Also accepts a <tt>marshal</tt> value, which defaults to <tt>true</tt>. Set <tt>marshal</tt> to <tt>false</tt> if you want the <tt>value</tt> to be set directly.
|
155
|
-
#
|
156
|
-
def set(key, value,
|
182
|
+
# Also accepts a <tt>marshal</tt> value, which defaults to <tt>true</tt>. Set <tt>marshal</tt> to <tt>false</tt> if you want the <tt>value</tt> to be set directly.
|
183
|
+
#
|
184
|
+
def set(key, value, ttl=nil, marshal=true, flags=FLAGS)
|
157
185
|
value = marshal ? Marshal.dump(value) : value.to_s
|
158
186
|
check_return_code(
|
159
|
-
Lib.memcached_set(@struct, key, value,
|
187
|
+
Lib.memcached_set(@struct, key, value, ttl || options[:default_ttl], flags)
|
160
188
|
)
|
161
189
|
end
|
162
190
|
|
163
191
|
# Add a key/value pair. Raises <b>Memcached::NotStored</b> if the key already exists on the server. The parameters are the same as <tt>set</tt>.
|
164
|
-
def add(key, value,
|
192
|
+
def add(key, value, ttl=nil, marshal=true, flags=FLAGS)
|
165
193
|
value = marshal ? Marshal.dump(value) : value.to_s
|
166
194
|
check_return_code(
|
167
|
-
Lib.memcached_add(@struct, key, value,
|
195
|
+
Lib.memcached_add(@struct, key, value, ttl || options[:default_ttl], flags)
|
168
196
|
)
|
169
197
|
end
|
170
198
|
|
171
|
-
# Increment a key's value. Accepts a String <tt>key</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist.
|
199
|
+
# Increment a key's value. Accepts a String <tt>key</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist.
|
172
200
|
#
|
173
201
|
# Also accepts an optional <tt>offset</tt> paramater, which defaults to 1. <tt>offset</tt> must be an integer.
|
174
202
|
#
|
@@ -185,53 +213,53 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
185
213
|
check_return_code(ret)
|
186
214
|
value
|
187
215
|
end
|
188
|
-
|
189
|
-
#:stopdoc:
|
216
|
+
|
217
|
+
#:stopdoc:
|
190
218
|
alias :incr :increment
|
191
219
|
alias :decr :decrement
|
192
220
|
#:startdoc:
|
193
221
|
|
194
222
|
# Replace a key/value pair. Raises <b>Memcached::NotFound</b> if the key does not exist on the server. The parameters are the same as <tt>set</tt>.
|
195
|
-
def replace(key, value,
|
223
|
+
def replace(key, value, ttl=nil, marshal=true, flags=FLAGS)
|
196
224
|
value = marshal ? Marshal.dump(value) : value.to_s
|
197
225
|
check_return_code(
|
198
|
-
Lib.memcached_replace(@struct, key, value,
|
226
|
+
Lib.memcached_replace(@struct, key, value, ttl || options[:default_ttl], flags)
|
199
227
|
)
|
200
228
|
end
|
201
229
|
|
202
|
-
# Appends a string to a key's value. Accepts a String <tt>key</tt> and a String <tt>value</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist on the server.
|
230
|
+
# Appends a string to a key's value. Accepts a String <tt>key</tt> and a String <tt>value</tt>. Raises <b>Memcached::NotFound</b> if the key does not exist on the server.
|
203
231
|
#
|
204
232
|
# Note that the key must be initialized to an unmarshalled string first, via <tt>set</tt>, <tt>add</tt>, or <tt>replace</tt> with <tt>marshal</tt> set to <tt>false</tt>.
|
205
233
|
def append(key, value)
|
206
234
|
# Requires memcached 1.2.4
|
207
235
|
check_return_code(
|
208
|
-
Lib.memcached_append(@struct, key, value.to_s, IGNORED,
|
236
|
+
Lib.memcached_append(@struct, key, value.to_s, IGNORED, IGNORED)
|
209
237
|
)
|
210
238
|
end
|
211
|
-
|
239
|
+
|
212
240
|
# Prepends a string to a key's value. The parameters and exception behavior are the same as <tt>append</tt>.
|
213
241
|
def prepend(key, value)
|
214
242
|
# Requires memcached 1.2.4
|
215
243
|
check_return_code(
|
216
|
-
Lib.memcached_prepend(@struct, key, value.to_s, IGNORED,
|
244
|
+
Lib.memcached_prepend(@struct, key, value.to_s, IGNORED, IGNORED)
|
217
245
|
)
|
218
246
|
end
|
219
|
-
|
247
|
+
|
220
248
|
# Reads a key's value from the server and yields it to a block. Replaces the key's value with the result of the block as long as the key hasn't been updated in the meantime, otherwise raises <b>Memcached::NotStored</b>. Accepts a String <tt>key</tt> and a block.
|
221
249
|
#
|
222
|
-
# Also accepts an optional <tt>
|
250
|
+
# Also accepts an optional <tt>ttl</tt> value.
|
223
251
|
#
|
224
252
|
# CAS stands for "compare and swap", and avoids the need for manual key mutexing. CAS support must be enabled in Memcached.new or a <b>Memcached::ClientError</b> will be raised. Note that CAS may be buggy in memcached itself.
|
225
253
|
#
|
226
|
-
def cas(key,
|
254
|
+
def cas(key, ttl=nil, marshal=true, flags=FLAGS)
|
227
255
|
raise ClientError, "CAS not enabled for this Memcached instance" unless options[:support_cas]
|
228
|
-
|
256
|
+
|
229
257
|
value = get(key, marshal)
|
230
258
|
value = yield value
|
231
259
|
value = marshal ? Marshal.dump(value) : value.to_s
|
232
|
-
|
260
|
+
|
233
261
|
check_return_code(
|
234
|
-
Lib.memcached_cas(@struct, key, value,
|
262
|
+
Lib.memcached_cas(@struct, key, value, ttl || options[:default_ttl], flags, @struct.result.cas)
|
235
263
|
)
|
236
264
|
end
|
237
265
|
|
@@ -241,18 +269,18 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
241
269
|
def delete(key)
|
242
270
|
check_return_code(
|
243
271
|
Lib.memcached_delete(@struct, key, IGNORED)
|
244
|
-
)
|
272
|
+
)
|
245
273
|
end
|
246
|
-
|
274
|
+
|
247
275
|
# Flushes all key/value pairs from all the servers.
|
248
276
|
def flush
|
249
277
|
check_return_code(
|
250
278
|
Lib.memcached_flush(@struct, IGNORED)
|
251
279
|
)
|
252
280
|
end
|
253
|
-
|
254
|
-
### Getters
|
255
|
-
|
281
|
+
|
282
|
+
### Getters
|
283
|
+
|
256
284
|
# Gets a key's value from the server. Accepts a String <tt>key</tt> or array of String <tt>keys</tt>.
|
257
285
|
#
|
258
286
|
# Also accepts a <tt>marshal</tt> value, which defaults to <tt>true</tt>. Set <tt>marshal</tt> to <tt>false</tt> if you want the <tt>value</tt> to be returned directly as a String. Otherwise it will be assumed to be a marshalled Ruby object and unmarshalled.
|
@@ -266,13 +294,11 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
266
294
|
def get(keys, marshal=true)
|
267
295
|
if keys.is_a? Array
|
268
296
|
# Multi get
|
269
|
-
keys.map! { |key| key }
|
270
|
-
hash = {}
|
271
|
-
|
272
297
|
ret = Lib.memcached_mget(@struct, keys);
|
273
298
|
check_return_code(ret)
|
274
|
-
|
275
|
-
|
299
|
+
|
300
|
+
hash = {}
|
301
|
+
keys.size.times do
|
276
302
|
value, key, flags, ret = Lib.memcached_fetch_rvalue(@struct)
|
277
303
|
break if ret == Lib::MEMCACHED_END
|
278
304
|
check_return_code(ret)
|
@@ -287,88 +313,92 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
287
313
|
check_return_code(ret)
|
288
314
|
value = Marshal.load(value) if marshal
|
289
315
|
value
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
293
319
|
### Information methods
|
294
|
-
|
320
|
+
|
295
321
|
# Return a Hash of statistics responses from the set of servers. Each value is an array with one entry for each server, in the same order the servers were defined.
|
296
322
|
def stats
|
297
323
|
stats = Hash.new([])
|
298
|
-
|
324
|
+
|
299
325
|
stat_struct, ret = Lib.memcached_stat(@struct, "")
|
300
326
|
check_return_code(ret)
|
301
|
-
|
327
|
+
|
302
328
|
keys, ret = Lib.memcached_stat_get_keys(@struct, stat_struct)
|
303
329
|
check_return_code(ret)
|
304
|
-
|
330
|
+
|
305
331
|
keys.each do |key|
|
306
332
|
server_structs.size.times do |index|
|
307
333
|
|
308
334
|
value, ret = Lib.memcached_stat_get_rvalue(
|
309
|
-
@struct,
|
335
|
+
@struct,
|
310
336
|
Lib.memcached_select_stat_at(@struct, stat_struct, index),
|
311
337
|
key)
|
312
338
|
check_return_code(ret)
|
313
339
|
|
314
340
|
value = case value
|
315
|
-
when /^\d+\.\d+$/: value.to_f
|
341
|
+
when /^\d+\.\d+$/: value.to_f
|
316
342
|
when /^\d+$/: value.to_i
|
317
343
|
else value
|
318
|
-
end
|
319
|
-
|
344
|
+
end
|
345
|
+
|
320
346
|
stats[key.to_sym] += [value]
|
321
347
|
end
|
322
348
|
end
|
323
|
-
|
349
|
+
|
324
350
|
Lib.memcached_stat_free(@struct, stat_struct)
|
325
351
|
stats
|
326
|
-
end
|
327
|
-
|
352
|
+
end
|
353
|
+
|
328
354
|
### Operations helpers
|
329
|
-
|
355
|
+
|
330
356
|
private
|
331
|
-
|
357
|
+
|
332
358
|
# Checks the return code from Rlibmemcached against the exception list. Raises the corresponding exception if the return code is not Memcached::Success or Memcached::ActionQueued. Accepts an integer return code.
|
333
359
|
def check_return_code(ret) #:doc:
|
334
|
-
|
335
|
-
|
360
|
+
return if ret == 0 or # Lib::MEMCACHED_SUCCESS
|
361
|
+
ret == Lib::MEMCACHED_BUFFERED
|
336
362
|
|
337
363
|
# SystemError; eject from the pool
|
338
|
-
if ret ==
|
364
|
+
if ret == Lib::MEMCACHED_NOTFOUND and !options[:show_backtraces]
|
365
|
+
raise @not_found_instance
|
366
|
+
elsif options[:failover] and (ret == Lib::MEMCACHED_UNKNOWN_READ_FAILURE or ret == Lib::MEMCACHED_ERRNO)
|
339
367
|
failed = sweep_servers
|
340
368
|
raise EXCEPTIONS[ret], "Server #{failed} failed permanently"
|
341
369
|
else
|
342
|
-
raise EXCEPTIONS[ret], ""
|
370
|
+
raise EXCEPTIONS[ret], ""
|
343
371
|
end
|
344
|
-
end
|
372
|
+
end
|
345
373
|
|
346
374
|
# Eject the first dead server we find from the pool and reset the struct
|
347
375
|
def sweep_servers
|
348
376
|
# XXX This method is annoying, but necessary until we get Lib.memcached_delete_server or equivalent.
|
349
377
|
server_structs.each do |server|
|
350
|
-
if server.next_retry > Time.now
|
351
|
-
server_name =
|
378
|
+
if server.next_retry > Time.now
|
379
|
+
server_name = inspect_server(server)
|
352
380
|
current_servers = servers
|
353
|
-
current_servers.delete(server_name)
|
381
|
+
current_servers.delete(server_name)
|
354
382
|
reset(current_servers)
|
355
|
-
return server_name
|
383
|
+
return server_name
|
356
384
|
end
|
357
385
|
end
|
358
386
|
"(unknown)"
|
359
387
|
end
|
360
|
-
|
388
|
+
|
361
389
|
# Set the servers on the struct
|
362
390
|
def set_servers(servers)
|
363
391
|
Array(servers).each_with_index do |server, index|
|
364
|
-
unless server.is_a? String and server =~ /^[\w\d
|
365
|
-
raise ArgumentError, "Servers must be in the format host:port (e.g., 'localhost:11211')"
|
392
|
+
unless server.is_a? String and server =~ /^[\w\d\.-]+(:\d{1,5}){0,2}$/
|
393
|
+
raise ArgumentError, "Servers must be in the format host:port[:weight] (e.g., 'localhost:11211' or 'localhost:11211:10')"
|
366
394
|
end
|
367
|
-
host, port = server.split(":")
|
368
|
-
Lib.
|
369
|
-
end
|
395
|
+
host, port, weight = server.split(":")
|
396
|
+
Lib.memcached_server_add_with_weight(@struct, host, port.to_i, (weight || options[:default_weight]).to_i)
|
397
|
+
end
|
398
|
+
# For inspect
|
399
|
+
@servers = send(:servers)
|
370
400
|
end
|
371
|
-
|
401
|
+
|
372
402
|
# Set the behaviors on the struct from the current options
|
373
403
|
def set_behaviors
|
374
404
|
BEHAVIORS.keys.each do |behavior|
|
@@ -377,15 +407,19 @@ Please note that when non-blocking IO is enabled, setter and deleter methods do
|
|
377
407
|
end
|
378
408
|
|
379
409
|
# Set the callbacks on the struct from the current options
|
380
|
-
def set_callbacks
|
410
|
+
def set_callbacks
|
381
411
|
# Only support prefix_key for now
|
382
412
|
if options[:prefix_key]
|
383
|
-
|
384
|
-
if options[:prefix_key].size > Lib::MEMCACHED_PREFIX_KEY_MAX_SIZE - 1
|
413
|
+
unless options[:prefix_key].size < Lib::MEMCACHED_PREFIX_KEY_MAX_SIZE
|
385
414
|
raise ArgumentError, "Max prefix_key size is #{Lib::MEMCACHED_PREFIX_KEY_MAX_SIZE - 1}"
|
386
|
-
end
|
415
|
+
end
|
387
416
|
Lib.memcached_callback_set(@struct, Lib::MEMCACHED_CALLBACK_PREFIX_KEY, options[:prefix_key])
|
388
417
|
end
|
389
418
|
end
|
390
419
|
|
420
|
+
# Stringify an opaque server struct
|
421
|
+
def inspect_server(server)
|
422
|
+
"#{server.hostname}:#{server.port}#{":#{server.weight}" if options[:ketama_weighted]}"
|
423
|
+
end
|
424
|
+
|
391
425
|
end
|