memcached_store 0.10.0 → 0.11.0
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +5 -2
- data/Gemfile +11 -0
- data/README.md +3 -3
- data/lib/active_support/cache/memcached_snappy_store.rb +5 -2
- data/lib/active_support/cache/memcached_store.rb +145 -0
- data/lib/memcached_store.rb +1 -0
- data/lib/memcached_store/version.rb +1 -1
- data/memcached_store.gemspec +2 -3
- data/test/test_helper.rb +3 -4
- data/test/test_memcached_store.rb +291 -0
- metadata +11 -37
- data/Gemfile.lock +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b05b5adfbadd1297a6914f2227a649e1bcd0d178
|
4
|
+
data.tar.gz: 9d8aa9dcf3f9435b00f5e5dd07697beda9930ab1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51829aa977156ed9c8c06bdab489b1f4febfc3c4aedd2d96555996b3a750bd0e64d7d2a708ebadbf51a9baf443f8e97c74622251eac7093dd9d0a9e85b64e5c9
|
7
|
+
data.tar.gz: c35fac05d247a305443a4732f2daf375f66066e3befc3266f5a6d78348ee20328f1cf2ce3cfb2a386c5d59de4e990633780aa5dcaa93055a71f37270f091a2ad
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -2,3 +2,14 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in rails_cache_adapters.gemspec
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
version = ENV["AS_VERSION"] || "3.2.16"
|
7
|
+
as_version = case version
|
8
|
+
when "master"
|
9
|
+
{:github => "rails/rails"}
|
10
|
+
else
|
11
|
+
"~> #{version}"
|
12
|
+
end
|
13
|
+
|
14
|
+
gem 'minitest', '~> 4.0' if version == "3.2.16"
|
15
|
+
gem "activesupport", as_version
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ ActiveSupport cache store that adds snappy compression at the cost of making the
|
|
6
6
|
|
7
7
|
Add this line to your application's Gemfile:
|
8
8
|
|
9
|
-
gem '
|
9
|
+
gem 'memcached_store'
|
10
10
|
|
11
11
|
And then execute:
|
12
12
|
|
@@ -14,7 +14,7 @@ And then execute:
|
|
14
14
|
|
15
15
|
Or install it yourself as:
|
16
16
|
|
17
|
-
$ gem install
|
17
|
+
$ gem install memcached_store
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
@@ -29,7 +29,7 @@ In your environment file:
|
|
29
29
|
|
30
30
|
## Code status
|
31
31
|
|
32
|
-
[](https://travis-ci.org/Shopify/memcached_store)
|
33
33
|
|
34
34
|
## Contributing
|
35
35
|
|
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'active_support/cache/memcached_store'
|
2
|
+
require 'snappy'
|
3
|
+
|
1
4
|
module ActiveSupport
|
2
5
|
module Cache
|
3
|
-
class MemcachedSnappyStore <
|
6
|
+
class MemcachedSnappyStore < MemcachedStore
|
4
7
|
class UnsupportedOperation < StandardError; end
|
5
8
|
|
6
9
|
def increment(*args)
|
@@ -26,7 +29,7 @@ module ActiveSupport
|
|
26
29
|
|
27
30
|
serialized_compressed_value = Snappy.deflate(serialized_value)
|
28
31
|
|
29
|
-
|
32
|
+
@data.set(escape_key(key), serialized_compressed_value, expires_in, true)
|
30
33
|
end
|
31
34
|
|
32
35
|
def deserialize_entry(compressed_value)
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# file havily based out off https://github.com/rails/rails/blob/3-2-stable/activesupport/lib/active_support/cache/mem_cache_store.rb
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
module ActiveSupport
|
5
|
+
module Cache
|
6
|
+
# A cache store implementation which stores data in Memcached:
|
7
|
+
# http://memcached.org/
|
8
|
+
#
|
9
|
+
# MemcachedStore uses memcached gem as backend to connect to Memcached server.
|
10
|
+
#
|
11
|
+
# MemcachedStore implements the Strategy::LocalCache strategy which implements
|
12
|
+
# an in-memory cache inside of a block.
|
13
|
+
class MemcachedStore < Store
|
14
|
+
FATAL_EXCEPTIONS = [ Memcached::ABadKeyWasProvidedOrCharactersOutOfRange,
|
15
|
+
Memcached::AKeyLengthOfZeroWasProvided,
|
16
|
+
Memcached::ConnectionBindFailure,
|
17
|
+
Memcached::ConnectionDataDoesNotExist,
|
18
|
+
Memcached::ConnectionFailure,
|
19
|
+
Memcached::ConnectionSocketCreateFailure,
|
20
|
+
Memcached::CouldNotOpenUnixSocket,
|
21
|
+
Memcached::NoServersDefined,
|
22
|
+
Memcached::TheHostTransportProtocolDoesNotMatchThatOfTheClient
|
23
|
+
]
|
24
|
+
|
25
|
+
if defined?(::Rails) && ::Rails.env.test?
|
26
|
+
NONFATAL_EXCEPTIONS = []
|
27
|
+
else
|
28
|
+
NONFATAL_EXCEPTIONS = Memcached::EXCEPTIONS - FATAL_EXCEPTIONS
|
29
|
+
end
|
30
|
+
|
31
|
+
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
32
|
+
|
33
|
+
def initialize(*addresses)
|
34
|
+
addresses = addresses.flatten
|
35
|
+
options = addresses.extract_options!
|
36
|
+
super(options)
|
37
|
+
|
38
|
+
if addresses.first.respond_to?(:get)
|
39
|
+
@data = addresses.first
|
40
|
+
else
|
41
|
+
mem_cache_options = options.dup
|
42
|
+
UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
|
43
|
+
@data = Memcached::Rails.new(*(addresses + [mem_cache_options]))
|
44
|
+
end
|
45
|
+
|
46
|
+
extend Strategy::LocalCache
|
47
|
+
end
|
48
|
+
|
49
|
+
def read_multi(*names)
|
50
|
+
options = names.extract_options!
|
51
|
+
options = merged_options(options)
|
52
|
+
keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
|
53
|
+
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
|
54
|
+
values = {}
|
55
|
+
raw_values.each do |key, value|
|
56
|
+
entry = deserialize_entry(value)
|
57
|
+
values[keys_to_names[key]] = entry.value unless entry.expired?
|
58
|
+
end
|
59
|
+
values
|
60
|
+
end
|
61
|
+
|
62
|
+
def increment(name, amount = 1, options = nil) # :nodoc:
|
63
|
+
options = merged_options(options)
|
64
|
+
instrument(:increment, name, :amount => amount) do
|
65
|
+
@data.incr(escape_key(namespaced_key(name, options)), amount)
|
66
|
+
end
|
67
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
68
|
+
@data.log_exception(e)
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def decrement(name, amount = 1, options = nil) # :nodoc:
|
73
|
+
options = merged_options(options)
|
74
|
+
instrument(:decrement, name, :amount => amount) do
|
75
|
+
@data.decr(escape_key(namespaced_key(name, options)), amount)
|
76
|
+
end
|
77
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
78
|
+
@data.log_exception(e)
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def clear(options = nil)
|
83
|
+
@data.flush_all
|
84
|
+
end
|
85
|
+
|
86
|
+
def stats
|
87
|
+
@data.stats
|
88
|
+
end
|
89
|
+
|
90
|
+
def exist?(*args)
|
91
|
+
!!super
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
def read_entry(key, options) # :nodoc:
|
96
|
+
deserialize_entry(@data.get(escape_key(key), true))
|
97
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
98
|
+
@data.log_exception(e)
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_entry(key, entry, options) # :nodoc:
|
103
|
+
method = options && options[:unless_exist] ? :add : :set
|
104
|
+
value = options[:raw] ? entry.value.to_s : entry
|
105
|
+
expires_in = options[:expires_in].to_i
|
106
|
+
if expires_in > 0 && !options[:raw]
|
107
|
+
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
108
|
+
expires_in += 5.minutes
|
109
|
+
end
|
110
|
+
@data.send(method, escape_key(key), value, expires_in, options[:raw])
|
111
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
112
|
+
@data.log_exception(e)
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
def delete_entry(key, options) # :nodoc:
|
117
|
+
@data.delete(escape_key(key))
|
118
|
+
true
|
119
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
120
|
+
@data.log_exception(e)
|
121
|
+
false
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def escape_key(key)
|
127
|
+
key = key.to_s.dup
|
128
|
+
key = key.force_encoding(Encoding::ASCII_8BIT)
|
129
|
+
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
130
|
+
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
131
|
+
key
|
132
|
+
end
|
133
|
+
|
134
|
+
def deserialize_entry(raw_value)
|
135
|
+
if raw_value
|
136
|
+
entry = Marshal.load(raw_value) rescue raw_value
|
137
|
+
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
138
|
+
else
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/memcached_store.rb
CHANGED
data/memcached_store.gemspec
CHANGED
@@ -17,11 +17,10 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.version = MemcachedStore::VERSION
|
18
18
|
gem.add_runtime_dependency "activesupport", ">= 3.2"
|
19
19
|
gem.add_runtime_dependency "snappy", "0.0.4"
|
20
|
-
gem.
|
20
|
+
gem.add_runtime_dependency "memcached", "~> 1.5.0"
|
21
|
+
|
21
22
|
gem.add_development_dependency "rake"
|
22
23
|
gem.add_development_dependency "minitest"
|
23
24
|
gem.add_development_dependency "mocha"
|
24
25
|
gem.add_development_dependency "timecop"
|
25
|
-
gem.add_development_dependency "memcached"
|
26
|
-
gem.add_development_dependency "memcache-client"
|
27
26
|
end
|
data/test/test_helper.rb
CHANGED
@@ -0,0 +1,291 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestMemcachedStore < ActiveSupport::TestCase
|
4
|
+
setup do
|
5
|
+
@cache = ActiveSupport::Cache.lookup_store(:memcached_store, expires_in: 60)
|
6
|
+
@cache.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_read_and_write_strings
|
10
|
+
assert @cache.write('foo', 'bar')
|
11
|
+
assert_equal 'bar', @cache.read('foo')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_overwrite
|
15
|
+
@cache.write('foo', 'bar')
|
16
|
+
@cache.write('foo', 'baz')
|
17
|
+
assert_equal 'baz', @cache.read('foo')
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_fetch_without_cache_miss
|
21
|
+
@cache.write('foo', 'bar')
|
22
|
+
@cache.expects(:write).never
|
23
|
+
assert_equal 'bar', @cache.fetch('foo') { 'baz' }
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_fetch_with_cache_miss
|
27
|
+
@cache.expects(:write).with('foo', 'baz', @cache.options)
|
28
|
+
assert_equal 'baz', @cache.fetch('foo') { 'baz' }
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_fetch_with_forced_cache_miss
|
32
|
+
@cache.write('foo', 'bar')
|
33
|
+
@cache.expects(:read).never
|
34
|
+
@cache.expects(:write).with('foo', 'bar', @cache.options.merge(:force => true))
|
35
|
+
@cache.fetch('foo', :force => true) { 'bar' }
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_fetch_with_cached_nil
|
39
|
+
@cache.write('foo', nil)
|
40
|
+
@cache.expects(:write).never
|
41
|
+
assert_nil @cache.fetch('foo') { 'baz' }
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_read_and_write_hash
|
45
|
+
assert @cache.write('foo', {:a => "b"})
|
46
|
+
assert_equal({:a => "b"}, @cache.read('foo'))
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_should_read_and_write_integer
|
50
|
+
assert @cache.write('foo', 1)
|
51
|
+
assert_equal 1, @cache.read('foo')
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_should_read_and_write_nil
|
55
|
+
assert @cache.write('foo', nil)
|
56
|
+
assert_equal nil, @cache.read('foo')
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_should_read_and_write_false
|
60
|
+
assert @cache.write('foo', false)
|
61
|
+
assert_equal false, @cache.read('foo')
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_read_multi
|
65
|
+
@cache.write('foo', 'bar')
|
66
|
+
@cache.write('fu', 'baz')
|
67
|
+
@cache.write('fud', 'biz')
|
68
|
+
assert_equal({"foo" => "bar", "fu" => "baz"}, @cache.read_multi('foo', 'fu'))
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_read_multi_with_expires
|
72
|
+
time = Time.now
|
73
|
+
@cache.write('foo', 'bar', :expires_in => 10)
|
74
|
+
@cache.write('fu', 'baz')
|
75
|
+
@cache.write('fud', 'biz')
|
76
|
+
Time.stubs(:now).returns(time + 11)
|
77
|
+
assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu'))
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_read_multi
|
81
|
+
@cache.write('foo', 'bar')
|
82
|
+
@cache.write('fu', 'baz')
|
83
|
+
@cache.write('fud', 'biz')
|
84
|
+
assert_equal({"foo" => "bar", "fu" => "baz"}, @cache.read_multi('foo', 'fu'))
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_read_multi_with_expires
|
88
|
+
@cache.write('foo', 'bar', :expires_in => 0.001)
|
89
|
+
@cache.write('fu', 'baz')
|
90
|
+
@cache.write('fud', 'biz')
|
91
|
+
sleep(0.002)
|
92
|
+
assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu'))
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_read_and_write_compressed_small_data
|
96
|
+
@cache.write('foo', 'bar', :compress => true)
|
97
|
+
assert_equal 'bar', @cache.read('foo')
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_read_and_write_compressed_large_data
|
101
|
+
@cache.write('foo', 'bar', :compress => true, :compress_threshold => 2)
|
102
|
+
assert_equal 'bar', @cache.read('foo')
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_read_and_write_compressed_nil
|
106
|
+
@cache.write('foo', nil, :compress => true)
|
107
|
+
assert_nil @cache.read('foo')
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_cache_key
|
111
|
+
obj = Object.new
|
112
|
+
def obj.cache_key
|
113
|
+
:foo
|
114
|
+
end
|
115
|
+
@cache.write(obj, "bar")
|
116
|
+
assert_equal "bar", @cache.read("foo")
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_param_as_cache_key
|
120
|
+
obj = Object.new
|
121
|
+
def obj.to_param
|
122
|
+
"foo"
|
123
|
+
end
|
124
|
+
@cache.write(obj, "bar")
|
125
|
+
assert_equal "bar", @cache.read("foo")
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_array_as_cache_key
|
129
|
+
@cache.write([:fu, "foo"], "bar")
|
130
|
+
assert_equal "bar", @cache.read("fu/foo")
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_hash_as_cache_key
|
134
|
+
@cache.write({:foo => 1, :fu => 2}, "bar")
|
135
|
+
assert_equal "bar", @cache.read("foo=1/fu=2")
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_keys_are_case_sensitive
|
139
|
+
@cache.write("foo", "bar")
|
140
|
+
assert_nil @cache.read("FOO")
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_exist
|
144
|
+
@cache.write('foo', 'bar')
|
145
|
+
assert_equal true, @cache.exist?('foo')
|
146
|
+
assert_equal false, @cache.exist?('bar')
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_nil_exist
|
150
|
+
@cache.write('foo', nil)
|
151
|
+
assert @cache.exist?('foo')
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_delete
|
155
|
+
@cache.write('foo', 'bar')
|
156
|
+
assert @cache.exist?('foo')
|
157
|
+
assert @cache.delete('foo')
|
158
|
+
assert !@cache.exist?('foo')
|
159
|
+
|
160
|
+
assert @cache.delete('foo')
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_original_store_objects_should_not_be_immutable
|
164
|
+
bar = 'bar'
|
165
|
+
@cache.write('foo', bar)
|
166
|
+
assert_nothing_raised { bar.gsub!(/.*/, 'baz') }
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_expires_in
|
170
|
+
time = Time.local(2008, 4, 24)
|
171
|
+
Time.stubs(:now).returns(time)
|
172
|
+
|
173
|
+
@cache.write('foo', 'bar')
|
174
|
+
assert_equal 'bar', @cache.read('foo')
|
175
|
+
|
176
|
+
Time.stubs(:now).returns(time + 30)
|
177
|
+
assert_equal 'bar', @cache.read('foo')
|
178
|
+
|
179
|
+
Time.stubs(:now).returns(time + 61)
|
180
|
+
assert_nil @cache.read('foo')
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_race_condition_protection
|
184
|
+
time = Time.now
|
185
|
+
@cache.write('foo', 'bar', :expires_in => 60)
|
186
|
+
Time.stubs(:now).returns(time + 61)
|
187
|
+
result = @cache.fetch('foo', :race_condition_ttl => 10) do
|
188
|
+
assert_equal 'bar', @cache.read('foo')
|
189
|
+
"baz"
|
190
|
+
end
|
191
|
+
assert_equal "baz", result
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_race_condition_protection_is_limited
|
195
|
+
time = Time.now
|
196
|
+
@cache.write('foo', 'bar', :expires_in => 60)
|
197
|
+
Time.stubs(:now).returns(time + 71)
|
198
|
+
result = @cache.fetch('foo', :race_condition_ttl => 10) do
|
199
|
+
assert_equal nil, @cache.read('foo')
|
200
|
+
"baz"
|
201
|
+
end
|
202
|
+
assert_equal "baz", result
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_race_condition_protection_is_safe
|
206
|
+
time = Time.now
|
207
|
+
@cache.write('foo', 'bar', :expires_in => 60)
|
208
|
+
Time.stubs(:now).returns(time + 61)
|
209
|
+
begin
|
210
|
+
@cache.fetch('foo', :race_condition_ttl => 10) do
|
211
|
+
assert_equal 'bar', @cache.read('foo')
|
212
|
+
raise ArgumentError.new
|
213
|
+
end
|
214
|
+
rescue ArgumentError
|
215
|
+
end
|
216
|
+
assert_equal "bar", @cache.read('foo')
|
217
|
+
Time.stubs(:now).returns(time + 91)
|
218
|
+
assert_nil @cache.read('foo')
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_crazy_key_characters
|
222
|
+
crazy_key = "#/:*(<+=> )&$%@?;'\"\'`~-"
|
223
|
+
assert @cache.write(crazy_key, "1", :raw => true)
|
224
|
+
assert_equal "1", @cache.read(crazy_key)
|
225
|
+
assert_equal "1", @cache.fetch(crazy_key)
|
226
|
+
assert @cache.delete(crazy_key)
|
227
|
+
assert_equal "2", @cache.fetch(crazy_key, :raw => true) { "2" }
|
228
|
+
assert_equal 3, @cache.increment(crazy_key)
|
229
|
+
assert_equal 2, @cache.decrement(crazy_key)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_really_long_keys
|
233
|
+
key = ""
|
234
|
+
900.times{key << "x"}
|
235
|
+
assert @cache.write(key, "bar")
|
236
|
+
assert_equal "bar", @cache.read(key)
|
237
|
+
assert_equal "bar", @cache.fetch(key)
|
238
|
+
assert_nil @cache.read("#{key}x")
|
239
|
+
assert_equal({key => "bar"}, @cache.read_multi(key))
|
240
|
+
assert @cache.delete(key)
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_increment
|
244
|
+
@cache.write('foo', 1, :raw => true)
|
245
|
+
assert_equal 1, @cache.read('foo').to_i
|
246
|
+
assert_equal 2, @cache.increment('foo')
|
247
|
+
assert_equal 2, @cache.read('foo').to_i
|
248
|
+
assert_equal 3, @cache.increment('foo')
|
249
|
+
assert_equal 3, @cache.read('foo').to_i
|
250
|
+
assert_nil @cache.increment('bar')
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_decrement
|
254
|
+
@cache.write('foo', 3, :raw => true)
|
255
|
+
assert_equal 3, @cache.read('foo').to_i
|
256
|
+
assert_equal 2, @cache.decrement('foo')
|
257
|
+
assert_equal 2, @cache.read('foo').to_i
|
258
|
+
assert_equal 1, @cache.decrement('foo')
|
259
|
+
assert_equal 1, @cache.read('foo').to_i
|
260
|
+
assert_nil @cache.decrement('bar')
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_common_utf8_values
|
264
|
+
key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8)
|
265
|
+
assert @cache.write(key, "1", :raw => true)
|
266
|
+
assert_equal "1", @cache.read(key)
|
267
|
+
assert_equal "1", @cache.fetch(key)
|
268
|
+
assert @cache.delete(key)
|
269
|
+
assert_equal "2", @cache.fetch(key, :raw => true) { "2" }
|
270
|
+
assert_equal 3, @cache.increment(key)
|
271
|
+
assert_equal 2, @cache.decrement(key)
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_retains_encoding
|
275
|
+
key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8)
|
276
|
+
assert @cache.write(key, "1", :raw => true)
|
277
|
+
assert_equal Encoding::UTF_8, key.encoding
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_initialize_accepts_a_list_of_servers_in_options
|
281
|
+
options = {servers: ["localhost:21211"]}
|
282
|
+
cache = ActiveSupport::Cache.lookup_store(:memcached_store, options)
|
283
|
+
assert_equal 21211, cache.instance_variable_get(:@data).servers.first.port
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_multiple_servers
|
287
|
+
options = {servers: ["localhost:21211", "localhost:11211"]}
|
288
|
+
cache = ActiveSupport::Cache.lookup_store(:memcached_store, options)
|
289
|
+
assert_equal [21211, 11211], cache.instance_variable_get(:@data).servers.map(&:port)
|
290
|
+
end
|
291
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: memcached_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Camilo Lopez
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-01-
|
13
|
+
date: 2014-01-10 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -41,19 +41,19 @@ dependencies:
|
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: 0.0.4
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
|
-
name:
|
44
|
+
name: memcached
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- - "
|
47
|
+
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
50
|
-
type: :
|
49
|
+
version: 1.5.0
|
50
|
+
type: :runtime
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
|
-
- - "
|
54
|
+
- - "~>"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
56
|
+
version: 1.5.0
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: rake
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,34 +110,6 @@ dependencies:
|
|
110
110
|
- - ">="
|
111
111
|
- !ruby/object:Gem::Version
|
112
112
|
version: '0'
|
113
|
-
- !ruby/object:Gem::Dependency
|
114
|
-
name: memcached
|
115
|
-
requirement: !ruby/object:Gem::Requirement
|
116
|
-
requirements:
|
117
|
-
- - ">="
|
118
|
-
- !ruby/object:Gem::Version
|
119
|
-
version: '0'
|
120
|
-
type: :development
|
121
|
-
prerelease: false
|
122
|
-
version_requirements: !ruby/object:Gem::Requirement
|
123
|
-
requirements:
|
124
|
-
- - ">="
|
125
|
-
- !ruby/object:Gem::Version
|
126
|
-
version: '0'
|
127
|
-
- !ruby/object:Gem::Dependency
|
128
|
-
name: memcache-client
|
129
|
-
requirement: !ruby/object:Gem::Requirement
|
130
|
-
requirements:
|
131
|
-
- - ">="
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: '0'
|
134
|
-
type: :development
|
135
|
-
prerelease: false
|
136
|
-
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
requirements:
|
138
|
-
- - ">="
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
version: '0'
|
141
113
|
description: Plugin-able Memcached adapters to add features (compression, safety)
|
142
114
|
email:
|
143
115
|
- camilo@camilolopez.com
|
@@ -150,11 +122,11 @@ files:
|
|
150
122
|
- ".gitignore"
|
151
123
|
- ".travis.yml"
|
152
124
|
- Gemfile
|
153
|
-
- Gemfile.lock
|
154
125
|
- LICENSE
|
155
126
|
- README.md
|
156
127
|
- Rakefile
|
157
128
|
- lib/active_support/cache/memcached_snappy_store.rb
|
129
|
+
- lib/active_support/cache/memcached_store.rb
|
158
130
|
- lib/memcached_store.rb
|
159
131
|
- lib/memcached_store/memcached_safety.rb
|
160
132
|
- lib/memcached_store/version.rb
|
@@ -162,6 +134,7 @@ files:
|
|
162
134
|
- test/test_helper.rb
|
163
135
|
- test/test_memcached_safety.rb
|
164
136
|
- test/test_memcached_snappy_store.rb
|
137
|
+
- test/test_memcached_store.rb
|
165
138
|
homepage: https://github.com/Shopify/memcached_store/
|
166
139
|
licenses: []
|
167
140
|
metadata: {}
|
@@ -189,3 +162,4 @@ test_files:
|
|
189
162
|
- test/test_helper.rb
|
190
163
|
- test/test_memcached_safety.rb
|
191
164
|
- test/test_memcached_snappy_store.rb
|
165
|
+
- test/test_memcached_store.rb
|
data/Gemfile.lock
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
memcached_store (0.10.0)
|
5
|
-
activesupport (>= 3.2)
|
6
|
-
snappy (= 0.0.4)
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: https://rubygems.org/
|
10
|
-
specs:
|
11
|
-
activesupport (3.2.13)
|
12
|
-
i18n (= 0.6.1)
|
13
|
-
multi_json (~> 1.0)
|
14
|
-
i18n (0.6.1)
|
15
|
-
memcache-client (1.8.5)
|
16
|
-
memcached (1.5.0)
|
17
|
-
metaclass (0.0.1)
|
18
|
-
minitest (4.7.1)
|
19
|
-
mocha (0.13.3)
|
20
|
-
metaclass (~> 0.0.1)
|
21
|
-
multi_json (1.8.3)
|
22
|
-
rake (10.0.4)
|
23
|
-
snappy (0.0.4)
|
24
|
-
timecop (0.6.1)
|
25
|
-
|
26
|
-
PLATFORMS
|
27
|
-
ruby
|
28
|
-
|
29
|
-
DEPENDENCIES
|
30
|
-
i18n
|
31
|
-
memcache-client
|
32
|
-
memcached
|
33
|
-
memcached_store!
|
34
|
-
minitest
|
35
|
-
mocha
|
36
|
-
rake
|
37
|
-
timecop
|