memcached_store 2.0.1 → 2.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: aa72b41fd6b6cb58a042294012e8f736c3b5ef62
4
- data.tar.gz: e053cc731f76cb2bc909e36f7f004002b2fd7e38
2
+ SHA256:
3
+ metadata.gz: 4635e49b33c70f622363339dda844ed847785724779b9fa7820d4a34dbf372f8
4
+ data.tar.gz: 2371f00c595f4b9fb5f4fd37621a591e8ac11125b53467dbbd990febfa9296d9
5
5
  SHA512:
6
- metadata.gz: 2045826e00f5d2c2d988eed051036713348bafcd7867bf06b1f6760decea9719e62a0cfc332ee82f3e3ef84f2eecb65ab7eba373f1e969f5592cfa53eb12a034
7
- data.tar.gz: c36fde971c9abc498626b8662cb87977369e85c3818efbbb5bf23bf0ec0bf51e9a17e338dce98661c41b7fdb2abbf7fc6a1a271bea0cb0a8fd177e8f9e5dccf7
6
+ metadata.gz: 18831e059e7db2fae9d3733baa244f2ba69050bfc1d72ecd72dd80332a0e525b50a409f98cb76d224450fce01919e29695ba3c5585cadc42bfaef1b66474ac72
7
+ data.tar.gz: cc44c59b08101ac3934ce59b90c89179d0b88c64dd519d265b81e76adbb09c8d3e2f5b4445e7de6e8c73973df615c46a613a29dd5f9c0db8acfa6d2c788d4445
@@ -12,6 +12,16 @@ module ActiveSupport
12
12
  class MemcachedSnappyStore < MemcachedStore
13
13
  class UnsupportedOperation < StandardError; end
14
14
 
15
+ module SnappyCompressor
16
+ def self.compress(source)
17
+ Snappy.deflate(source)
18
+ end
19
+
20
+ def self.decompress(source)
21
+ Snappy.inflate(source)
22
+ end
23
+ end
24
+
15
25
  def increment(*)
16
26
  raise UnsupportedOperation, "increment is not supported by: #{self.class.name}"
17
27
  end
@@ -25,21 +35,10 @@ module ActiveSupport
25
35
  false
26
36
  end
27
37
 
28
- private
29
-
30
- def serialize_entry(entry, options)
31
- value = options[:raw] ? entry.value.to_s : Marshal.dump(entry)
32
- [Snappy.deflate(value), true]
33
- end
34
-
35
- def deserialize_entry(compressed_value)
36
- if compressed_value
37
- super(Snappy.inflate(compressed_value))
38
- end
39
- end
40
-
41
- def cas_raw?(_options)
42
- true
38
+ def initialize(*addresses, **options)
39
+ options[:codec] ||= ActiveSupport::Cache::MemcachedStore::Codec.new(compressor: SnappyCompressor)
40
+ options[:compress] = false
41
+ super(*addresses, **options)
43
42
  end
44
43
  end
45
44
  end
@@ -13,30 +13,86 @@ module ActiveSupport
13
13
  class MemcachedStore < Store
14
14
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
15
15
 
16
+ class Codec
17
+ # use dalli compatible flags
18
+ SERIALIZED_FLAG = 0x1
19
+ COMPRESSED_FLAG = 0x2
20
+
21
+ # Older versions of this gem would use 0 for the flags whether or not
22
+ # the value was marshal dumped. By setting this flag, we can tell if
23
+ # it were set with an older version for backwards compatible decoding.
24
+ RAW_FLAG = 0x10
25
+
26
+ def initialize(serializer: Marshal, compressor: nil)
27
+ @serializer = serializer
28
+ @compressor = compressor
29
+ end
30
+
31
+ def encode(_key, value, flags)
32
+ unless value.is_a?(String)
33
+ flags |= SERIALIZED_FLAG
34
+ value = @serializer.dump(value)
35
+ end
36
+ if @compressor
37
+ flags |= COMPRESSED_FLAG
38
+ value = @compressor.compress(value)
39
+ end
40
+ flags |= RAW_FLAG if flags == 0
41
+ [value, flags]
42
+ end
43
+
44
+ def decode(_key, value, flags)
45
+ if (flags & COMPRESSED_FLAG) != 0
46
+ value = @compressor.decompress(value)
47
+ end
48
+
49
+ if (flags & SERIALIZED_FLAG) != 0
50
+ @serializer.load(value)
51
+ elsif flags == 0 # legacy cache value
52
+ @serializer.load(value) rescue value
53
+ else
54
+ value
55
+ end
56
+ end
57
+ end
58
+
16
59
  attr_accessor :read_only, :swallow_exceptions
17
60
 
18
- def initialize(*addresses)
61
+ def initialize(*addresses, **options)
19
62
  addresses = addresses.flatten
20
- options = addresses.extract_options!
63
+ options[:codec] ||= Codec.new
21
64
  @swallow_exceptions = true
22
65
  @swallow_exceptions = options.delete(:swallow_exceptions) if options.key?(:swallow_exceptions)
23
66
 
24
67
  super(options)
25
68
 
26
69
  if addresses.first.is_a?(Memcached)
27
- @data = addresses.first
70
+ @connection = addresses.first
28
71
  raise "Memcached::Rails is no longer supported, "\
29
- "use a Memcached instance instead" if @data.is_a?(Memcached::Rails)
72
+ "use a Memcached instance instead" if @connection.is_a?(Memcached::Rails)
30
73
  else
31
74
  mem_cache_options = options.dup
32
75
  servers = mem_cache_options.delete(:servers)
33
76
  UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) }
34
- @data = Memcached.new([*addresses, *servers], mem_cache_options)
77
+ @connection = Memcached.new([*addresses, *servers], mem_cache_options)
35
78
  end
36
79
 
37
80
  extend Strategy::LocalCache
38
81
  end
39
82
 
83
+ def append(name, value, options = nil)
84
+ return true if read_only
85
+ options = merged_options(options)
86
+ normalized_key = normalize_key(name, options)
87
+
88
+ handle_exceptions(return_value_on_error: nil, on_miss: false, miss_exceptions: [Memcached::NotStored]) do
89
+ instrument(:append, name) do
90
+ @connection.append(normalized_key, value)
91
+ end
92
+ true
93
+ end
94
+ end
95
+
40
96
  def write(*)
41
97
  return true if read_only
42
98
  super
@@ -57,7 +113,7 @@ module ActiveSupport
57
113
 
58
114
  handle_exceptions(return_value_on_error: {}) do
59
115
  instrument(:read_multi, names, options) do
60
- if raw_values = @data.get(keys_to_names.keys, false)
116
+ if raw_values = @connection.get(keys_to_names.keys)
61
117
  raw_values.each do |key, value|
62
118
  entry = deserialize_entry(value)
63
119
  values[keys_to_names[key]] = entry.value unless entry.expired?
@@ -74,19 +130,18 @@ module ActiveSupport
74
130
 
75
131
  handle_exceptions(return_value_on_error: false) do
76
132
  instrument(:cas, name, options) do
77
- @data.cas(key, expiration(options), !cas_raw?(options)) do |raw_value|
133
+ @connection.cas(key, expiration(options)) do |raw_value|
78
134
  entry = deserialize_entry(raw_value)
79
135
  value = yield entry.value
80
136
  break true if read_only
81
- serialize_entry(Entry.new(value, options), options).first
137
+ serialize_entry(Entry.new(value, **options), options)
82
138
  end
83
139
  end
84
140
  true
85
141
  end
86
142
  end
87
143
 
88
- def cas_multi(*names)
89
- options = names.extract_options!
144
+ def cas_multi(*names, **options)
90
145
  return if names.empty?
91
146
 
92
147
  options = merged_options(options)
@@ -94,7 +149,7 @@ module ActiveSupport
94
149
 
95
150
  handle_exceptions(return_value_on_error: false) do
96
151
  instrument(:cas_multi, names, options) do
97
- @data.cas(keys_to_names.keys, expiration(options), !cas_raw?(options)) do |raw_values|
152
+ @connection.cas(keys_to_names.keys, expiration(options)) do |raw_values|
98
153
  values = {}
99
154
 
100
155
  raw_values.each do |key, raw_value|
@@ -107,7 +162,7 @@ module ActiveSupport
107
162
  break true if read_only
108
163
 
109
164
  serialized_values = values.map do |name, value|
110
- [normalize_key(name, options), serialize_entry(Entry.new(value, options), options).first]
165
+ [normalize_key(name, options), serialize_entry(Entry.new(value, **options), options)]
111
166
  end
112
167
 
113
168
  Hash[serialized_values]
@@ -121,7 +176,7 @@ module ActiveSupport
121
176
  options = merged_options(options)
122
177
  handle_exceptions(return_value_on_error: nil) do
123
178
  instrument(:increment, name, amount: amount) do
124
- @data.incr(normalize_key(name, options), amount)
179
+ @connection.incr(normalize_key(name, options), amount)
125
180
  end
126
181
  end
127
182
  end
@@ -130,20 +185,20 @@ module ActiveSupport
130
185
  options = merged_options(options)
131
186
  handle_exceptions(return_value_on_error: nil) do
132
187
  instrument(:decrement, name, amount: amount) do
133
- @data.decr(normalize_key(name, options), amount)
188
+ @connection.decr(normalize_key(name, options), amount)
134
189
  end
135
190
  end
136
191
  end
137
192
 
138
193
  def clear(options = nil)
139
194
  ActiveSupport::Notifications.instrument("cache_clear.active_support", options || {}) do
140
- @data.flush
195
+ @connection.flush
141
196
  end
142
197
  end
143
198
 
144
199
  def stats
145
200
  ActiveSupport::Notifications.instrument("cache_stats.active_support") do
146
- @data.stats
201
+ @connection.stats
147
202
  end
148
203
  end
149
204
 
@@ -153,7 +208,7 @@ module ActiveSupport
153
208
 
154
209
  def reset #:nodoc:
155
210
  handle_exceptions(return_value_on_error: false) do
156
- @data.reset
211
+ @connection.reset
157
212
  end
158
213
  end
159
214
 
@@ -161,7 +216,7 @@ module ActiveSupport
161
216
 
162
217
  def read_entry(key, _options) # :nodoc:
163
218
  handle_exceptions(return_value_on_error: nil) do
164
- deserialize_entry(@data.get(escape_key(key), false))
219
+ deserialize_entry(@connection.get(escape_key(key)))
165
220
  end
166
221
  end
167
222
 
@@ -169,9 +224,9 @@ module ActiveSupport
169
224
  return true if read_only
170
225
  method = options && options[:unless_exist] ? :add : :set
171
226
  expires_in = expiration(options)
172
- value, raw = serialize_entry(entry, options)
227
+ value = serialize_entry(entry, options)
173
228
  handle_exceptions(return_value_on_error: false) do
174
- @data.send(method, escape_key(key), value, expires_in, !raw)
229
+ @connection.send(method, escape_key(key), value, expires_in)
175
230
  true
176
231
  end
177
232
  end
@@ -179,7 +234,7 @@ module ActiveSupport
179
234
  def delete_entry(key, _options) # :nodoc:
180
235
  return true if read_only
181
236
  handle_exceptions(return_value_on_error: false, on_miss: true) do
182
- @data.delete(escape_key(key))
237
+ @connection.delete(escape_key(key))
183
238
  true
184
239
  end
185
240
  end
@@ -213,38 +268,31 @@ module ActiveSupport
213
268
  end
214
269
  end
215
270
 
216
- def deserialize_entry(raw_value)
217
- if raw_value
218
- entry = begin
219
- Marshal.load(raw_value)
220
- rescue
221
- raw_value
222
- end
223
- entry.is_a?(Entry) ? entry : Entry.new(entry)
271
+ def deserialize_entry(value)
272
+ if value
273
+ value.is_a?(Entry) ? value : Entry.new(value, compress: false)
224
274
  end
225
275
  end
226
276
 
227
277
  def serialize_entry(entry, options)
228
- entry = entry.value.to_s if options[:raw]
229
- [entry, options[:raw]]
230
- end
231
-
232
- def cas_raw?(options)
233
- options[:raw]
278
+ if options[:raw]
279
+ entry.value.to_s
280
+ else
281
+ entry
282
+ end
234
283
  end
235
284
 
236
285
  def expiration(options)
237
286
  expires_in = options[:expires_in].to_i
238
- if expires_in > 0 && !options[:raw]
239
- # Set the memcache expire a few minutes in the future to support race condition ttls on read
240
- expires_in += 5.minutes.to_i
287
+ if expires_in > 0 && options[:race_condition_ttl] && !options[:raw]
288
+ expires_in += options[:race_condition_ttl].to_i
241
289
  end
242
290
  expires_in
243
291
  end
244
292
 
245
- def handle_exceptions(return_value_on_error:, on_miss: return_value_on_error)
293
+ def handle_exceptions(return_value_on_error:, on_miss: return_value_on_error, miss_exceptions: [])
246
294
  yield
247
- rescue Memcached::NotFound, Memcached::ConnectionDataExists
295
+ rescue Memcached::NotFound, Memcached::ConnectionDataExists, *miss_exceptions
248
296
  on_miss
249
297
  rescue Memcached::Error => e
250
298
  log_warning(e)
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module MemcachedStore
3
- VERSION = "2.0.1"
3
+ VERSION = "2.1.5"
4
4
  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: 2.0.1
4
+ version: 2.1.5
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: 2018-08-23 00:00:00.000000000 Z
14
+ date: 2020-05-25 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -75,7 +75,8 @@ files:
75
75
  homepage: https://github.com/Shopify/memcached_store/
76
76
  licenses:
77
77
  - MIT
78
- metadata: {}
78
+ metadata:
79
+ allowed_push_host: https://rubygems.org
79
80
  post_install_message:
80
81
  rdoc_options: []
81
82
  require_paths:
@@ -91,8 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
92
  - !ruby/object:Gem::Version
92
93
  version: '0'
93
94
  requirements: []
94
- rubyforge_project:
95
- rubygems_version: 2.6.14
95
+ rubygems_version: 3.0.3
96
96
  signing_key:
97
97
  specification_version: 4
98
98
  summary: Plugin-able Memcached adapters to add features (compression, safety)