dalli 1.0.0 → 1.0.1
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.
- data/History.md +11 -0
- data/README.md +6 -1
- data/Rakefile +5 -0
- data/lib/active_support/cache/dalli_store23.rb +2 -1
- data/lib/dalli/client.rb +2 -4
- data/lib/dalli/server.rb +19 -20
- data/lib/dalli/version.rb +1 -1
- data/test/test_dalli.rb +12 -0
- data/test/test_sasl.rb +27 -3
- metadata +3 -6
- data/lib/dalli/sasl/anonymous.rb +0 -14
- data/lib/dalli/sasl/base.rb +0 -89
- data/lib/dalli/sasl/plain.rb +0 -18
data/History.md
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
Dalli Changelog
|
2
2
|
=====================
|
3
3
|
|
4
|
+
1.0.1
|
5
|
+
=======
|
6
|
+
|
7
|
+
- Explicitly handle application marshalling bugs, GH-56
|
8
|
+
- Add support for username/password as options, to allow multiple bucket access
|
9
|
+
from the same Ruby process, GH-52
|
10
|
+
- Add support for >1MB values with :value_max_bytes option, GH-54 (r-stu31)
|
11
|
+
- Add support for default TTL, :expires_in, in Rails 2.3. (Steven Novotny)
|
12
|
+
config.cache_store = :dalli_store, 'localhost:11211', {:expires_in => 4.hours}
|
13
|
+
|
14
|
+
|
4
15
|
1.0.0
|
5
16
|
=======
|
6
17
|
|
data/README.md
CHANGED
@@ -128,8 +128,13 @@ Dalli::Client accepts the following options. All times are in seconds.
|
|
128
128
|
|
129
129
|
**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.
|
130
130
|
|
131
|
-
**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 to low, otherwise each request which tries the failed server might hang for the maximum
|
131
|
+
**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 to low, otherwise each request which tries the failed server might hang for the maximum **socket_timeout**. Default is 1 second.
|
132
132
|
|
133
|
+
**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.
|
134
|
+
|
135
|
+
**username**: The username to use for authenticating this client instance against a SASL-enabled memcached server. Heroku users should not need to use this normally.
|
136
|
+
|
137
|
+
**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.
|
133
138
|
|
134
139
|
Features and Changes
|
135
140
|
------------------------
|
data/Rakefile
CHANGED
@@ -37,6 +37,7 @@ module ActiveSupport
|
|
37
37
|
|
38
38
|
mem_cache_options = options.dup
|
39
39
|
@namespace = mem_cache_options.delete(:namespace)
|
40
|
+
@expires_in = mem_cache_options[:expires_in]
|
40
41
|
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
41
42
|
|
42
43
|
extend Strategy::LocalCache
|
@@ -154,7 +155,7 @@ module ActiveSupport
|
|
154
155
|
|
155
156
|
# Exists in 2.3.8 but not in 2.3.2 so roll our own version
|
156
157
|
def expires_in(options)
|
157
|
-
expires_in = options && options[:expires_in]
|
158
|
+
expires_in = (options && options[:expires_in]) || @expires_in
|
158
159
|
|
159
160
|
raise ":expires_in must be a number" if expires_in && !expires_in.is_a?(Numeric)
|
160
161
|
|
data/lib/dalli/client.rb
CHANGED
@@ -19,7 +19,7 @@ module Dalli
|
|
19
19
|
# - :threadsafe - ensure that only one thread is actively using a socket at a time. Default: true.
|
20
20
|
# - :expires_in - default TTL in seconds if you do not pass TTL as a parameter to an individual operation, defaults to 0 or forever
|
21
21
|
# - :compression - defaults to false, if true Dalli will compress values larger than 100 bytes before
|
22
|
-
#
|
22
|
+
# sending them to memcached.
|
23
23
|
#
|
24
24
|
def initialize(servers=nil, options={})
|
25
25
|
@servers = env_servers || servers || 'localhost:11211'
|
@@ -145,9 +145,7 @@ module Dalli
|
|
145
145
|
end
|
146
146
|
|
147
147
|
# deprecated, please use #flush.
|
148
|
-
|
149
|
-
flush(delay)
|
150
|
-
end
|
148
|
+
alias_method :flush_all, :flush
|
151
149
|
|
152
150
|
##
|
153
151
|
# Incr adds the given amount to the counter on the memcached server.
|
data/lib/dalli/server.rb
CHANGED
@@ -17,7 +17,11 @@ module Dalli
|
|
17
17
|
# times a socket operation may fail before considering the server dead
|
18
18
|
:socket_max_failures => 2,
|
19
19
|
# amount of time to sleep between retries when a failure occurs
|
20
|
-
:socket_failure_delay => 0.01
|
20
|
+
:socket_failure_delay => 0.01,
|
21
|
+
# max size of value in bytes (default is 1 MB, can be overriden with "memcached -I <size>")
|
22
|
+
:value_max_bytes => 1024 * 1024,
|
23
|
+
:username => nil,
|
24
|
+
:password => nil,
|
21
25
|
}
|
22
26
|
|
23
27
|
def initialize(attribs, options = {})
|
@@ -41,6 +45,11 @@ module Dalli
|
|
41
45
|
raise
|
42
46
|
rescue Dalli::DalliError
|
43
47
|
raise
|
48
|
+
rescue TypeError => ex
|
49
|
+
Dalli.logger.error "Application bug: #{ex.class.name}: #{ex.message}"
|
50
|
+
Dalli.logger.error "You are trying to cache a Ruby object which cannot be serialized to memcached."
|
51
|
+
Dalli.logger.error ex.backtrace.join("\n\t")
|
52
|
+
false
|
44
53
|
rescue Exception => ex
|
45
54
|
Dalli.logger.error "Unexpected exception in Dalli: #{ex.class.name}: #{ex.message}"
|
46
55
|
Dalli.logger.error "This is a bug in Dalli, please enter an issue in Github if it does not already exist."
|
@@ -126,8 +135,6 @@ module Dalli
|
|
126
135
|
Thread.current[:dalli_multi]
|
127
136
|
end
|
128
137
|
|
129
|
-
ONE_MB = 1024 * 1024
|
130
|
-
|
131
138
|
def get(key)
|
132
139
|
req = [REQUEST, OPCODES[:get], key.bytesize, 0, 0, 0, key.bytesize, 0, 0, key].pack(FORMAT[:get])
|
133
140
|
write(req)
|
@@ -255,7 +262,7 @@ module Dalli
|
|
255
262
|
value = Zlib::Deflate.deflate(value)
|
256
263
|
compressed = true
|
257
264
|
end
|
258
|
-
raise Dalli::DalliError, "Value too large, memcached can only store
|
265
|
+
raise Dalli::DalliError, "Value too large, memcached can only store #{@options[:value_max_bytes]} of data per key" if value.bytesize > @options[:value_max_bytes]
|
259
266
|
flags = 0
|
260
267
|
flags |= FLAG_COMPRESSED if compressed
|
261
268
|
flags |= FLAG_MARSHALLED if marshalled
|
@@ -364,7 +371,7 @@ module Dalli
|
|
364
371
|
begin
|
365
372
|
@sock = KSocket.open(hostname, port, :timeout => options[:socket_timeout])
|
366
373
|
@version = version # trigger actual connect
|
367
|
-
sasl_authentication if
|
374
|
+
sasl_authentication if need_auth?
|
368
375
|
up!
|
369
376
|
rescue Dalli::DalliError # SASL auth failure
|
370
377
|
raise
|
@@ -450,26 +457,19 @@ module Dalli
|
|
450
457
|
# SASL authentication support for NorthScale
|
451
458
|
#######
|
452
459
|
|
453
|
-
def
|
454
|
-
ENV['MEMCACHE_USERNAME']
|
460
|
+
def need_auth?
|
461
|
+
@options[:username] || ENV['MEMCACHE_USERNAME']
|
455
462
|
end
|
456
463
|
|
457
|
-
def init_sasl
|
458
|
-
require 'dalli/sasl/base'
|
459
|
-
require 'dalli/sasl/plain'
|
460
|
-
end
|
461
|
-
|
462
464
|
def username
|
463
|
-
ENV['MEMCACHE_USERNAME']
|
465
|
+
@options[:username] || ENV['MEMCACHE_USERNAME']
|
464
466
|
end
|
465
467
|
|
466
468
|
def password
|
467
|
-
ENV['MEMCACHE_PASSWORD']
|
469
|
+
@options[:password] || ENV['MEMCACHE_PASSWORD']
|
468
470
|
end
|
469
471
|
|
470
472
|
def sasl_authentication
|
471
|
-
init_sasl if !defined?(::SASL)
|
472
|
-
|
473
473
|
Dalli.logger.info { "Dalli/SASL authenticating as #{username}" }
|
474
474
|
|
475
475
|
# negotiate
|
@@ -482,12 +482,11 @@ module Dalli
|
|
482
482
|
content = read(count)
|
483
483
|
return (Dalli.logger.debug("Authentication not required/supported by server")) if status == 0x81
|
484
484
|
mechanisms = content.split(' ')
|
485
|
+
raise NotImplementedError, "Dalli only supports the PLAIN authentication mechanism" if !mechanisms.include?('PLAIN')
|
485
486
|
|
486
487
|
# request
|
487
|
-
|
488
|
-
msg =
|
489
|
-
mechanism = sasl.name
|
490
|
-
#p [mechanism, msg]
|
488
|
+
mechanism = 'PLAIN'
|
489
|
+
msg = "\x0#{username}\x0#{password}"
|
491
490
|
req = [REQUEST, OPCODES[:auth_request], mechanism.bytesize, 0, 0, 0, mechanism.bytesize + msg.bytesize, 0, 0, mechanism, msg].pack(FORMAT[:auth_request])
|
492
491
|
write(req)
|
493
492
|
|
data/lib/dalli/version.rb
CHANGED
data/test/test_dalli.rb
CHANGED
@@ -329,6 +329,18 @@ class TestDalli < Test::Unit::TestCase
|
|
329
329
|
end
|
330
330
|
end
|
331
331
|
|
332
|
+
should "handle application marshalling issues" do
|
333
|
+
memcached do |dc|
|
334
|
+
old = Dalli.logger
|
335
|
+
Dalli.logger = Logger.new(nil)
|
336
|
+
begin
|
337
|
+
assert_equal false, dc.set('a', Proc.new { true })
|
338
|
+
ensure
|
339
|
+
Dalli.logger = old
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
332
344
|
context 'with compression' do
|
333
345
|
should 'allow large values' do
|
334
346
|
memcached do |dc|
|
data/test/test_sasl.rb
CHANGED
@@ -6,7 +6,7 @@ class TestSasl < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
context 'without authentication credentials' do
|
8
8
|
setup do
|
9
|
-
ENV['MEMCACHE_USERNAME'] = '
|
9
|
+
ENV['MEMCACHE_USERNAME'] = 'foo'
|
10
10
|
ENV['MEMCACHE_PASSWORD'] = 'wrongpwd'
|
11
11
|
end
|
12
12
|
|
@@ -24,6 +24,15 @@ class TestSasl < Test::Unit::TestCase
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
should 'fail SASL authentication with wrong options' do
|
28
|
+
memcached(19124, '-S') do |dc|
|
29
|
+
dc = Dalli::Client.new('localhost:19124', :username => 'foo', :password => 'wrongpwd')
|
30
|
+
assert_raise Dalli::DalliError, /32/ do
|
31
|
+
dc.set('abc', 123)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
27
36
|
# OSX: Create a SASL user for the memcached application like so:
|
28
37
|
#
|
29
38
|
# saslpasswd2 -a memcached -c testuser
|
@@ -40,16 +49,31 @@ class TestSasl < Test::Unit::TestCase
|
|
40
49
|
ENV['MEMCACHE_PASSWORD'] = nil
|
41
50
|
end
|
42
51
|
|
43
|
-
should '
|
52
|
+
should 'pass SASL authentication' do
|
44
53
|
memcached(19124, '-S') do |dc|
|
45
54
|
# I get "Dalli::DalliError: Error authenticating: 32" in OSX
|
46
55
|
# but SASL works on Heroku servers. YMMV.
|
47
56
|
assert_equal true, dc.set('abc', 123)
|
48
57
|
assert_equal 123, dc.get('abc')
|
49
|
-
|
58
|
+
results = dc.stats
|
59
|
+
assert_equal 1, results.size
|
60
|
+
assert_equal 38, results.values.first.size
|
50
61
|
end
|
51
62
|
end
|
52
63
|
end
|
53
64
|
|
65
|
+
should 'pass SASL authentication with options' do
|
66
|
+
memcached(19124, '-S') do |dc|
|
67
|
+
dc = Dalli::Client.new('localhost:19124', :username => 'testuser', :password => 'testtest')
|
68
|
+
# I get "Dalli::DalliError: Error authenticating: 32" in OSX
|
69
|
+
# but SASL works on Heroku servers. YMMV.
|
70
|
+
assert_equal true, dc.set('abc', 123)
|
71
|
+
assert_equal 123, dc.get('abc')
|
72
|
+
results = dc.stats
|
73
|
+
assert_equal 1, results.size
|
74
|
+
assert_equal 38, results.values.first.size
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
54
78
|
end
|
55
79
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 1.0.
|
8
|
+
- 1
|
9
|
+
version: 1.0.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Mike Perham
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-01-05 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -89,9 +89,6 @@ files:
|
|
89
89
|
- lib/dalli/client.rb
|
90
90
|
- lib/dalli/options.rb
|
91
91
|
- lib/dalli/ring.rb
|
92
|
-
- lib/dalli/sasl/anonymous.rb
|
93
|
-
- lib/dalli/sasl/base.rb
|
94
|
-
- lib/dalli/sasl/plain.rb
|
95
92
|
- lib/dalli/server.rb
|
96
93
|
- lib/dalli/socket.rb
|
97
94
|
- lib/dalli/version.rb
|
data/lib/dalli/sasl/anonymous.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
module SASL
|
2
|
-
##
|
3
|
-
# SASL ANONYMOUS where you only send a username that may not get
|
4
|
-
# evaluated by the server.
|
5
|
-
#
|
6
|
-
# RFC 4505:
|
7
|
-
# http://tools.ietf.org/html/rfc4505
|
8
|
-
class Anonymous < Mechanism
|
9
|
-
def start
|
10
|
-
@state = nil
|
11
|
-
['auth', preferences.username.to_s]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/lib/dalli/sasl/base.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
module SASL
|
2
|
-
|
3
|
-
MECHANISMS = {
|
4
|
-
}
|
5
|
-
|
6
|
-
class Preferences
|
7
|
-
def authzid
|
8
|
-
nil
|
9
|
-
end
|
10
|
-
|
11
|
-
def realm
|
12
|
-
raise NotImplementedError
|
13
|
-
end
|
14
|
-
|
15
|
-
def digest_uri
|
16
|
-
raise NotImplementedError
|
17
|
-
end
|
18
|
-
|
19
|
-
def username
|
20
|
-
ENV['MEMCACHE_USERNAME']
|
21
|
-
end
|
22
|
-
|
23
|
-
def has_password?
|
24
|
-
false
|
25
|
-
end
|
26
|
-
|
27
|
-
def allow_plaintext?
|
28
|
-
false
|
29
|
-
end
|
30
|
-
|
31
|
-
def password
|
32
|
-
ENV['MEMCACHE_PASSWORD']
|
33
|
-
end
|
34
|
-
|
35
|
-
def want_anonymous?
|
36
|
-
false
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def SASL.new(mechanisms)
|
41
|
-
mechanisms.each do |mech|
|
42
|
-
if MECHANISMS.has_key?(mech)
|
43
|
-
x = MECHANISMS[mech]
|
44
|
-
return x.new(mech, Preferences.new)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
raise NotImplementedError, "No supported mechanisms in #{mechanisms.join(',')}"
|
49
|
-
end
|
50
|
-
|
51
|
-
##
|
52
|
-
# Common functions for mechanisms
|
53
|
-
#
|
54
|
-
# Mechanisms implement handling of methods start and receive. They
|
55
|
-
# return: [message_name, content] or nil where message_name is
|
56
|
-
# either 'auth' or 'response' and content is either a string which
|
57
|
-
# may transmitted encoded as Base64 or nil.
|
58
|
-
class Mechanism
|
59
|
-
attr_reader :preferences
|
60
|
-
attr_reader :name
|
61
|
-
|
62
|
-
def initialize(name, preferences)
|
63
|
-
@name = name
|
64
|
-
@preferences = preferences
|
65
|
-
@state = nil
|
66
|
-
end
|
67
|
-
|
68
|
-
def success?
|
69
|
-
@state == :success
|
70
|
-
end
|
71
|
-
def failure?
|
72
|
-
@state == :failure
|
73
|
-
end
|
74
|
-
|
75
|
-
def start
|
76
|
-
raise NotImplementedError
|
77
|
-
end
|
78
|
-
|
79
|
-
def receive(message_name, content)
|
80
|
-
case message_name
|
81
|
-
when 'success'
|
82
|
-
@state = :success
|
83
|
-
when 'failure'
|
84
|
-
@state = :failure
|
85
|
-
end
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
data/lib/dalli/sasl/plain.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
module SASL
|
2
|
-
##
|
3
|
-
# RFC 4616:
|
4
|
-
# http://tools.ietf.org/html/rfc4616
|
5
|
-
class Plain < Mechanism
|
6
|
-
|
7
|
-
def start
|
8
|
-
@state = nil
|
9
|
-
message = [preferences.authzid.to_s,
|
10
|
-
preferences.username,
|
11
|
-
preferences.password].join("\000")
|
12
|
-
['auth', message]
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
MECHANISMS['PLAIN'] = SASL::Plain
|
17
|
-
|
18
|
-
end
|