dalli 1.1.5 → 2.0.0
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/Gemfile +0 -2
- data/History.md +23 -5
- data/Performance.md +26 -69
- data/README.md +13 -22
- data/dalli.gemspec +1 -4
- data/lib/active_support/cache/dalli_store.rb +121 -104
- data/lib/dalli.rb +0 -6
- data/lib/dalli/client.rb +23 -28
- data/lib/dalli/server.rb +9 -14
- data/lib/dalli/socket.rb +19 -113
- data/lib/dalli/version.rb +1 -1
- data/test/helper.rb +0 -1
- data/test/memcached_mock.rb +2 -15
- data/test/test_active_support.rb +9 -52
- data/test/test_dalli.rb +67 -56
- metadata +10 -29
- data/Upgrade.md +0 -45
- data/lib/active_support/cache/dalli_store23.rb +0 -172
- data/lib/dalli/compatibility.rb +0 -52
- data/lib/dalli/memcache-client.rb +0 -1
- data/test/test_compatibility.rb +0 -33
- data/test/test_synchrony.rb +0 -175
data/test/test_dalli.rb
CHANGED
@@ -2,6 +2,33 @@ require 'helper'
|
|
2
2
|
require 'memcached_mock'
|
3
3
|
|
4
4
|
describe 'Dalli' do
|
5
|
+
describe 'options parsing' do
|
6
|
+
should 'handle deprecated options' do
|
7
|
+
dc = Dalli::Client.new('foo', :compression => true)
|
8
|
+
assert dc.instance_variable_get(:@options)[:compress]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'key validation' do
|
13
|
+
should 'not allow whitespace' do
|
14
|
+
dc = Dalli::Client.new
|
15
|
+
assert_raises ArgumentError do
|
16
|
+
dc.set ' ', 1
|
17
|
+
end
|
18
|
+
assert_raises ArgumentError do
|
19
|
+
dc.set "\t", 1
|
20
|
+
end
|
21
|
+
assert_raises ArgumentError do
|
22
|
+
dc.set "\n", 1
|
23
|
+
end
|
24
|
+
assert_raises ArgumentError do
|
25
|
+
dc.set "", 1
|
26
|
+
end
|
27
|
+
assert_raises ArgumentError do
|
28
|
+
dc.set nil, 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
5
32
|
|
6
33
|
should "default to localhost:11211" do
|
7
34
|
dc = Dalli::Client.new
|
@@ -26,60 +53,6 @@ describe 'Dalli' do
|
|
26
53
|
assert_equal s2, s3
|
27
54
|
end
|
28
55
|
|
29
|
-
context 'using unix sockets' do
|
30
|
-
should 'pass smoke test' do
|
31
|
-
memcached(nil,'',{:unix => true}) do |dc|
|
32
|
-
# get/set
|
33
|
-
dc.flush
|
34
|
-
assert_nil dc.get(:a)
|
35
|
-
assert dc.set(:a,1)
|
36
|
-
assert_equal 1, dc.get(:a)
|
37
|
-
|
38
|
-
# replace
|
39
|
-
dc.set(:a,1)
|
40
|
-
dc.replace(:a,2)
|
41
|
-
assert_equal 2, dc.get(:a)
|
42
|
-
|
43
|
-
# delete
|
44
|
-
dc.delete(:a)
|
45
|
-
assert_nil dc.get(:a)
|
46
|
-
|
47
|
-
# fetch
|
48
|
-
executed, expected = false, 1
|
49
|
-
|
50
|
-
value = dc.fetch(:fetched) do
|
51
|
-
executed = true
|
52
|
-
expected
|
53
|
-
end
|
54
|
-
|
55
|
-
assert executed
|
56
|
-
assert_equal expected, value
|
57
|
-
|
58
|
-
executed = false
|
59
|
-
value = dc.fetch(:fetched) do
|
60
|
-
executed = true
|
61
|
-
expected
|
62
|
-
end
|
63
|
-
|
64
|
-
assert !executed
|
65
|
-
assert_equal expected, value
|
66
|
-
|
67
|
-
# cas
|
68
|
-
dc.set(:a,1)
|
69
|
-
3.times { dc.cas(:a){|a| a+=1} }
|
70
|
-
assert_equal 4, dc.get(:a)
|
71
|
-
|
72
|
-
# get_multi
|
73
|
-
resp = dc.get_multi(%w(b c d))
|
74
|
-
assert_equal({}, resp)
|
75
|
-
dc.set("b",1)
|
76
|
-
dc.set("c",11)
|
77
|
-
resp = dc.get_multi(%w(b c d))
|
78
|
-
assert_equal({"b" => 1, "c" => 11}, resp)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
56
|
context 'using a live server' do
|
84
57
|
|
85
58
|
should "support get/set" do
|
@@ -103,6 +76,30 @@ describe 'Dalli' do
|
|
103
76
|
end
|
104
77
|
end
|
105
78
|
|
79
|
+
should "support stats" do
|
80
|
+
memcached do |dc|
|
81
|
+
# make sure that get_hits would not equal 0
|
82
|
+
dc.get(:a)
|
83
|
+
|
84
|
+
stats = dc.stats
|
85
|
+
servers = stats.keys
|
86
|
+
assert(servers.any? do |s|
|
87
|
+
stats[s]["get_hits"].to_i != 0
|
88
|
+
end)
|
89
|
+
|
90
|
+
# reset_stats test
|
91
|
+
results = dc.reset_stats
|
92
|
+
assert(results.all? { |x| x })
|
93
|
+
stats = dc.stats
|
94
|
+
servers = stats.keys
|
95
|
+
|
96
|
+
# check if reset was performed
|
97
|
+
servers.each do |s|
|
98
|
+
assert_equal 0, dc.stats[s]["get_hits"].to_i
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
106
103
|
should "support the fetch operation" do
|
107
104
|
memcached do |dc|
|
108
105
|
dc.flush
|
@@ -270,6 +267,20 @@ describe 'Dalli' do
|
|
270
267
|
end
|
271
268
|
end
|
272
269
|
|
270
|
+
should 'allow TCP connections to be configured for keepalive' do
|
271
|
+
memcached(19122, '', :keepalive => true) do |dc|
|
272
|
+
dc.set(:a, 1)
|
273
|
+
ring = dc.send(:ring)
|
274
|
+
server = ring.servers.first
|
275
|
+
socket = server.instance_variable_get('@sock')
|
276
|
+
|
277
|
+
optval = socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE)
|
278
|
+
optval = optval.unpack 'i'
|
279
|
+
|
280
|
+
assert_equal true, (optval[0] != 0)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
273
284
|
should "pass a simple smoke test" do
|
274
285
|
memcached do |dc|
|
275
286
|
resp = dc.flush
|
@@ -396,7 +407,7 @@ describe 'Dalli' do
|
|
396
407
|
context 'with compression' do
|
397
408
|
should 'allow large values' do
|
398
409
|
memcached do |dc|
|
399
|
-
dalli = Dalli::Client.new(dc.instance_variable_get(:@servers), :
|
410
|
+
dalli = Dalli::Client.new(dc.instance_variable_get(:@servers), :compress => true)
|
400
411
|
|
401
412
|
value = "0"*1024*1024
|
402
413
|
assert_raises Dalli::DalliError, /too large/ do
|
@@ -428,7 +439,7 @@ describe 'Dalli' do
|
|
428
439
|
|
429
440
|
should 'fit more values with compression' do
|
430
441
|
memcached(19126, '-m 1 -M') do |dc|
|
431
|
-
dalli = Dalli::Client.new('localhost:19126', :
|
442
|
+
dalli = Dalli::Client.new('localhost:19126', :compress => true)
|
432
443
|
failed = false
|
433
444
|
value = "1234567890"*1000
|
434
445
|
10_000.times do |idx|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dalli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mini_shoulda
|
16
|
-
requirement: &
|
16
|
+
requirement: &70227367207220 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70227367207220
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: mocha
|
27
|
-
requirement: &
|
27
|
+
requirement: &70227367204000 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,29 +32,18 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70227367204000
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rails
|
38
|
-
requirement: &
|
38
|
+
requirement: &70227367199700 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: '3.0'
|
44
|
-
type: :development
|
45
|
-
prerelease: false
|
46
|
-
version_requirements: *70232123465920
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: memcache-client
|
49
|
-
requirement: &70232123465100 !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
|
-
requirements:
|
52
|
-
- - ! '>='
|
41
|
+
- - ~>
|
53
42
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
43
|
+
version: '3'
|
55
44
|
type: :development
|
56
45
|
prerelease: false
|
57
|
-
version_requirements: *
|
46
|
+
version_requirements: *70227367199700
|
58
47
|
description: High performance memcached client for Ruby
|
59
48
|
email: mperham@gmail.com
|
60
49
|
executables: []
|
@@ -63,10 +52,7 @@ extra_rdoc_files: []
|
|
63
52
|
files:
|
64
53
|
- lib/action_dispatch/middleware/session/dalli_store.rb
|
65
54
|
- lib/active_support/cache/dalli_store.rb
|
66
|
-
- lib/active_support/cache/dalli_store23.rb
|
67
55
|
- lib/dalli/client.rb
|
68
|
-
- lib/dalli/compatibility.rb
|
69
|
-
- lib/dalli/memcache-client.rb
|
70
56
|
- lib/dalli/options.rb
|
71
57
|
- lib/dalli/ring.rb
|
72
58
|
- lib/dalli/server.rb
|
@@ -81,13 +67,11 @@ files:
|
|
81
67
|
- Gemfile
|
82
68
|
- dalli.gemspec
|
83
69
|
- Performance.md
|
84
|
-
- Upgrade.md
|
85
70
|
- test/abstract_unit.rb
|
86
71
|
- test/benchmark_test.rb
|
87
72
|
- test/helper.rb
|
88
73
|
- test/memcached_mock.rb
|
89
74
|
- test/test_active_support.rb
|
90
|
-
- test/test_compatibility.rb
|
91
75
|
- test/test_dalli.rb
|
92
76
|
- test/test_encoding.rb
|
93
77
|
- test/test_failover.rb
|
@@ -95,7 +79,6 @@ files:
|
|
95
79
|
- test/test_ring.rb
|
96
80
|
- test/test_sasl.rb
|
97
81
|
- test/test_session_store.rb
|
98
|
-
- test/test_synchrony.rb
|
99
82
|
homepage: http://github.com/mperham/dalli
|
100
83
|
licenses: []
|
101
84
|
post_install_message:
|
@@ -127,7 +110,6 @@ test_files:
|
|
127
110
|
- test/helper.rb
|
128
111
|
- test/memcached_mock.rb
|
129
112
|
- test/test_active_support.rb
|
130
|
-
- test/test_compatibility.rb
|
131
113
|
- test/test_dalli.rb
|
132
114
|
- test/test_encoding.rb
|
133
115
|
- test/test_failover.rb
|
@@ -135,4 +117,3 @@ test_files:
|
|
135
117
|
- test/test_ring.rb
|
136
118
|
- test/test_sasl.rb
|
137
119
|
- test/test_session_store.rb
|
138
|
-
- test/test_synchrony.rb
|
data/Upgrade.md
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
Upgrading from memcache-client
|
2
|
-
========
|
3
|
-
|
4
|
-
Dalli is not meant to be 100% compatible with memcache-client, there are a few minor differences in the API.
|
5
|
-
|
6
|
-
|
7
|
-
Compatibility Layer
|
8
|
-
----------------------
|
9
|
-
|
10
|
-
Enable memcache-client compatibility in your application when upgrading by requiring this when
|
11
|
-
initalizing your app:
|
12
|
-
|
13
|
-
require 'dalli/memcache-client'
|
14
|
-
|
15
|
-
This will print out warnings if your code is using the old memcache-client API style, explained below.
|
16
|
-
|
17
|
-
|
18
|
-
Marshalling
|
19
|
-
---------------
|
20
|
-
|
21
|
-
Dalli has changed the raw parameter to a :raw option. The memcache-client API allowed you to control marshalling on a per-method basis using a boolean 'raw' parameter to several of the API methods:
|
22
|
-
|
23
|
-
cache = MemCache.new
|
24
|
-
cache.set('abc', 123, 0, true)
|
25
|
-
cache.get('abc', true) => '123'
|
26
|
-
|
27
|
-
cache.set('abc', 123, 0)
|
28
|
-
cache.get('abc') => 123
|
29
|
-
|
30
|
-
Note that the last parameter is set to true in the first two API calls and so `get` returns a string, not an integer. In the second example, we don't provide the raw parameter. Since it defaults to false, it works exactly like Dalli.
|
31
|
-
|
32
|
-
If the code specifies raw as false, you can simply remove that parameter. If the code is using raw = true, you will need to use the :raw option:
|
33
|
-
|
34
|
-
cache.set('abc', 123, 0, :raw => true)
|
35
|
-
|
36
|
-
|
37
|
-
Return Values
|
38
|
-
----------------
|
39
|
-
|
40
|
-
In memcache-client, `set(key, value)` normally returns "STORED\r\n". This is an artifact of the text protocol used in earlier versions of memcached. Code that checks the return value will need to be updated. Dalli raises errors for exceptional cases but otherwise returns true or false depending on whether the operation succeeded or not. These methods are affected:
|
41
|
-
|
42
|
-
set
|
43
|
-
add
|
44
|
-
replace
|
45
|
-
delete
|
@@ -1,172 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'dalli'
|
3
|
-
rescue LoadError => e
|
4
|
-
$stderr.puts "You don't have dalli installed in your application: #{e.message}"
|
5
|
-
raise e
|
6
|
-
end
|
7
|
-
require 'digest/md5'
|
8
|
-
|
9
|
-
module ActiveSupport
|
10
|
-
module Cache
|
11
|
-
# A cache store implementation which stores data in Memcached:
|
12
|
-
# http://www.danga.com/memcached/
|
13
|
-
#
|
14
|
-
# DalliStore implements the Strategy::LocalCache strategy which implements
|
15
|
-
# an in memory cache inside of a block.
|
16
|
-
class DalliStore < Store
|
17
|
-
|
18
|
-
def self.build_mem_cache(*addresses)
|
19
|
-
addresses = addresses.flatten
|
20
|
-
options = addresses.extract_options!
|
21
|
-
addresses = ["localhost"] if addresses.empty?
|
22
|
-
Dalli::Client.new(addresses, options)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Creates a new DalliStore object, with the given memcached server
|
26
|
-
# addresses. Each address is either a host name, or a host-with-port string
|
27
|
-
# in the form of "host_name:port". For example:
|
28
|
-
#
|
29
|
-
# ActiveSupport::Cache::DalliStore.new("localhost", "server-downstairs.localnetwork:8229")
|
30
|
-
#
|
31
|
-
# If no addresses are specified, then DalliStore will connect to
|
32
|
-
# localhost port 11211 (the default memcached port).
|
33
|
-
#
|
34
|
-
def initialize(*addresses)
|
35
|
-
addresses = addresses.flatten
|
36
|
-
options = addresses.extract_options!
|
37
|
-
|
38
|
-
mem_cache_options = options.dup
|
39
|
-
@namespace = mem_cache_options.delete(:namespace)
|
40
|
-
@expires_in = mem_cache_options[:expires_in]
|
41
|
-
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
42
|
-
|
43
|
-
extend Strategy::LocalCache
|
44
|
-
end
|
45
|
-
|
46
|
-
# Reads multiple keys from the cache using a single call to the
|
47
|
-
# servers for all keys. Options can be passed in the last argument.
|
48
|
-
def read_multi(*names)
|
49
|
-
options = nil
|
50
|
-
options = names.pop if names.last.is_a?(Hash)
|
51
|
-
keys_to_names = names.inject({}){|map, name| map[escape_key(name)] = name; map}
|
52
|
-
cache_keys = {}
|
53
|
-
# map keys to servers
|
54
|
-
names.each do |key|
|
55
|
-
cache_key = escape_key key
|
56
|
-
cache_keys[cache_key] = key
|
57
|
-
end
|
58
|
-
|
59
|
-
values = @data.get_multi(keys_to_names.keys, options)
|
60
|
-
results = {}
|
61
|
-
values.each do |key, value|
|
62
|
-
results[cache_keys[key]] = value
|
63
|
-
end
|
64
|
-
results
|
65
|
-
end
|
66
|
-
|
67
|
-
def reset
|
68
|
-
@data.reset
|
69
|
-
end
|
70
|
-
|
71
|
-
# Read an entry from the cache.
|
72
|
-
def read(key, options = nil) # :nodoc:
|
73
|
-
super
|
74
|
-
@data.get(escape_key(key), options)
|
75
|
-
rescue Dalli::DalliError => e
|
76
|
-
logger.error("DalliError: #{e.message}")
|
77
|
-
nil
|
78
|
-
end
|
79
|
-
|
80
|
-
# Writes a value to the cache.
|
81
|
-
#
|
82
|
-
# Possible options:
|
83
|
-
# - +:unless_exist+ - set to true if you don't want to update the cache
|
84
|
-
# if the key is already set.
|
85
|
-
# - +:expires_in+ - the number of seconds that this value may stay in
|
86
|
-
# the cache. See ActiveSupport::Cache::Store#write for an example.
|
87
|
-
def write(key, value, options = nil)
|
88
|
-
super
|
89
|
-
value = value.to_s if options && options[:raw]
|
90
|
-
method = options && options[:unless_exist] ? :add : :set
|
91
|
-
@data.send(method, escape_key(key), value, expires_in(options), options)
|
92
|
-
rescue Dalli::DalliError => e
|
93
|
-
logger.error("DalliError: #{e.message}")
|
94
|
-
false
|
95
|
-
end
|
96
|
-
|
97
|
-
def delete(key, options = nil) # :nodoc:
|
98
|
-
super
|
99
|
-
@data.delete(escape_key(key))
|
100
|
-
rescue Dalli::DalliError => e
|
101
|
-
logger.error("DalliError: #{e.message}")
|
102
|
-
false
|
103
|
-
end
|
104
|
-
|
105
|
-
def exist?(key, options = nil) # :nodoc:
|
106
|
-
# Doesn't call super, cause exist? in memcache is in fact a read
|
107
|
-
# But who cares? Reading is very fast anyway
|
108
|
-
# Local cache is checked first, if it doesn't know then memcache itself is read from
|
109
|
-
!read(key, options).nil?
|
110
|
-
end
|
111
|
-
|
112
|
-
# Increment a cached value. This method uses the memcached incr atomic
|
113
|
-
# operator and can only be used on values written with the :raw option.
|
114
|
-
# Calling it on a value not stored with :raw will initialize that value
|
115
|
-
# to zero.
|
116
|
-
def increment(key, amount = 1) # :nodoc:
|
117
|
-
log("incrementing", key, amount)
|
118
|
-
@data.incr(escape_key(key), amount)
|
119
|
-
rescue Dalli::DalliError => e
|
120
|
-
logger.error("DalliError: #{e.message}") if logger
|
121
|
-
nil
|
122
|
-
end
|
123
|
-
|
124
|
-
# Decrement a cached value. This method uses the memcached decr atomic
|
125
|
-
# operator and can only be used on values written with the :raw option.
|
126
|
-
# Calling it on a value not stored with :raw will initialize that value
|
127
|
-
# to zero.
|
128
|
-
def decrement(key, amount = 1) # :nodoc:
|
129
|
-
log("decrement", key, amount)
|
130
|
-
@data.decr(escape_key(key), amount)
|
131
|
-
rescue Dalli::DalliError => e
|
132
|
-
logger.error("DalliError: #{e.message}") if logger
|
133
|
-
nil
|
134
|
-
end
|
135
|
-
|
136
|
-
def delete_matched(matcher, options = nil) # :nodoc:
|
137
|
-
# don't do any local caching at present, just pass
|
138
|
-
# through and let the error happen
|
139
|
-
super
|
140
|
-
raise "Not supported by Memcache"
|
141
|
-
end
|
142
|
-
|
143
|
-
# Clear the entire cache on all memcached servers. This method should
|
144
|
-
# be used with care when using a shared cache.
|
145
|
-
def clear
|
146
|
-
@data.flush_all
|
147
|
-
end
|
148
|
-
|
149
|
-
# Get the statistics from the memcached servers.
|
150
|
-
def stats
|
151
|
-
@data.stats
|
152
|
-
end
|
153
|
-
|
154
|
-
private
|
155
|
-
|
156
|
-
# Exists in 2.3.8 but not in 2.3.2 so roll our own version
|
157
|
-
def expires_in(options)
|
158
|
-
expires_in = (options && options[:expires_in]) || @expires_in
|
159
|
-
|
160
|
-
raise ":expires_in must be a number" if expires_in && !expires_in.is_a?(Numeric)
|
161
|
-
|
162
|
-
expires_in || 0
|
163
|
-
end
|
164
|
-
|
165
|
-
def escape_key(key)
|
166
|
-
prefix = @namespace.is_a?(Proc) ? @namespace.call : @namespace
|
167
|
-
key = "#{prefix}:#{key}" if prefix
|
168
|
-
key
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|