dalli 2.7.0 → 2.7.11
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dalli might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/Gemfile +6 -3
- data/History.md +94 -0
- data/LICENSE +1 -1
- data/README.md +62 -43
- data/lib/action_dispatch/middleware/session/dalli_store.rb +2 -1
- data/lib/active_support/cache/dalli_store.rb +121 -41
- data/lib/dalli/cas/client.rb +5 -4
- data/lib/dalli/client.rb +103 -52
- data/lib/dalli/compressor.rb +2 -1
- data/lib/dalli/options.rb +1 -0
- data/lib/dalli/railtie.rb +1 -0
- data/lib/dalli/ring.rb +6 -6
- data/lib/dalli/server.rb +151 -91
- data/lib/dalli/socket.rb +104 -42
- data/lib/dalli/version.rb +2 -1
- data/lib/dalli.rb +3 -0
- data/lib/rack/session/dalli.rb +140 -27
- metadata +22 -95
- data/Performance.md +0 -42
- data/Rakefile +0 -42
- data/dalli.gemspec +0 -29
- data/test/benchmark_test.rb +0 -242
- data/test/helper.rb +0 -55
- data/test/memcached_mock.rb +0 -121
- data/test/sasldb +0 -1
- data/test/test_active_support.rb +0 -427
- data/test/test_cas_client.rb +0 -107
- data/test/test_compressor.rb +0 -53
- data/test/test_dalli.rb +0 -601
- data/test/test_encoding.rb +0 -32
- data/test/test_failover.rb +0 -128
- data/test/test_network.rb +0 -54
- data/test/test_rack_session.rb +0 -321
- data/test/test_ring.rb +0 -85
- data/test/test_sasl.rb +0 -110
- data/test/test_serializer.rb +0 -30
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ascii
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'dalli'
|
3
4
|
|
4
5
|
module ActiveSupport
|
@@ -8,6 +9,10 @@ module ActiveSupport
|
|
8
9
|
attr_reader :silence, :options
|
9
10
|
alias_method :silence?, :silence
|
10
11
|
|
12
|
+
def self.supports_cache_versioning?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
11
16
|
# Silence the logger.
|
12
17
|
def silence!
|
13
18
|
@silence = true
|
@@ -45,6 +50,11 @@ module ActiveSupport
|
|
45
50
|
# wish to use pool support.
|
46
51
|
#
|
47
52
|
def initialize(*addresses)
|
53
|
+
puts <<-EOS
|
54
|
+
DEPRECATION: :dalli_store will be removed in Dalli 3.0.
|
55
|
+
Please use Rails' official :mem_cache_store instead.
|
56
|
+
https://guides.rubyonrails.org/caching_with_rails.html
|
57
|
+
EOS
|
48
58
|
addresses = addresses.flatten
|
49
59
|
options = addresses.extract_options!
|
50
60
|
@options = options.dup
|
@@ -54,6 +64,8 @@ module ActiveSupport
|
|
54
64
|
pool_options[:timeout] = options[:pool_timeout] if options[:pool_timeout]
|
55
65
|
|
56
66
|
@options[:compress] ||= @options[:compression]
|
67
|
+
|
68
|
+
addresses.compact!
|
57
69
|
servers = if addresses.empty?
|
58
70
|
nil # use the default from Dalli::Client
|
59
71
|
else
|
@@ -66,6 +78,7 @@ module ActiveSupport
|
|
66
78
|
end
|
67
79
|
|
68
80
|
extend Strategy::LocalCache
|
81
|
+
extend LocalCacheEntryUnwrapAndRaw
|
69
82
|
end
|
70
83
|
|
71
84
|
##
|
@@ -79,31 +92,41 @@ module ActiveSupport
|
|
79
92
|
@data.with(&block)
|
80
93
|
end
|
81
94
|
|
95
|
+
# Fetch the value associated with the key.
|
96
|
+
# If a value is found, then it is returned.
|
97
|
+
#
|
98
|
+
# If a value is not found and no block is given, then nil is returned.
|
99
|
+
#
|
100
|
+
# If a value is not found (or if the found value is nil and :cache_nils is false)
|
101
|
+
# and a block is given, the block will be invoked and its return value
|
102
|
+
# written to the cache and returned.
|
82
103
|
def fetch(name, options=nil)
|
83
104
|
options ||= {}
|
84
|
-
|
85
|
-
|
105
|
+
options[:cache_nils] = true if @options[:cache_nils]
|
106
|
+
namespaced_name = namespaced_key(name, options)
|
107
|
+
not_found = options[:cache_nils] ? Dalli::Server::NOT_FOUND : nil
|
86
108
|
if block_given?
|
109
|
+
entry = not_found
|
87
110
|
unless options[:force]
|
88
|
-
entry =
|
89
|
-
read_entry(
|
111
|
+
entry = instrument_with_log(:read, namespaced_name, options) do |payload|
|
112
|
+
read_entry(namespaced_name, options).tap do |result|
|
90
113
|
if payload
|
91
114
|
payload[:super_operation] = :fetch
|
92
|
-
payload[:hit] =
|
115
|
+
payload[:hit] = not_found != result
|
93
116
|
end
|
94
117
|
end
|
95
118
|
end
|
96
119
|
end
|
97
120
|
|
98
|
-
if
|
99
|
-
|
100
|
-
|
101
|
-
else
|
102
|
-
result = instrument(:generate, name, options) do |payload|
|
103
|
-
yield
|
121
|
+
if not_found == entry
|
122
|
+
result = instrument_with_log(:generate, namespaced_name, options) do |payload|
|
123
|
+
yield(name)
|
104
124
|
end
|
105
125
|
write(name, result, options)
|
106
126
|
result
|
127
|
+
else
|
128
|
+
instrument_with_log(:fetch_hit, namespaced_name, options) { |payload| }
|
129
|
+
entry
|
107
130
|
end
|
108
131
|
else
|
109
132
|
read(name, options)
|
@@ -112,20 +135,20 @@ module ActiveSupport
|
|
112
135
|
|
113
136
|
def read(name, options=nil)
|
114
137
|
options ||= {}
|
115
|
-
name =
|
138
|
+
name = namespaced_key(name, options)
|
116
139
|
|
117
|
-
|
140
|
+
instrument_with_log(:read, name, options) do |payload|
|
118
141
|
entry = read_entry(name, options)
|
119
|
-
payload[:hit] =
|
142
|
+
payload[:hit] = !entry.nil? if payload
|
120
143
|
entry
|
121
144
|
end
|
122
145
|
end
|
123
146
|
|
124
147
|
def write(name, value, options=nil)
|
125
148
|
options ||= {}
|
126
|
-
name =
|
149
|
+
name = namespaced_key(name, options)
|
127
150
|
|
128
|
-
|
151
|
+
instrument_with_log(:write, name, options) do |payload|
|
129
152
|
with do |connection|
|
130
153
|
options = options.merge(:connection => connection)
|
131
154
|
write_entry(name, value, options)
|
@@ -135,7 +158,7 @@ module ActiveSupport
|
|
135
158
|
|
136
159
|
def exist?(name, options=nil)
|
137
160
|
options ||= {}
|
138
|
-
name =
|
161
|
+
name = namespaced_key(name, options)
|
139
162
|
|
140
163
|
log(:exist, name, options)
|
141
164
|
!read_entry(name, options).nil?
|
@@ -143,9 +166,9 @@ module ActiveSupport
|
|
143
166
|
|
144
167
|
def delete(name, options=nil)
|
145
168
|
options ||= {}
|
146
|
-
name =
|
169
|
+
name = namespaced_key(name, options)
|
147
170
|
|
148
|
-
|
171
|
+
instrument_with_log(:delete, name, options) do |payload|
|
149
172
|
delete_entry(name, options)
|
150
173
|
end
|
151
174
|
end
|
@@ -153,12 +176,12 @@ module ActiveSupport
|
|
153
176
|
# Reads multiple keys from the cache using a single call to the
|
154
177
|
# servers for all keys. Keys must be Strings.
|
155
178
|
def read_multi(*names)
|
156
|
-
names.extract_options!
|
157
|
-
mapping = names.inject({}) { |memo, name| memo[
|
158
|
-
|
179
|
+
options = names.extract_options!
|
180
|
+
mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
|
181
|
+
instrument_with_log(:read_multi, mapping.keys) do
|
159
182
|
results = {}
|
160
183
|
if local_cache
|
161
|
-
mapping.
|
184
|
+
mapping.each_key do |key|
|
162
185
|
if value = local_cache.read_entry(key, options)
|
163
186
|
results[key] = value
|
164
187
|
end
|
@@ -184,9 +207,9 @@ module ActiveSupport
|
|
184
207
|
# and the result will be written to the cache and returned.
|
185
208
|
def fetch_multi(*names)
|
186
209
|
options = names.extract_options!
|
187
|
-
mapping = names.inject({}) { |memo, name| memo[
|
210
|
+
mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
|
188
211
|
|
189
|
-
|
212
|
+
instrument_with_log(:fetch_multi, mapping.keys) do
|
190
213
|
with do |connection|
|
191
214
|
results = connection.get_multi(mapping.keys)
|
192
215
|
|
@@ -214,14 +237,15 @@ module ActiveSupport
|
|
214
237
|
# memcached counters cannot hold negative values.
|
215
238
|
def increment(name, amount = 1, options=nil)
|
216
239
|
options ||= {}
|
217
|
-
name =
|
240
|
+
name = namespaced_key(name, options)
|
218
241
|
initial = options.has_key?(:initial) ? options[:initial] : amount
|
219
242
|
expires_in = options[:expires_in]
|
220
|
-
|
243
|
+
instrument_with_log(:increment, name, :amount => amount) do
|
221
244
|
with { |c| c.incr(name, amount, expires_in, initial) }
|
222
245
|
end
|
223
246
|
rescue Dalli::DalliError => e
|
224
|
-
|
247
|
+
log_dalli_error(e)
|
248
|
+
instrument_error(e) if instrument_errors?
|
225
249
|
raise if raise_errors?
|
226
250
|
nil
|
227
251
|
end
|
@@ -233,14 +257,15 @@ module ActiveSupport
|
|
233
257
|
# memcached counters cannot hold negative values.
|
234
258
|
def decrement(name, amount = 1, options=nil)
|
235
259
|
options ||= {}
|
236
|
-
name =
|
260
|
+
name = namespaced_key(name, options)
|
237
261
|
initial = options.has_key?(:initial) ? options[:initial] : 0
|
238
262
|
expires_in = options[:expires_in]
|
239
|
-
|
263
|
+
instrument_with_log(:decrement, name, :amount => amount) do
|
240
264
|
with { |c| c.decr(name, amount, expires_in, initial) }
|
241
265
|
end
|
242
266
|
rescue Dalli::DalliError => e
|
243
|
-
|
267
|
+
log_dalli_error(e)
|
268
|
+
instrument_error(e) if instrument_errors?
|
244
269
|
raise if raise_errors?
|
245
270
|
nil
|
246
271
|
end
|
@@ -248,11 +273,12 @@ module ActiveSupport
|
|
248
273
|
# Clear the entire cache on all memcached servers. This method should
|
249
274
|
# be used with care when using a shared cache.
|
250
275
|
def clear(options=nil)
|
251
|
-
|
276
|
+
instrument_with_log(:clear, 'flushing all keys') do
|
252
277
|
with { |c| c.flush_all }
|
253
278
|
end
|
254
279
|
rescue Dalli::DalliError => e
|
255
|
-
|
280
|
+
log_dalli_error(e)
|
281
|
+
instrument_error(e) if instrument_errors?
|
256
282
|
raise if raise_errors?
|
257
283
|
nil
|
258
284
|
end
|
@@ -286,7 +312,8 @@ module ActiveSupport
|
|
286
312
|
# NB Backwards data compatibility, to be removed at some point
|
287
313
|
entry.is_a?(ActiveSupport::Cache::Entry) ? entry.value : entry
|
288
314
|
rescue Dalli::DalliError => e
|
289
|
-
|
315
|
+
log_dalli_error(e)
|
316
|
+
instrument_error(e) if instrument_errors?
|
290
317
|
raise if raise_errors?
|
291
318
|
nil
|
292
319
|
end
|
@@ -300,7 +327,8 @@ module ActiveSupport
|
|
300
327
|
connection = options.delete(:connection)
|
301
328
|
connection.send(method, key, value, expires_in, options)
|
302
329
|
rescue Dalli::DalliError => e
|
303
|
-
|
330
|
+
log_dalli_error(e)
|
331
|
+
instrument_error(e) if instrument_errors?
|
304
332
|
raise if raise_errors?
|
305
333
|
false
|
306
334
|
end
|
@@ -309,16 +337,31 @@ module ActiveSupport
|
|
309
337
|
def delete_entry(key, options) # :nodoc:
|
310
338
|
with { |c| c.delete(key) }
|
311
339
|
rescue Dalli::DalliError => e
|
312
|
-
|
340
|
+
log_dalli_error(e)
|
341
|
+
instrument_error(e) if instrument_errors?
|
313
342
|
raise if raise_errors?
|
314
343
|
false
|
315
344
|
end
|
316
345
|
|
317
346
|
private
|
318
|
-
|
319
|
-
|
320
|
-
|
347
|
+
|
348
|
+
def namespaced_key(key, options)
|
349
|
+
digest_class = @options[:digest_class] || ::Digest::MD5
|
350
|
+
key = expanded_key(key)
|
351
|
+
namespace = options[:namespace] if options
|
352
|
+
prefix = namespace.is_a?(Proc) ? namespace.call : namespace
|
353
|
+
key = "#{prefix}:#{key}" if prefix
|
354
|
+
key = "#{key[0, 213]}:md5:#{digest_class.hexdigest(key)}" if key && key.size > 250
|
355
|
+
key
|
356
|
+
end
|
357
|
+
alias :normalize_key :namespaced_key
|
358
|
+
|
359
|
+
# Expand key to be a consistent string value. Invokes +cache_key_with_version+
|
360
|
+
# first to support Rails 5.2 cache versioning.
|
361
|
+
# Invoke +cache_key+ if object responds to +cache_key+. Otherwise, to_param method
|
362
|
+
# will be called. If the key is a Hash, then keys will be sorted alphabetically.
|
321
363
|
def expanded_key(key) # :nodoc:
|
364
|
+
return key.cache_key_with_version.to_s if key.respond_to?(:cache_key_with_version)
|
322
365
|
return key.cache_key.to_s if key.respond_to?(:cache_key)
|
323
366
|
|
324
367
|
case key
|
@@ -340,12 +383,26 @@ module ActiveSupport
|
|
340
383
|
key
|
341
384
|
end
|
342
385
|
|
343
|
-
def
|
386
|
+
def log_dalli_error(error)
|
387
|
+
logger.error("DalliError: #{error.message}") if logger
|
388
|
+
end
|
389
|
+
|
390
|
+
def instrument_with_log(operation, key, options=nil)
|
344
391
|
log(operation, key, options)
|
345
392
|
|
346
393
|
payload = { :key => key }
|
347
394
|
payload.merge!(options) if options.is_a?(Hash)
|
348
|
-
|
395
|
+
instrument(operation, payload) { |p| yield(p) }
|
396
|
+
end
|
397
|
+
|
398
|
+
def instrument_error(error)
|
399
|
+
instrument(:error, { :key => 'DalliError', :message => error.message })
|
400
|
+
end
|
401
|
+
|
402
|
+
def instrument(operation, payload)
|
403
|
+
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) do
|
404
|
+
yield(payload) if block_given?
|
405
|
+
end
|
349
406
|
end
|
350
407
|
|
351
408
|
def log(operation, key, options=nil)
|
@@ -356,6 +413,29 @@ module ActiveSupport
|
|
356
413
|
def raise_errors?
|
357
414
|
!!@options[:raise_errors]
|
358
415
|
end
|
416
|
+
|
417
|
+
def instrument_errors?
|
418
|
+
!!@options[:instrument_errors]
|
419
|
+
end
|
420
|
+
|
421
|
+
# Make sure LocalCache is giving raw values, not `Entry`s, and
|
422
|
+
# respect `raw` option.
|
423
|
+
module LocalCacheEntryUnwrapAndRaw # :nodoc:
|
424
|
+
protected
|
425
|
+
def read_entry(key, options)
|
426
|
+
retval = super(key, **options)
|
427
|
+
if retval.is_a? ActiveSupport::Cache::Entry
|
428
|
+
# Must have come from LocalStore, unwrap it
|
429
|
+
if options[:raw]
|
430
|
+
retval.value.to_s
|
431
|
+
else
|
432
|
+
retval.value
|
433
|
+
end
|
434
|
+
else
|
435
|
+
retval
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
359
439
|
end
|
360
440
|
end
|
361
441
|
end
|
data/lib/dalli/cas/client.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'dalli/client'
|
2
3
|
|
3
4
|
module Dalli
|
@@ -33,7 +34,7 @@ module Dalli
|
|
33
34
|
|
34
35
|
##
|
35
36
|
# Set the key-value pair, verifying existing CAS.
|
36
|
-
# Returns the resulting CAS value if succeeded, and
|
37
|
+
# Returns the resulting CAS value if succeeded, and falsy otherwise.
|
37
38
|
def set_cas(key, value, cas, ttl=nil, options=nil)
|
38
39
|
ttl ||= @options[:expires_in].to_i
|
39
40
|
perform(:set, key, value, ttl, cas, options)
|
@@ -42,17 +43,17 @@ module Dalli
|
|
42
43
|
##
|
43
44
|
# Conditionally add a key/value pair, verifying existing CAS, only if the
|
44
45
|
# key already exists on the server. Returns the new CAS value if the
|
45
|
-
# operation succeeded, or
|
46
|
+
# operation succeeded, or falsy otherwise.
|
46
47
|
def replace_cas(key, value, cas, ttl=nil, options=nil)
|
47
48
|
ttl ||= @options[:expires_in].to_i
|
48
49
|
perform(:replace, key, value, ttl, cas, options)
|
49
50
|
end
|
50
51
|
|
51
52
|
# Delete a key/value pair, verifying existing CAS.
|
52
|
-
# Returns true if succeeded, and
|
53
|
+
# Returns true if succeeded, and falsy otherwise.
|
53
54
|
def delete_cas(key, cas=0)
|
54
55
|
perform(:delete, key, cas)
|
55
56
|
end
|
56
57
|
|
57
58
|
end
|
58
|
-
end
|
59
|
+
end
|