@@ -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
@@ -134,8 +86,7 @@ def cas(name, options = nil)
13486 @connection . cas ( key , expiration ( options ) ) do |raw_value |
13587 entry = deserialize_entry ( raw_value )
13688 value = yield entry . value
137- break true if read_only
138- serialize_entry ( Entry . new ( value , **options ) , options )
89+ serialize_entry ( Entry . new ( value , **options ) , **options )
13990 end
14091 end
14192 true
@@ -160,10 +111,8 @@ def cas_multi(*names, **options)
160111
161112 values = yield values
162113
163- break true if read_only
164-
165114 serialized_values = values . map do |name , value |
166- [ normalize_key ( name , options ) , serialize_entry ( Entry . new ( value , **options ) , options ) ]
115+ [ normalize_key ( name , options ) , serialize_entry ( Entry . new ( value , **options ) , ** options ) ]
167116 end
168117
169118 Hash [ serialized_values ]
@@ -215,118 +164,61 @@ def reset #:nodoc:
215164
216165 private
217166
218- if private_method_defined? ( :read_serialized_entry )
219- class DupLocalStore < DelegateClass ( Strategy ::LocalCache ::LocalStore )
220- def write_entry ( _key , entry )
221- if entry . is_a? ( Entry )
222- entry . dup_value!
223- end
224- super
225- end
226-
227- def fetch_entry ( key )
228- entry = super do
229- new_entry = yield
230- if entry . is_a? ( Entry )
231- new_entry . dup_value!
232- end
233- new_entry
234- end
235- entry = entry . dup
236-
237- if entry . is_a? ( Entry )
238- entry . dup_value!
239- end
240-
241- entry
242- end
243- end
244-
245- module DupLocalCache
246- private
247-
248- def local_cache
249- if local_cache = super
250- DupLocalStore . new ( local_cache )
251- end
252- end
253- end
254-
255- prepend DupLocalCache
256-
257- def read_entry ( key , **options ) # :nodoc:
258- deserialize_entry ( read_serialized_entry ( key , **options ) )
259- end
260-
261- def read_serialized_entry ( key , **)
262- handle_exceptions ( return_value_on_error : nil ) do
263- @connection . get ( key )
264- end
265- end
266-
267- def write_entry ( key , entry , **options ) # :nodoc:
268- return true if read_only
167+ def read_entry ( key , **options ) # :nodoc:
168+ deserialize_entry ( read_serialized_entry ( key , **options ) , **options )
169+ end
269170
270- write_serialized_entry ( key , serialize_entry ( entry , **options ) , **options )
171+ def read_serialized_entry ( key , **)
172+ handle_exceptions ( return_value_on_error : nil ) do
173+ @connection . get ( key )
271174 end
175+ end
272176
273- def write_serialized_entry ( key , value , **options )
274- method = options && options [ :unless_exist ] ? :add : :set
275- expires_in = expiration ( options )
276- handle_exceptions ( return_value_on_error : false ) do
277- @connection . send ( method , key , value , expires_in )
278- true
279- end
280- end
281- else
282- def read_entry ( key , _options ) # :nodoc:
283- handle_exceptions ( return_value_on_error : nil ) do
284- deserialize_entry ( @connection . get ( key ) )
285- end
286- end
177+ def write_entry ( key , entry , **options ) # :nodoc:
178+ write_serialized_entry ( key , serialize_entry ( entry , **options ) , **options )
179+ end
287180
288- def write_entry ( key , entry , options ) # :nodoc:
289- return true if read_only
290- method = options && options [ :unless_exist ] ? :add : :set
291- expires_in = expiration ( options )
292- value = serialize_entry ( entry , options )
293- handle_exceptions ( return_value_on_error : false ) do
294- @connection . send ( method , key , value , expires_in )
295- true
296- end
181+ def write_serialized_entry ( key , value , **options )
182+ method = options && options [ :unless_exist ] ? :add : :set
183+ expires_in = expiration ( options )
184+ handle_exceptions ( return_value_on_error : false ) do
185+ @connection . send ( method , key , value , expires_in )
186+ true
297187 end
298188 end
299189
300190 def delete_entry ( key , _options ) # :nodoc:
301- return true if read_only
302191 handle_exceptions ( return_value_on_error : false , on_miss : true ) do
303192 @connection . delete ( key )
304193 true
305194 end
306195 end
307196
308- private
309-
310197 def normalize_key ( key , options )
311198 key = super . dup
312199 key = key . force_encoding ( Encoding ::ASCII_8BIT )
313200 key = key . gsub ( ESCAPE_KEY_CHARS ) { |match | "%#{ match . getbyte ( 0 ) . to_s ( 16 ) . upcase } " }
314- # When we remove support to Rails 5.1 we can change the code to use ActiveSupport::Digest
315201 key = "#{ key [ 0 , 213 ] } :md5:#{ ::Digest ::MD5 . hexdigest ( key ) } " if key . size > 250
316202 key
317203 end
318204
319- def deserialize_entry ( value )
320- unless value . nil?
321- value . is_a? ( Entry ) ? value : Entry . new ( value , compress : false )
205+ def deserialize_entry ( payload , raw : false , **)
206+ if !payload . nil? && raw
207+ if payload . is_a? ( Entry )
208+ payload
209+ else
210+ Entry . new ( payload , compress : false )
211+ end
212+ else
213+ super ( payload )
322214 end
323215 end
324216
325- def serialize_entry ( entry , options )
326- if options [ : raw]
217+ def serialize_entry ( entry , raw : false , ** )
218+ if raw
327219 entry . value . to_s
328220 else
329- entry
221+ super ( entry )
330222 end
331223 end
332224
@@ -342,19 +234,16 @@ def handle_exceptions(return_value_on_error:, on_miss: return_value_on_error, mi
342234 yield
343235 rescue Memcached ::NotFound , Memcached ::ConnectionDataExists , *miss_exceptions
344236 on_miss
237+ rescue Memcached ::NotStored
238+ return_value_on_error
345239 rescue Memcached ::Error => e
346240 log_warning ( e )
347- raise unless @swallow_exceptions
348241 return_value_on_error
349242 end
350243
351244 def log_warning ( err )
352- return unless logger
353- return if err . is_a? ( Memcached ::NotStored ) && @swallow_exceptions
354-
355- logger . warn (
356- "[MEMCACHED_ERROR] swallowed=#{ @swallow_exceptions } " \
357- " exception_class=#{ err . class } exception_message=#{ err . message } "
245+ logger &.warn (
246+ "[MEMCACHED_ERROR] exception_class=#{ err . class } exception_message=#{ err . message } "
358247 )
359248 end
360249
0 commit comments