dalli 2.7.2 → 2.7.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dalli might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +14 -0
- data/README.md +18 -14
- data/Rakefile +1 -0
- data/lib/active_support/cache/dalli_store.rb +24 -15
- data/lib/dalli/client.rb +14 -10
- data/lib/dalli/ring.rb +1 -1
- data/lib/dalli/server.rb +48 -23
- data/lib/dalli/socket.rb +74 -40
- data/lib/dalli/version.rb +1 -1
- data/test/benchmark_test.rb +3 -2
- data/test/helper.rb +3 -2
- data/test/memcached_mock.rb +97 -17
- data/test/sasl/memcached.conf +1 -0
- data/test/{sasldb → sasl/sasldb} +0 -0
- data/test/test_active_support.rb +163 -61
- data/test/test_cas_client.rb +7 -7
- data/test/test_compressor.rb +4 -5
- data/test/test_dalli.rb +92 -35
- data/test/test_encoding.rb +2 -2
- data/test/test_failover.rb +44 -35
- data/test/test_network.rb +10 -0
- data/test/test_rack_session.rb +3 -3
- data/test/test_ring.rb +2 -2
- data/test/test_sasl.rb +9 -14
- data/test/test_serializer.rb +6 -7
- data/test/test_server.rb +30 -0
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d251aba11eb6809a22a244864c5d8d509347dac9
|
4
|
+
data.tar.gz: 5d3cb28222688e09fc202179a7bc98b2546268d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6741b307e4311f199c8bcbaf8981838f5e3a82f920e37d138663f35fc96900b5f5f040be67358381c3b4b90893cb7e30e8871b0a6bd5fe0c10d604741d0e5a1e
|
7
|
+
data.tar.gz: 40f41b7bfb6d9de9e99cf4fcafc06112c3776c297bfe52f9525ef45209ff92e3aa52ee8831de66ea4e07f2ab3165481dae8c8d03175a0e3bda78453df4145845
|
data/History.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
Dalli Changelog
|
2
2
|
=====================
|
3
3
|
|
4
|
+
2.7.3
|
5
|
+
==========
|
6
|
+
|
7
|
+
- Assorted spec improvements
|
8
|
+
- README changes to specify defaults for failover and compress options (keen99, #470)
|
9
|
+
- SASL authentication changes to deal with Unicode characters (flypiggy, #477)
|
10
|
+
- Call to_i on ttl to accomodate ActiveSupport::Duration (#494)
|
11
|
+
- Change to implicit blocks for performance (glaucocustodio, #495)
|
12
|
+
- Change to each_key for performance (jastix, #496)
|
13
|
+
- Support stats settings - (dterei, #500)
|
14
|
+
- Raise DallError if hostname canno be parsed (dannyfallon, #501)
|
15
|
+
- Fix instrumentation for falsey values (AlexRiedler, #514)
|
16
|
+
- Support UNIX socket configurations (r-stu31, #515)
|
17
|
+
|
4
18
|
2.7.2
|
5
19
|
==========
|
6
20
|
|
data/README.md
CHANGED
@@ -44,7 +44,7 @@ If you have problems, please enter an issue.
|
|
44
44
|
Installation and Usage
|
45
45
|
------------------------
|
46
46
|
|
47
|
-
Remember, Dalli **requires** memcached 1.4+. You can check the version with `memcached -h`. Please note that memcached that Mac OS X Snow Leopard ships with is 1.2.8 and won't work. Install 1.4.x using Homebrew with
|
47
|
+
Remember, Dalli **requires** memcached 1.4+. You can check the version with `memcached -h`. Please note that the memcached version that *Mac OS X Snow Leopard* ships with is 1.2.8 and it won't work. Install memcached 1.4.x using Homebrew with
|
48
48
|
|
49
49
|
brew install memcached
|
50
50
|
|
@@ -130,7 +130,7 @@ add :pool\_size to your `dalli_store` config:
|
|
130
130
|
config.cache_store = :dalli_store, 'cache-1.example.com', { :pool_size => 5 }
|
131
131
|
```
|
132
132
|
|
133
|
-
You can then use the Rails cache as normal or check out a Dalli client directly from the pool:
|
133
|
+
You can then use the Rails cache as normal and Rails.cache will use the pool transparently under the covers, or you can check out a Dalli client directly from the pool:
|
134
134
|
|
135
135
|
```ruby
|
136
136
|
Rails.cache.fetch('foo', :expires_in => 300) do
|
@@ -151,16 +151,26 @@ Dalli::Client accepts the following options. All times are in seconds.
|
|
151
151
|
|
152
152
|
**expires_in**: Global default for key TTL. Default is 0, which means no expiry.
|
153
153
|
|
154
|
-
**
|
154
|
+
**namespace**: If specified, prepends each key with this value to provide simple namespacing. Default is nil.
|
155
155
|
|
156
|
-
**
|
156
|
+
**failover**: Boolean, if true Dalli will failover to another server if the main server for a key is down. Default is true.
|
157
|
+
|
158
|
+
**threadsafe**: Boolean. If true Dalli ensures that only one thread is using a socket at a given time. Default is true. Set to false at your own peril.
|
159
|
+
|
160
|
+
**serializer**: The serializer to use for objects being stored (ex. JSON).
|
161
|
+
Default is Marshal.
|
162
|
+
|
163
|
+
**compress**: Boolean, if true Dalli will gzip-compress values larger than 1K. Default is false.
|
157
164
|
|
158
165
|
**compression_min_size**: Minimum value byte size for which to attempt compression. Default is 1K.
|
159
166
|
|
160
167
|
**compression_max_size**: Maximum value byte size for which to attempt compression. Default is unlimited.
|
161
168
|
|
162
|
-
**
|
163
|
-
Default is
|
169
|
+
**compressor**: The compressor to use for objects being stored.
|
170
|
+
Default is zlib, implemented under `Dalli::Compressor`.
|
171
|
+
If serving compressed data using nginx's HttpMemcachedModule, set `memcached_gzip_flag 2` and use `Dalli::GzipCompressor`
|
172
|
+
|
173
|
+
**keepalive**: Boolean. If true, Dalli will enable keep-alive for socket connections. Default is true.
|
164
174
|
|
165
175
|
**socket_timeout**: Timeout for all socket operations (connect, read, write). Default is 0.5.
|
166
176
|
|
@@ -168,7 +178,7 @@ Default is Marshal.
|
|
168
178
|
|
169
179
|
**socket_failure_delay**: Before retrying a socket operation, the process sleeps for this amount of time. Default is 0.01. Set to nil for no delay.
|
170
180
|
|
171
|
-
**down_retry_delay**: When a server has been marked down due to many failures, the server will be checked again for being alive only after this amount of time. Don't set this value
|
181
|
+
**down_retry_delay**: When a server has been marked down due to many failures, the server will be checked again for being alive only after this amount of time. Don't set this value too low, otherwise each request which tries the failed server might hang for the maximum **socket_timeout**. Default is 1 second.
|
172
182
|
|
173
183
|
**value_max_bytes**: The maximum size of a value in memcached. Defaults to 1MB, this can be increased with memcached's -I parameter. You must also configure Dalli to allow the larger size here.
|
174
184
|
|
@@ -176,12 +186,6 @@ Default is Marshal.
|
|
176
186
|
|
177
187
|
**password**: The password to use for authenticating this client instance against a SASL-enabled memcached server. Heroku users should not need to use this normally.
|
178
188
|
|
179
|
-
**keepalive**: Boolean. If true, Dalli will enable keep-alive for socket connections. Default is true.
|
180
|
-
|
181
|
-
**compressor**: The compressor to use for objects being stored.
|
182
|
-
Default is zlib, implemented under `Dalli::Compressor`.
|
183
|
-
If serving compressed data using nginx's HttpMemcachedModule, set `memcached_gzip_flag 2` and use `Dalli::GzipCompressor`
|
184
|
-
|
185
189
|
Features and Changes
|
186
190
|
------------------------
|
187
191
|
|
@@ -205,7 +209,7 @@ We're not accepting new compressors. They are trivial to add in an initializer.
|
|
205
209
|
Thanks
|
206
210
|
------------
|
207
211
|
|
208
|
-
Eric Wong - for help using his [kgio](http://
|
212
|
+
Eric Wong - for help using his [kgio](http://bogomips.org/kgio/) library.
|
209
213
|
|
210
214
|
Brian Mitchell - for his remix-stash project which was helpful when implementing and testing the binary protocol support.
|
211
215
|
|
data/Rakefile
CHANGED
@@ -83,15 +83,15 @@ module ActiveSupport
|
|
83
83
|
|
84
84
|
def fetch(name, options=nil)
|
85
85
|
options ||= {}
|
86
|
-
|
86
|
+
namespaced_name = namespaced_key(name, options)
|
87
87
|
|
88
88
|
if block_given?
|
89
89
|
unless options[:force]
|
90
|
-
entry = instrument(:read,
|
91
|
-
read_entry(
|
90
|
+
entry = instrument(:read, namespaced_name, options) do |payload|
|
91
|
+
read_entry(namespaced_name, options).tap do |result|
|
92
92
|
if payload
|
93
93
|
payload[:super_operation] = :fetch
|
94
|
-
payload[:hit] =
|
94
|
+
payload[:hit] = !result.nil?
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
@@ -114,18 +114,18 @@ module ActiveSupport
|
|
114
114
|
|
115
115
|
def read(name, options=nil)
|
116
116
|
options ||= {}
|
117
|
-
name =
|
117
|
+
name = namespaced_key(name, options)
|
118
118
|
|
119
119
|
instrument(:read, name, options) do |payload|
|
120
120
|
entry = read_entry(name, options)
|
121
|
-
payload[:hit] =
|
121
|
+
payload[:hit] = !entry.nil? if payload
|
122
122
|
entry
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
126
|
def write(name, value, options=nil)
|
127
127
|
options ||= {}
|
128
|
-
name =
|
128
|
+
name = namespaced_key(name, options)
|
129
129
|
|
130
130
|
instrument(:write, name, options) do |payload|
|
131
131
|
with do |connection|
|
@@ -137,7 +137,7 @@ module ActiveSupport
|
|
137
137
|
|
138
138
|
def exist?(name, options=nil)
|
139
139
|
options ||= {}
|
140
|
-
name =
|
140
|
+
name = namespaced_key(name, options)
|
141
141
|
|
142
142
|
log(:exist, name, options)
|
143
143
|
!read_entry(name, options).nil?
|
@@ -145,7 +145,7 @@ module ActiveSupport
|
|
145
145
|
|
146
146
|
def delete(name, options=nil)
|
147
147
|
options ||= {}
|
148
|
-
name =
|
148
|
+
name = namespaced_key(name, options)
|
149
149
|
|
150
150
|
instrument(:delete, name, options) do |payload|
|
151
151
|
delete_entry(name, options)
|
@@ -155,12 +155,12 @@ module ActiveSupport
|
|
155
155
|
# Reads multiple keys from the cache using a single call to the
|
156
156
|
# servers for all keys. Keys must be Strings.
|
157
157
|
def read_multi(*names)
|
158
|
-
names.extract_options!
|
159
|
-
mapping = names.inject({}) { |memo, name| memo[
|
158
|
+
options = names.extract_options!
|
159
|
+
mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
|
160
160
|
instrument(:read_multi, names) do
|
161
161
|
results = {}
|
162
162
|
if local_cache
|
163
|
-
mapping.
|
163
|
+
mapping.each_key do |key|
|
164
164
|
if value = local_cache.read_entry(key, options)
|
165
165
|
results[key] = value
|
166
166
|
end
|
@@ -186,7 +186,7 @@ module ActiveSupport
|
|
186
186
|
# and the result will be written to the cache and returned.
|
187
187
|
def fetch_multi(*names)
|
188
188
|
options = names.extract_options!
|
189
|
-
mapping = names.inject({}) { |memo, name| memo[
|
189
|
+
mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
|
190
190
|
|
191
191
|
instrument(:fetch_multi, names) do
|
192
192
|
with do |connection|
|
@@ -216,7 +216,7 @@ module ActiveSupport
|
|
216
216
|
# memcached counters cannot hold negative values.
|
217
217
|
def increment(name, amount = 1, options=nil)
|
218
218
|
options ||= {}
|
219
|
-
name =
|
219
|
+
name = namespaced_key(name, options)
|
220
220
|
initial = options.has_key?(:initial) ? options[:initial] : amount
|
221
221
|
expires_in = options[:expires_in]
|
222
222
|
instrument(:increment, name, :amount => amount) do
|
@@ -235,7 +235,7 @@ module ActiveSupport
|
|
235
235
|
# memcached counters cannot hold negative values.
|
236
236
|
def decrement(name, amount = 1, options=nil)
|
237
237
|
options ||= {}
|
238
|
-
name =
|
238
|
+
name = namespaced_key(name, options)
|
239
239
|
initial = options.has_key?(:initial) ? options[:initial] : 0
|
240
240
|
expires_in = options[:expires_in]
|
241
241
|
instrument(:decrement, name, :amount => amount) do
|
@@ -317,6 +317,15 @@ module ActiveSupport
|
|
317
317
|
end
|
318
318
|
|
319
319
|
private
|
320
|
+
|
321
|
+
def namespaced_key(key, options)
|
322
|
+
key = expanded_key(key)
|
323
|
+
namespace = options[:namespace] if options
|
324
|
+
prefix = namespace.is_a?(Proc) ? namespace.call : namespace
|
325
|
+
key = "#{prefix}:#{key}" if prefix
|
326
|
+
key
|
327
|
+
end
|
328
|
+
|
320
329
|
# Expand key to be a consistent string value. Invoke +cache_key+ if
|
321
330
|
# object responds to +cache_key+. Otherwise, to_param method will be
|
322
331
|
# called. If the key is a Hash, then keys will be sorted alphabetically.
|
data/lib/dalli/client.rb
CHANGED
@@ -9,12 +9,15 @@ module Dalli
|
|
9
9
|
# Dalli::Client is the main class which developers will use to interact with
|
10
10
|
# the memcached server. Usage:
|
11
11
|
#
|
12
|
-
# Dalli::Client.new(['localhost:11211:10', 'cache-2.example.com:11211:5', '192.168.0.1:22122:5'],
|
12
|
+
# Dalli::Client.new(['localhost:11211:10', 'cache-2.example.com:11211:5', '192.168.0.1:22122:5', '/var/run/memcached/socket'],
|
13
13
|
# :threadsafe => true, :failover => true, :expires_in => 300)
|
14
14
|
#
|
15
15
|
# servers is an Array of "host:port:weight" where weight allows you to distribute cache unevenly.
|
16
16
|
# Both weight and port are optional. If you pass in nil, Dalli will use the <tt>MEMCACHE_SERVERS</tt>
|
17
|
-
# environment variable or default to 'localhost:11211' if it is not present.
|
17
|
+
# environment variable or default to 'localhost:11211' if it is not present. Dalli also supports
|
18
|
+
# the ability to connect to Memcached on localhost through a UNIX socket. To use this functionality,
|
19
|
+
# use a full pathname (beginning with a slash character '/') in place of the "host:port" pair in
|
20
|
+
# the server configuration.
|
18
21
|
#
|
19
22
|
# Options:
|
20
23
|
# - :namespace - prepend each key with this value to provide simple namespacing.
|
@@ -58,10 +61,11 @@ module Dalli
|
|
58
61
|
# If a block is given, yields key/value pairs one at a time.
|
59
62
|
# Otherwise returns a hash of { 'key' => 'value', 'key2' => 'value1' }
|
60
63
|
def get_multi(*keys)
|
64
|
+
return {} if keys.flatten.compact.empty?
|
61
65
|
if block_given?
|
62
66
|
get_multi_yielder(keys) {|k, data| yield k, data.first}
|
63
67
|
else
|
64
|
-
|
68
|
+
Hash.new.tap do |hash|
|
65
69
|
get_multi_yielder(keys) {|k, data| hash[k] = data.first}
|
66
70
|
end
|
67
71
|
end
|
@@ -88,12 +92,12 @@ module Dalli
|
|
88
92
|
# - nil if the key did not exist.
|
89
93
|
# - false if the value was changed by someone else.
|
90
94
|
# - true if the value was successfully updated.
|
91
|
-
def cas(key, ttl=nil, options=nil
|
95
|
+
def cas(key, ttl=nil, options=nil)
|
92
96
|
ttl ||= @options[:expires_in].to_i
|
93
97
|
(value, cas) = perform(:cas, key)
|
94
98
|
value = (!value || value == 'Not found') ? nil : value
|
95
99
|
if value
|
96
|
-
newvalue =
|
100
|
+
newvalue = yield(value)
|
97
101
|
perform(:set, key, newvalue, ttl, cas, options)
|
98
102
|
end
|
99
103
|
end
|
@@ -193,13 +197,13 @@ module Dalli
|
|
193
197
|
|
194
198
|
##
|
195
199
|
# Collect the stats for each server.
|
196
|
-
# You can optionally pass a type including :items or :
|
200
|
+
# You can optionally pass a type including :items, :slabs or :settings to get specific stats
|
197
201
|
# Returns a hash like { 'hostname:port' => { 'stat1' => 'value1', ... }, 'hostname2:port' => { ... } }
|
198
202
|
def stats(type=nil)
|
199
|
-
type = nil if ![nil, :items,:slabs].include? type
|
203
|
+
type = nil if ![nil, :items,:slabs,:settings].include? type
|
200
204
|
values = {}
|
201
205
|
ring.servers.each do |server|
|
202
|
-
values["#{server.
|
206
|
+
values["#{server.name}"] = server.alive? ? server.request(:stats,type.to_s) : nil
|
203
207
|
end
|
204
208
|
values
|
205
209
|
end
|
@@ -223,7 +227,7 @@ module Dalli
|
|
223
227
|
def version
|
224
228
|
values = {}
|
225
229
|
ring.servers.each do |server|
|
226
|
-
values["#{server.
|
230
|
+
values["#{server.name}"] = server.alive? ? server.request(:version) : nil
|
227
231
|
end
|
228
232
|
values
|
229
233
|
end
|
@@ -272,7 +276,7 @@ module Dalli
|
|
272
276
|
server.request(:send_multiget, keys_for_server)
|
273
277
|
rescue DalliError, NetworkError => e
|
274
278
|
Dalli.logger.debug { e.inspect }
|
275
|
-
Dalli.logger.debug { "unable to get keys for server #{server.
|
279
|
+
Dalli.logger.debug { "unable to get keys for server #{server.name}" }
|
276
280
|
end
|
277
281
|
end
|
278
282
|
end
|
data/lib/dalli/ring.rb
CHANGED
@@ -15,7 +15,7 @@ module Dalli
|
|
15
15
|
continuum = []
|
16
16
|
servers.each do |server|
|
17
17
|
entry_count_for(server, servers.size, total_weight).times do |idx|
|
18
|
-
hash = Digest::SHA1.hexdigest("#{server.
|
18
|
+
hash = Digest::SHA1.hexdigest("#{server.name}:#{idx}")
|
19
19
|
value = Integer("0x#{hash[0..7]}")
|
20
20
|
continuum << Dalli::Ring::Entry.new(value, server)
|
21
21
|
end
|
data/lib/dalli/server.rb
CHANGED
@@ -8,7 +8,10 @@ module Dalli
|
|
8
8
|
attr_accessor :weight
|
9
9
|
attr_accessor :options
|
10
10
|
attr_reader :sock
|
11
|
+
attr_reader :socket_type # possible values: :unix, :tcp
|
11
12
|
|
13
|
+
DEFAULT_PORT = 11211
|
14
|
+
DEFAULT_WEIGHT = 1
|
12
15
|
DEFAULTS = {
|
13
16
|
# seconds between trying to contact a remote server
|
14
17
|
:down_retry_delay => 1,
|
@@ -32,11 +35,7 @@ module Dalli
|
|
32
35
|
}
|
33
36
|
|
34
37
|
def initialize(attribs, options = {})
|
35
|
-
|
36
|
-
@port ||= 11211
|
37
|
-
@port = Integer(@port)
|
38
|
-
@weight ||= 1
|
39
|
-
@weight = Integer(@weight)
|
38
|
+
@hostname, @port, @weight, @socket_type = parse_hostname(attribs)
|
40
39
|
@fail_count = 0
|
41
40
|
@down_at = nil
|
42
41
|
@last_down_at = nil
|
@@ -49,13 +48,17 @@ module Dalli
|
|
49
48
|
end
|
50
49
|
|
51
50
|
def name
|
52
|
-
|
51
|
+
if socket_type == :unix
|
52
|
+
hostname
|
53
|
+
else
|
54
|
+
"#{hostname}:#{port}"
|
55
|
+
end
|
53
56
|
end
|
54
57
|
|
55
58
|
# Chokepoint method for instrumentation
|
56
59
|
def request(op, *args)
|
57
60
|
verify_state
|
58
|
-
raise Dalli::NetworkError, "#{
|
61
|
+
raise Dalli::NetworkError, "#{name} is down: #{@error} #{@msg}. If you are sure it is running, ensure memcached version is > 1.4." unless alive?
|
59
62
|
begin
|
60
63
|
send(op, *args)
|
61
64
|
rescue Dalli::NetworkError
|
@@ -67,9 +70,10 @@ module Dalli
|
|
67
70
|
false
|
68
71
|
rescue Dalli::DalliError
|
69
72
|
raise
|
73
|
+
rescue Timeout::Error
|
74
|
+
raise
|
70
75
|
rescue => ex
|
71
|
-
Dalli.logger.error "Unexpected exception
|
72
|
-
Dalli.logger.error "This is a bug in Dalli, please enter an issue in Github if it does not already exist."
|
76
|
+
Dalli.logger.error "Unexpected exception during Dalli request: #{ex.class.name}: #{ex.message}"
|
73
77
|
Dalli.logger.error ex.backtrace.join("\n\t")
|
74
78
|
down!
|
75
79
|
end
|
@@ -80,7 +84,7 @@ module Dalli
|
|
80
84
|
|
81
85
|
if @last_down_at && @last_down_at + options[:down_retry_delay] >= Time.now
|
82
86
|
time = @last_down_at + options[:down_retry_delay] - Time.now
|
83
|
-
Dalli.logger.debug { "down_retry_delay not reached for #{
|
87
|
+
Dalli.logger.debug { "down_retry_delay not reached for #{name} (%.3f seconds left)" % time }
|
84
88
|
return false
|
85
89
|
end
|
86
90
|
|
@@ -203,7 +207,7 @@ module Dalli
|
|
203
207
|
end
|
204
208
|
|
205
209
|
def failure!(exception)
|
206
|
-
message = "#{
|
210
|
+
message = "#{name} failed (count: #{@fail_count}) #{exception.class}: #{exception.message}"
|
207
211
|
Dalli.logger.info { message }
|
208
212
|
|
209
213
|
@fail_count += 1
|
@@ -223,21 +227,21 @@ module Dalli
|
|
223
227
|
|
224
228
|
if @down_at
|
225
229
|
time = Time.now - @down_at
|
226
|
-
Dalli.logger.debug { "#{
|
230
|
+
Dalli.logger.debug { "#{name} is still down (for %.3f seconds now)" % time }
|
227
231
|
else
|
228
232
|
@down_at = @last_down_at
|
229
|
-
Dalli.logger.warn { "#{
|
233
|
+
Dalli.logger.warn { "#{name} is down" }
|
230
234
|
end
|
231
235
|
|
232
236
|
@error = $! && $!.class.name
|
233
237
|
@msg = @msg || ($! && $!.message && !$!.message.empty? && $!.message)
|
234
|
-
raise Dalli::NetworkError, "#{
|
238
|
+
raise Dalli::NetworkError, "#{name} is down: #{@error} #{@msg}"
|
235
239
|
end
|
236
240
|
|
237
241
|
def up!
|
238
242
|
if @down_at
|
239
243
|
time = Time.now - @down_at
|
240
|
-
Dalli.logger.warn { "#{
|
244
|
+
Dalli.logger.warn { "#{name} is back (downtime was %.3f seconds)" % time }
|
241
245
|
end
|
242
246
|
|
243
247
|
@fail_count = 0
|
@@ -396,6 +400,8 @@ module Dalli
|
|
396
400
|
marshalled = true
|
397
401
|
begin
|
398
402
|
self.serializer.dump(value)
|
403
|
+
rescue TimeoutError => e
|
404
|
+
raise e
|
399
405
|
rescue => ex
|
400
406
|
# Marshalling can throw several different types of generic Ruby exceptions.
|
401
407
|
# Convert to a specific exception so we can special case it higher up the stack.
|
@@ -467,9 +473,9 @@ module Dalli
|
|
467
473
|
def sanitize_ttl(ttl)
|
468
474
|
if ttl > MAX_ACCEPTABLE_EXPIRATION_INTERVAL
|
469
475
|
Dalli.logger.debug "Expiration interval too long for Memcached, converting to an expiration timestamp"
|
470
|
-
Time.now.to_i + ttl
|
476
|
+
Time.now.to_i + ttl.to_i
|
471
477
|
else
|
472
|
-
ttl
|
478
|
+
ttl.to_i
|
473
479
|
end
|
474
480
|
end
|
475
481
|
|
@@ -555,13 +561,17 @@ module Dalli
|
|
555
561
|
end
|
556
562
|
|
557
563
|
def connect
|
558
|
-
Dalli.logger.debug { "Dalli::Server#connect #{
|
564
|
+
Dalli.logger.debug { "Dalli::Server#connect #{name}" }
|
559
565
|
|
560
566
|
begin
|
561
567
|
@pid = Process.pid
|
562
|
-
|
563
|
-
|
568
|
+
if socket_type == :unix
|
569
|
+
@sock = KSocket::UNIX.open(hostname, self, options)
|
570
|
+
else
|
571
|
+
@sock = KSocket::TCP.open(hostname, port, self, options)
|
572
|
+
end
|
564
573
|
sasl_authentication if need_auth?
|
574
|
+
@version = version # trigger actual connect
|
565
575
|
up!
|
566
576
|
rescue Dalli::DalliError # SASL auth failure
|
567
577
|
raise
|
@@ -666,7 +676,7 @@ module Dalli
|
|
666
676
|
|
667
677
|
(extras, type, status, count) = read_header.unpack(NORMAL_HEADER)
|
668
678
|
raise Dalli::NetworkError, "Unexpected message format: #{extras} #{count}" unless extras == 0 && count > 0
|
669
|
-
content = read(count)
|
679
|
+
content = read(count).gsub(/\u0000/, ' ')
|
670
680
|
return (Dalli.logger.debug("Authentication not required/supported by server")) if status == 0x81
|
671
681
|
mechanisms = content.split(' ')
|
672
682
|
raise NotImplementedError, "Dalli only supports the PLAIN authentication mechanism" if !mechanisms.include?('PLAIN')
|
@@ -689,8 +699,23 @@ module Dalli
|
|
689
699
|
end
|
690
700
|
|
691
701
|
def parse_hostname(str)
|
692
|
-
res = str.match(/\A(\[([\h:]+)\]|[^:]+)(
|
693
|
-
|
702
|
+
res = str.match(/\A(\[([\h:]+)\]|[^:]+)(?::(\d+))?(?::(\d+))?\z/)
|
703
|
+
raise Dalli::DalliError, "Could not parse hostname #{str}" if res.nil? || res[1] == '[]'
|
704
|
+
hostnam = res[2] || res[1]
|
705
|
+
if hostnam =~ /\A\//
|
706
|
+
socket_type = :unix
|
707
|
+
# in case of unix socket, allow only setting of weight, not port
|
708
|
+
raise Dalli::DalliError, "Could not parse hostname #{str}" if res[4]
|
709
|
+
weigh = res[3]
|
710
|
+
else
|
711
|
+
socket_type = :tcp
|
712
|
+
por = res[3] || DEFAULT_PORT
|
713
|
+
por = Integer(por)
|
714
|
+
weigh = res[4]
|
715
|
+
end
|
716
|
+
weigh ||= DEFAULT_WEIGHT
|
717
|
+
weigh = Integer(weigh)
|
718
|
+
return hostnam, por, weigh, socket_type
|
694
719
|
end
|
695
720
|
end
|
696
721
|
end
|