@@ -14,58 +14,21 @@ module Cache
1414 class MemcachedStore < Store
1515 ESCAPE_KEY_CHARS = /[\x00 -\x20 %\x7F -\xFF ]/n
1616
17- class Codec
18- # use dalli compatible flags
19- SERIALIZED_FLAG = 0x1
20- COMPRESSED_FLAG = 0x2
21-
22- # Older versions of this gem would use 0 for the flags whether or not
23- # the value was marshal dumped. By setting this flag, we can tell if
24- # it were set with an older version for backwards compatible decoding.
25- RAW_FLAG = 0x10
26-
27- def initialize ( serializer : Marshal , compressor : nil )
28- @serializer = serializer
29- @compressor = compressor
30- end
31-
32- def encode ( _key , value , flags )
33- unless value . is_a? ( String )
34- flags |= SERIALIZED_FLAG
35- value = @serializer . dump ( value )
36- end
37- if @compressor
38- flags |= COMPRESSED_FLAG
39- value = @compressor . compress ( value )
40- end
41- flags |= RAW_FLAG if flags == 0
17+ module RawCodec
18+ def self . encode ( _key , value , flags )
4219 [ value , flags ]
4320 end
4421
45- def decode ( _key , value , flags )
46- if ( flags & COMPRESSED_FLAG ) != 0
47- value = @compressor . decompress ( value )
48- end
49-
50- if ( flags & SERIALIZED_FLAG ) != 0
51- @serializer . load ( value )
52- elsif flags == 0 # legacy cache value
53- @serializer . load ( value ) rescue value
54- else
55- value
56- end
22+ def self . decode ( _key , value , _flags )
23+ value
5724 end
5825 end
5926
60- attr_accessor :read_only , :swallow_exceptions
61-
6227 prepend ( Strategy ::LocalCache )
6328
6429 def initialize ( *addresses , **options )
6530 addresses = addresses . flatten
66- options [ :codec ] ||= Codec . new
67- @swallow_exceptions = true
68- @swallow_exceptions = options . delete ( :swallow_exceptions ) if options . key? ( :swallow_exceptions )
31+ options [ :codec ] ||= RawCodec
6932
7033 super ( options )
7134
@@ -82,7 +45,6 @@ def initialize(*addresses, **options)
8245 end
8346
8447 def append ( name , value , options = nil )
85- return true if read_only
8648 options = merged_options ( options )
8749 normalized_key = normalize_key ( name , options )
8850
@@ -94,16 +56,6 @@ def append(name, value, options = nil)
9456 end
9557 end
9658
97- def write ( *)
98- return true if read_only
99- super
100- end
101-
102- def delete ( *)
103- return true if read_only
104- super
105- end
106-
10759 def read_multi ( *names )
10860 options = names . extract_options!
10961 return { } if names . empty?
@@ -116,7 +68,7 @@ def read_multi(*names)
11668 instrument ( :read_multi , names , options ) do
11769 if raw_values = @connection . get ( keys_to_names . keys )
11870 raw_values . each do |key , value |
119- entry = deserialize_entry ( value )
71+ entry = deserialize_entry ( value , ** options )
12072 values [ keys_to_names [ key ] ] = entry . value unless entry . expired?
12173 end
12274 end
@@ -135,7 +87,6 @@ def cas(name, options = nil)
13587 @connection . cas ( key , expiration ( options ) ) do |raw_value |
13688 entry = deserialize_entry ( raw_value )
13789 value = yield entry . value
138- break true if read_only
13990 payload = serialize_entry ( Entry . new ( value , **options ) , options )
14091 end
14192 end
@@ -171,10 +122,8 @@ def cas_multi(*names, **options)
171122
172123 values = yield values
173124
174- break true if read_only
175-
176125 serialized_values = values . map do |name , value |
177- [ normalize_key ( name , options ) , serialize_entry ( Entry . new ( value , **options ) , options ) ]
126+ [ normalize_key ( name , options ) , serialize_entry ( Entry . new ( value , **options ) , ** options ) ]
178127 end
179128
180129 sent_payloads = Hash [ serialized_values ]
@@ -237,118 +186,63 @@ def reset #:nodoc:
237186
238187 private
239188
240- if private_method_defined? ( :read_serialized_entry )
241- class DupLocalStore < DelegateClass ( Strategy ::LocalCache ::LocalStore )
242- def write_entry ( _key , entry )
243- if entry . is_a? ( Entry )
244- entry . dup_value!
245- end
246- super
247- end
248-
249- def fetch_entry ( key )
250- entry = super do
251- new_entry = yield
252- if entry . is_a? ( Entry )
253- new_entry . dup_value!
254- end
255- new_entry
256- end
257- entry = entry . dup
258-
259- if entry . is_a? ( Entry )
260- entry . dup_value!
261- end
262-
263- entry
264- end
265- end
266-
267- module DupLocalCache
268- private
269-
270- def local_cache
271- if local_cache = super
272- DupLocalStore . new ( local_cache )
273- end
274- end
275- end
276-
277- prepend DupLocalCache
278-
279- def read_entry ( key , **options ) # :nodoc:
280- deserialize_entry ( read_serialized_entry ( key , **options ) )
281- end
282-
283- def read_serialized_entry ( key , **)
284- handle_exceptions ( return_value_on_error : nil ) do
285- @connection . get ( key )
286- end
189+ def read_entry ( key , **options ) # :nodoc:
190+ handle_exceptions ( return_value_on_error : nil ) do
191+ deserialize_entry ( read_serialized_entry ( key , **options ) , **options )
287192 end
193+ end
288194
289- def write_entry ( key , entry , **options ) # :nodoc:
290- return true if read_only
291-
292- write_serialized_entry ( key , serialize_entry ( entry , **options ) , **options )
195+ def read_serialized_entry ( key , **)
196+ handle_exceptions ( return_value_on_error : nil ) do
197+ @connection . get ( key )
293198 end
199+ end
294200
295- def write_serialized_entry ( key , value , **options )
296- method = options && options [ :unless_exist ] ? :add : :set
297- expires_in = expiration ( options )
298- handle_exceptions ( return_value_on_error : false ) do
299- @connection . send ( method , key , value , expires_in )
300- true
301- end
302- end
303- else
304- def read_entry ( key , _options ) # :nodoc:
305- handle_exceptions ( return_value_on_error : nil ) do
306- deserialize_entry ( @connection . get ( key ) )
307- end
308- end
201+ def write_entry ( key , entry , **options ) # :nodoc:
202+ write_serialized_entry ( key , serialize_entry ( entry , **options ) , **options )
203+ end
309204
310- def write_entry ( key , entry , options ) # :nodoc:
311- return true if read_only
312- method = options && options [ :unless_exist ] ? :add : :set
313- expires_in = expiration ( options )
314- value = serialize_entry ( entry , options )
315- handle_exceptions ( return_value_on_error : false ) do
316- @connection . send ( method , key , value , expires_in )
317- true
318- end
205+ def write_serialized_entry ( key , value , **options )
206+ method = options && options [ :unless_exist ] ? :add : :set
207+ expires_in = expiration ( options )
208+ handle_exceptions ( return_value_on_error : false ) do
209+ @connection . send ( method , key , value , expires_in )
210+ true
319211 end
320212 end
321213
322214 def delete_entry ( key , _options ) # :nodoc:
323- return true if read_only
324215 handle_exceptions ( return_value_on_error : false , on_miss : true ) do
325216 @connection . delete ( key )
326217 true
327218 end
328219 end
329220
330- private
331-
332221 def normalize_key ( key , options )
333222 key = super . dup
334223 key = key . force_encoding ( Encoding ::ASCII_8BIT )
335224 key = key . gsub ( ESCAPE_KEY_CHARS ) { |match | "%#{ match . getbyte ( 0 ) . to_s ( 16 ) . upcase } " }
336- # When we remove support to Rails 5.1 we can change the code to use ActiveSupport::Digest
337225 key = "#{ key [ 0 , 213 ] } :md5:#{ ::Digest ::MD5 . hexdigest ( key ) } " if key . size > 250
338226 key
339227 end
340228
341- def deserialize_entry ( value )
342- unless value . nil?
343- value . is_a? ( Entry ) ? value : Entry . new ( value , compress : false )
229+ def deserialize_entry ( payload , raw : false , **)
230+ if !payload . nil? && raw
231+ if payload . is_a? ( Entry )
232+ payload
233+ else
234+ Entry . new ( payload , compress : false )
235+ end
236+ else
237+ super ( payload )
344238 end
345239 end
346240
347- def serialize_entry ( entry , options )
348- if options [ : raw]
241+ def serialize_entry ( entry , raw : false , ** )
242+ if raw
349243 entry . value . to_s
350244 else
351- entry
245+ super ( entry )
352246 end
353247 end
354248
@@ -364,19 +258,16 @@ def handle_exceptions(return_value_on_error:, on_miss: return_value_on_error, mi
364258 yield
365259 rescue Memcached ::NotFound , Memcached ::ConnectionDataExists , *miss_exceptions
366260 on_miss
261+ rescue Memcached ::NotStored
262+ return_value_on_error
367263 rescue Memcached ::Error => e
368264 log_warning ( e )
369- raise unless @swallow_exceptions
370265 return_value_on_error
371266 end
372267
373268 def log_warning ( err )
374- return unless logger
375- return if err . is_a? ( Memcached ::NotStored ) && @swallow_exceptions
376-
377- logger . warn (
378- "[MEMCACHED_ERROR] swallowed=#{ @swallow_exceptions } " \
379- " exception_class=#{ err . class } exception_message=#{ err . message } "
269+ logger &.warn (
270+ "[MEMCACHED_ERROR] exception_class=#{ err . class } exception_message=#{ err . message } "
380271 )
381272 end
382273
0 commit comments