memcached_store 0.12.8 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +2 -2
- data/README.md +6 -2
- data/lib/active_support/cache/memcached_snappy_store.rb +6 -7
- data/lib/active_support/cache/memcached_store.rb +110 -78
- data/lib/memcached_store.rb +1 -1
- data/lib/memcached_store/version.rb +1 -1
- metadata +8 -22
- data/.gitignore +0 -20
- data/.travis.yml +0 -16
- data/Gemfile +0 -21
- data/Rakefile +0 -21
- data/lib/memcached_store/memcached_safety.rb +0 -88
- data/memcached_store.gemspec +0 -22
- data/shipit.rubygems.yml +0 -4
- data/test/test_helper.rb +0 -21
- data/test/test_memcached_safety.rb +0 -142
- data/test/test_memcached_snappy_store.rb +0 -172
- data/test/test_memcached_store.rb +0 -601
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0915f7c2305d9b4962115d99c52997673e711a58
|
4
|
+
data.tar.gz: 0cc5bbca84c1aee1bcf70f782735d90cd562252d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8a0873627bf43775afd6ef3a7aeb9788a3b5d96d82eaac63f3a49879942e43daf9ace73d8c90c697fc0ca4a4f8a6ee777b3314339634c18734953c84e065d94
|
7
|
+
data.tar.gz: 5326f2375fa65be54b8c0f5a9c163e0a606c8f6a474ee21f7476c8175fa39252813392e206ad599494b3b72251b6054ad8c824024e963dd9addc3ea16316513c
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2013
|
1
|
+
Copyright (c) 2013-2016 Shopify Inc.
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ ActiveSupport memcached store. This wraps the memcached gem into a ActiveSupport
|
|
8
8
|
|
9
9
|
### MemcachedSnappyStore
|
10
10
|
|
11
|
-
ActiveSupport cache store that adds snappy compression at the cost of making the
|
11
|
+
ActiveSupport cache store that adds snappy compression at the cost of making the `incr, decr` operations unavailable.
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
@@ -40,9 +40,13 @@ config.cache_store = :memcached_store,
|
|
40
40
|
|
41
41
|
# for snappy store
|
42
42
|
config.cache_store = :memcached_snappy_store,
|
43
|
-
Memcached::Rails.new(:
|
43
|
+
Memcached::Rails.new(servers: ['memcached1.foo.com', 'memcached2.foo.com'])
|
44
44
|
```
|
45
45
|
|
46
|
+
## Benchmarks
|
47
|
+
|
48
|
+
For benchmarks please refer to https://github.com/basecamp/memcached_bench.
|
49
|
+
|
46
50
|
## Code status
|
47
51
|
|
48
52
|
[![Build Status](https://travis-ci.org/Shopify/memcached_store.svg?branch=master)](https://travis-ci.org/Shopify/memcached_store)
|
@@ -12,12 +12,12 @@ module ActiveSupport
|
|
12
12
|
class MemcachedSnappyStore < MemcachedStore
|
13
13
|
class UnsupportedOperation < StandardError; end
|
14
14
|
|
15
|
-
def increment(*
|
16
|
-
raise UnsupportedOperation
|
15
|
+
def increment(*)
|
16
|
+
raise UnsupportedOperation, "increment is not supported by: #{self.class.name}"
|
17
17
|
end
|
18
18
|
|
19
|
-
def decrement(*
|
20
|
-
raise UnsupportedOperation
|
19
|
+
def decrement(*)
|
20
|
+
raise UnsupportedOperation, "decrement is not supported by: #{self.class.name}"
|
21
21
|
end
|
22
22
|
|
23
23
|
# IdentityCache has its own handling for read only.
|
@@ -26,6 +26,7 @@ module ActiveSupport
|
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
29
|
+
|
29
30
|
def serialize_entry(entry, options)
|
30
31
|
value = options[:raw] ? entry.value.to_s : Marshal.dump(entry)
|
31
32
|
[Snappy.deflate(value), true]
|
@@ -34,12 +35,10 @@ module ActiveSupport
|
|
34
35
|
def deserialize_entry(compressed_value)
|
35
36
|
if compressed_value
|
36
37
|
super(Snappy.inflate(compressed_value))
|
37
|
-
else
|
38
|
-
nil
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
def cas_raw?(
|
41
|
+
def cas_raw?(_options)
|
43
42
|
true
|
44
43
|
end
|
45
44
|
end
|
@@ -11,21 +11,20 @@ module ActiveSupport
|
|
11
11
|
# MemcachedStore implements the Strategy::LocalCache strategy which implements
|
12
12
|
# an in-memory cache inside of a block.
|
13
13
|
class MemcachedStore < Store
|
14
|
-
FATAL_EXCEPTIONS = [
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
NONFATAL_EXCEPTIONS = []
|
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
|
+
NONFATAL_EXCEPTIONS = if defined?(::Rails) && ::Rails.env.test?
|
25
|
+
[]
|
27
26
|
else
|
28
|
-
|
27
|
+
Memcached::EXCEPTIONS - FATAL_EXCEPTIONS
|
29
28
|
end
|
30
29
|
|
31
30
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
@@ -41,7 +40,7 @@ module ActiveSupport
|
|
41
40
|
@data = addresses.first
|
42
41
|
else
|
43
42
|
mem_cache_options = options.dup
|
44
|
-
UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
|
43
|
+
UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) }
|
45
44
|
@data = Memcached::Rails.new(*(addresses + [mem_cache_options]))
|
46
45
|
end
|
47
46
|
|
@@ -53,24 +52,24 @@ module ActiveSupport
|
|
53
52
|
@logger = ::Rails.logger if defined?(::Rails)
|
54
53
|
end
|
55
54
|
|
56
|
-
def write(*
|
55
|
+
def write(*)
|
57
56
|
return true if read_only
|
58
|
-
super
|
57
|
+
super
|
59
58
|
end
|
60
59
|
|
61
|
-
def delete(*
|
60
|
+
def delete(*)
|
62
61
|
return true if read_only
|
63
|
-
super
|
62
|
+
super
|
64
63
|
end
|
65
64
|
|
66
65
|
def read_multi(*names)
|
67
66
|
options = names.extract_options!
|
68
67
|
options = merged_options(options)
|
69
|
-
keys_to_names = Hash[names.map{|name| [
|
68
|
+
keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
|
70
69
|
values = {}
|
71
70
|
|
72
71
|
instrument(:read_multi, names, options) do
|
73
|
-
if raw_values = @data.get_multi(keys_to_names.keys, :
|
72
|
+
if raw_values = @data.get_multi(keys_to_names.keys, raw: true)
|
74
73
|
raw_values.each do |key, value|
|
75
74
|
entry = deserialize_entry(value)
|
76
75
|
values[keys_to_names[key]] = entry.value unless entry.expired?
|
@@ -85,7 +84,7 @@ module ActiveSupport
|
|
85
84
|
|
86
85
|
def cas(name, options = nil)
|
87
86
|
options = merged_options(options)
|
88
|
-
key =
|
87
|
+
key = normalize_key(name, options)
|
89
88
|
|
90
89
|
instrument(:cas, name, options) do
|
91
90
|
@data.cas(key, expiration(options), cas_raw?(options)) do |raw_value|
|
@@ -101,21 +100,30 @@ module ActiveSupport
|
|
101
100
|
end
|
102
101
|
|
103
102
|
def cas_multi(*names)
|
104
|
-
|
105
103
|
options = names.extract_options!
|
104
|
+
return if names.empty?
|
105
|
+
|
106
106
|
options = merged_options(options)
|
107
|
-
keys_to_names = Hash[names.map{|name| [
|
107
|
+
keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
|
108
108
|
|
109
109
|
instrument(:cas_multi, names, options) do
|
110
110
|
@data.cas(keys_to_names.keys, expiration(options), cas_raw?(options)) do |raw_values|
|
111
111
|
values = {}
|
112
|
+
|
112
113
|
raw_values.each do |key, raw_value|
|
113
114
|
entry = deserialize_entry(raw_value)
|
114
115
|
values[keys_to_names[key]] = entry.value unless entry.expired?
|
115
116
|
end
|
117
|
+
|
116
118
|
values = yield values
|
119
|
+
|
117
120
|
break true if read_only
|
118
|
-
|
121
|
+
|
122
|
+
serialized_values = values.map do |name, value|
|
123
|
+
[normalize_key(name, options), serialize_entry(Entry.new(value, options), options).first]
|
124
|
+
end
|
125
|
+
|
126
|
+
Hash[serialized_values]
|
119
127
|
end
|
120
128
|
end
|
121
129
|
rescue *NONFATAL_EXCEPTIONS => e
|
@@ -125,8 +133,8 @@ module ActiveSupport
|
|
125
133
|
|
126
134
|
def increment(name, amount = 1, options = nil) # :nodoc:
|
127
135
|
options = merged_options(options)
|
128
|
-
instrument(:increment, name, :
|
129
|
-
@data.incr(
|
136
|
+
instrument(:increment, name, amount: amount) do
|
137
|
+
@data.incr(normalize_key(name, options), amount)
|
130
138
|
end
|
131
139
|
rescue *NONFATAL_EXCEPTIONS => e
|
132
140
|
@data.log_exception(e)
|
@@ -135,8 +143,8 @@ module ActiveSupport
|
|
135
143
|
|
136
144
|
def decrement(name, amount = 1, options = nil) # :nodoc:
|
137
145
|
options = merged_options(options)
|
138
|
-
instrument(:decrement, name, :
|
139
|
-
@data.decr(
|
146
|
+
instrument(:decrement, name, amount: amount) do
|
147
|
+
@data.decr(normalize_key(name, options), amount)
|
140
148
|
end
|
141
149
|
rescue *NONFATAL_EXCEPTIONS => e
|
142
150
|
@data.log_exception(e)
|
@@ -144,14 +152,18 @@ module ActiveSupport
|
|
144
152
|
end
|
145
153
|
|
146
154
|
def clear(options = nil)
|
147
|
-
instrument(
|
155
|
+
ActiveSupport::Notifications.instrument("cache_clear.active_support", options || {}) do
|
156
|
+
@data.flush_all
|
157
|
+
end
|
148
158
|
end
|
149
159
|
|
150
160
|
def stats
|
151
|
-
instrument(
|
161
|
+
ActiveSupport::Notifications.instrument("cache_stats.active_support") do
|
162
|
+
@data.stats
|
163
|
+
end
|
152
164
|
end
|
153
165
|
|
154
|
-
def exist?(*
|
166
|
+
def exist?(*)
|
155
167
|
!!super
|
156
168
|
end
|
157
169
|
|
@@ -163,70 +175,90 @@ module ActiveSupport
|
|
163
175
|
end
|
164
176
|
|
165
177
|
protected
|
166
|
-
def read_entry(key, options) # :nodoc:
|
167
|
-
deserialize_entry(@data.get(escape_key(key), true))
|
168
|
-
rescue *NONFATAL_EXCEPTIONS => e
|
169
|
-
@data.log_exception(e)
|
170
|
-
nil
|
171
|
-
end
|
172
178
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
rescue *NONFATAL_EXCEPTIONS => e
|
180
|
-
@data.log_exception(e)
|
181
|
-
false
|
182
|
-
end
|
179
|
+
def read_entry(key, _options) # :nodoc:
|
180
|
+
deserialize_entry(@data.get(escape_key(key), true))
|
181
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
182
|
+
@data.log_exception(e)
|
183
|
+
nil
|
184
|
+
end
|
183
185
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
186
|
+
def write_entry(key, entry, options) # :nodoc:
|
187
|
+
return true if read_only
|
188
|
+
method = options && options[:unless_exist] ? :add : :set
|
189
|
+
expires_in = expiration(options)
|
190
|
+
value, raw = serialize_entry(entry, options)
|
191
|
+
@data.send(method, escape_key(key), value, expires_in, raw)
|
192
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
193
|
+
@data.log_exception(e)
|
194
|
+
false
|
195
|
+
end
|
196
|
+
|
197
|
+
def delete_entry(key, _options) # :nodoc:
|
198
|
+
return true if read_only
|
199
|
+
@data.delete(escape_key(key))
|
200
|
+
true
|
201
|
+
rescue *NONFATAL_EXCEPTIONS => e
|
202
|
+
@data.log_exception(e)
|
203
|
+
false
|
204
|
+
end
|
192
205
|
|
193
206
|
private
|
194
207
|
|
208
|
+
if ActiveSupport::VERSION::MAJOR < 5
|
209
|
+
def normalize_key(key, options)
|
210
|
+
escape_key(namespaced_key(key, options))
|
211
|
+
end
|
212
|
+
|
195
213
|
def escape_key(key)
|
196
214
|
key = key.to_s.dup
|
197
215
|
key = key.force_encoding(Encoding::ASCII_8BIT)
|
198
|
-
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
216
|
+
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
199
217
|
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
200
218
|
key
|
201
219
|
end
|
202
|
-
|
203
|
-
def
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
end
|
220
|
+
else
|
221
|
+
def normalize_key(key, options)
|
222
|
+
key = super.dup
|
223
|
+
key = key.force_encoding(Encoding::ASCII_8BIT)
|
224
|
+
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
225
|
+
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
226
|
+
key
|
210
227
|
end
|
211
228
|
|
212
|
-
def
|
213
|
-
|
214
|
-
[entry, options[:raw]]
|
229
|
+
def escape_key(key)
|
230
|
+
key
|
215
231
|
end
|
232
|
+
end
|
216
233
|
|
217
|
-
|
218
|
-
|
234
|
+
def deserialize_entry(raw_value)
|
235
|
+
if raw_value
|
236
|
+
entry = begin
|
237
|
+
Marshal.load(raw_value)
|
238
|
+
rescue
|
239
|
+
raw_value
|
240
|
+
end
|
241
|
+
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
219
242
|
end
|
243
|
+
end
|
220
244
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
245
|
+
def serialize_entry(entry, options)
|
246
|
+
entry = entry.value.to_s if options[:raw]
|
247
|
+
[entry, options[:raw]]
|
248
|
+
end
|
249
|
+
|
250
|
+
def cas_raw?(options)
|
251
|
+
options[:raw]
|
252
|
+
end
|
229
253
|
|
254
|
+
def expiration(options)
|
255
|
+
expires_in = options[:expires_in].to_i
|
256
|
+
if expires_in > 0 && !options[:raw]
|
257
|
+
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
258
|
+
expires_in += 5.minutes
|
259
|
+
end
|
260
|
+
expires_in
|
261
|
+
end
|
230
262
|
end
|
231
263
|
end
|
232
264
|
end
|
data/lib/memcached_store.rb
CHANGED
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: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Camilo Lopez
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2016-
|
14
|
+
date: 2016-12-01 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -19,14 +19,14 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '4'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '4'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: memcached
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -65,25 +65,15 @@ executables: []
|
|
65
65
|
extensions: []
|
66
66
|
extra_rdoc_files: []
|
67
67
|
files:
|
68
|
-
- ".gitignore"
|
69
|
-
- ".travis.yml"
|
70
|
-
- Gemfile
|
71
68
|
- LICENSE
|
72
69
|
- README.md
|
73
|
-
- Rakefile
|
74
70
|
- lib/active_support/cache/memcached_snappy_store.rb
|
75
71
|
- lib/active_support/cache/memcached_store.rb
|
76
72
|
- lib/memcached_store.rb
|
77
|
-
- lib/memcached_store/memcached_safety.rb
|
78
73
|
- lib/memcached_store/version.rb
|
79
|
-
- memcached_store.gemspec
|
80
|
-
- shipit.rubygems.yml
|
81
|
-
- test/test_helper.rb
|
82
|
-
- test/test_memcached_safety.rb
|
83
|
-
- test/test_memcached_snappy_store.rb
|
84
|
-
- test/test_memcached_store.rb
|
85
74
|
homepage: https://github.com/Shopify/memcached_store/
|
86
|
-
licenses:
|
75
|
+
licenses:
|
76
|
+
- MIT
|
87
77
|
metadata: {}
|
88
78
|
post_install_message:
|
89
79
|
rdoc_options: []
|
@@ -93,7 +83,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
83
|
requirements:
|
94
84
|
- - ">="
|
95
85
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
86
|
+
version: 2.2.0
|
97
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
88
|
requirements:
|
99
89
|
- - ">="
|
@@ -105,8 +95,4 @@ rubygems_version: 2.5.1
|
|
105
95
|
signing_key:
|
106
96
|
specification_version: 4
|
107
97
|
summary: Plugin-able Memcached adapters to add features (compression, safety)
|
108
|
-
test_files:
|
109
|
-
- test/test_helper.rb
|
110
|
-
- test/test_memcached_safety.rb
|
111
|
-
- test/test_memcached_snappy_store.rb
|
112
|
-
- test/test_memcached_store.rb
|
98
|
+
test_files: []
|