dalli 2.7.11 → 3.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/{History.md → CHANGELOG.md} +152 -0
  3. data/Gemfile +14 -8
  4. data/README.md +30 -198
  5. data/lib/dalli/cas/client.rb +1 -57
  6. data/lib/dalli/client.rb +226 -265
  7. data/lib/dalli/compressor.rb +12 -2
  8. data/lib/dalli/key_manager.rb +121 -0
  9. data/lib/dalli/options.rb +6 -7
  10. data/lib/dalli/pid_cache.rb +40 -0
  11. data/lib/dalli/pipelined_getter.rb +177 -0
  12. data/lib/dalli/protocol/base.rb +239 -0
  13. data/lib/dalli/protocol/binary/request_formatter.rb +117 -0
  14. data/lib/dalli/protocol/binary/response_header.rb +36 -0
  15. data/lib/dalli/protocol/binary/response_processor.rb +239 -0
  16. data/lib/dalli/protocol/binary/sasl_authentication.rb +60 -0
  17. data/lib/dalli/protocol/binary.rb +173 -0
  18. data/lib/dalli/protocol/connection_manager.rb +254 -0
  19. data/lib/dalli/protocol/meta/key_regularizer.rb +31 -0
  20. data/lib/dalli/protocol/meta/request_formatter.rb +121 -0
  21. data/lib/dalli/protocol/meta/response_processor.rb +211 -0
  22. data/lib/dalli/protocol/meta.rb +178 -0
  23. data/lib/dalli/protocol/response_buffer.rb +54 -0
  24. data/lib/dalli/protocol/server_config_parser.rb +86 -0
  25. data/lib/dalli/protocol/ttl_sanitizer.rb +45 -0
  26. data/lib/dalli/protocol/value_compressor.rb +85 -0
  27. data/lib/dalli/protocol/value_marshaller.rb +59 -0
  28. data/lib/dalli/protocol/value_serializer.rb +91 -0
  29. data/lib/dalli/protocol.rb +8 -0
  30. data/lib/dalli/ring.rb +94 -83
  31. data/lib/dalli/server.rb +3 -749
  32. data/lib/dalli/servers_arg_normalizer.rb +54 -0
  33. data/lib/dalli/socket.rb +117 -137
  34. data/lib/dalli/version.rb +4 -1
  35. data/lib/dalli.rb +42 -14
  36. data/lib/rack/session/dalli.rb +103 -94
  37. metadata +29 -10
  38. data/lib/action_dispatch/middleware/session/dalli_store.rb +0 -82
  39. data/lib/active_support/cache/dalli_store.rb +0 -441
  40. data/lib/dalli/railtie.rb +0 -8
@@ -1,441 +0,0 @@
1
- # encoding: ascii
2
- # frozen_string_literal: true
3
- require 'dalli'
4
-
5
- module ActiveSupport
6
- module Cache
7
- class DalliStore
8
-
9
- attr_reader :silence, :options
10
- alias_method :silence?, :silence
11
-
12
- def self.supports_cache_versioning?
13
- true
14
- end
15
-
16
- # Silence the logger.
17
- def silence!
18
- @silence = true
19
- self
20
- end
21
-
22
- # Silence the logger within a block.
23
- def mute
24
- previous_silence, @silence = defined?(@silence) && @silence, true
25
- yield
26
- ensure
27
- @silence = previous_silence
28
- end
29
-
30
- ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/
31
-
32
- # Creates a new DalliStore object, with the given memcached server
33
- # addresses. Each address is either a host name, or a host-with-port string
34
- # in the form of "host_name:port". For example:
35
- #
36
- # ActiveSupport::Cache::DalliStore.new("localhost", "server-downstairs.localnetwork:8229")
37
- #
38
- # If no addresses are specified, then DalliStore will connect to
39
- # localhost port 11211 (the default memcached port).
40
- #
41
- # Connection Pool support
42
- #
43
- # If you are using multithreaded Rails, the Rails.cache singleton can become a source
44
- # of contention. You can use a connection pool of Dalli clients with Rails.cache by
45
- # passing :pool_size and/or :pool_timeout:
46
- #
47
- # config.cache_store = :dalli_store, 'localhost:11211', :pool_size => 10
48
- #
49
- # Both pool options default to 5. You must include the `connection_pool` gem if you
50
- # wish to use pool support.
51
- #
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
58
- addresses = addresses.flatten
59
- options = addresses.extract_options!
60
- @options = options.dup
61
-
62
- pool_options = {}
63
- pool_options[:size] = options[:pool_size] if options[:pool_size]
64
- pool_options[:timeout] = options[:pool_timeout] if options[:pool_timeout]
65
-
66
- @options[:compress] ||= @options[:compression]
67
-
68
- addresses.compact!
69
- servers = if addresses.empty?
70
- nil # use the default from Dalli::Client
71
- else
72
- addresses
73
- end
74
- if pool_options.empty?
75
- @data = Dalli::Client.new(servers, @options)
76
- else
77
- @data = ::ConnectionPool.new(pool_options) { Dalli::Client.new(servers, @options.merge(:threadsafe => false)) }
78
- end
79
-
80
- extend Strategy::LocalCache
81
- extend LocalCacheEntryUnwrapAndRaw
82
- end
83
-
84
- ##
85
- # Access the underlying Dalli::Client or ConnectionPool instance for
86
- # access to get_multi, etc.
87
- def dalli
88
- @data
89
- end
90
-
91
- def with(&block)
92
- @data.with(&block)
93
- end
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.
103
- def fetch(name, options=nil)
104
- options ||= {}
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
108
- if block_given?
109
- entry = not_found
110
- unless options[:force]
111
- entry = instrument_with_log(:read, namespaced_name, options) do |payload|
112
- read_entry(namespaced_name, options).tap do |result|
113
- if payload
114
- payload[:super_operation] = :fetch
115
- payload[:hit] = not_found != result
116
- end
117
- end
118
- end
119
- end
120
-
121
- if not_found == entry
122
- result = instrument_with_log(:generate, namespaced_name, options) do |payload|
123
- yield(name)
124
- end
125
- write(name, result, options)
126
- result
127
- else
128
- instrument_with_log(:fetch_hit, namespaced_name, options) { |payload| }
129
- entry
130
- end
131
- else
132
- read(name, options)
133
- end
134
- end
135
-
136
- def read(name, options=nil)
137
- options ||= {}
138
- name = namespaced_key(name, options)
139
-
140
- instrument_with_log(:read, name, options) do |payload|
141
- entry = read_entry(name, options)
142
- payload[:hit] = !entry.nil? if payload
143
- entry
144
- end
145
- end
146
-
147
- def write(name, value, options=nil)
148
- options ||= {}
149
- name = namespaced_key(name, options)
150
-
151
- instrument_with_log(:write, name, options) do |payload|
152
- with do |connection|
153
- options = options.merge(:connection => connection)
154
- write_entry(name, value, options)
155
- end
156
- end
157
- end
158
-
159
- def exist?(name, options=nil)
160
- options ||= {}
161
- name = namespaced_key(name, options)
162
-
163
- log(:exist, name, options)
164
- !read_entry(name, options).nil?
165
- end
166
-
167
- def delete(name, options=nil)
168
- options ||= {}
169
- name = namespaced_key(name, options)
170
-
171
- instrument_with_log(:delete, name, options) do |payload|
172
- delete_entry(name, options)
173
- end
174
- end
175
-
176
- # Reads multiple keys from the cache using a single call to the
177
- # servers for all keys. Keys must be Strings.
178
- def read_multi(*names)
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
182
- results = {}
183
- if local_cache
184
- mapping.each_key do |key|
185
- if value = local_cache.read_entry(key, options)
186
- results[key] = value
187
- end
188
- end
189
- end
190
-
191
- data = with { |c| c.get_multi(mapping.keys - results.keys) }
192
- results.merge!(data)
193
- results.inject({}) do |memo, (inner, _)|
194
- entry = results[inner]
195
- # NB Backwards data compatibility, to be removed at some point
196
- value = (entry.is_a?(ActiveSupport::Cache::Entry) ? entry.value : entry)
197
- memo[mapping[inner]] = value
198
- local_cache.write_entry(inner, value, options) if local_cache
199
- memo
200
- end
201
- end
202
- end
203
-
204
- # Fetches data from the cache, using the given keys. If there is data in
205
- # the cache with the given keys, then that data is returned. Otherwise,
206
- # the supplied block is called for each key for which there was no data,
207
- # and the result will be written to the cache and returned.
208
- def fetch_multi(*names)
209
- options = names.extract_options!
210
- mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
211
-
212
- instrument_with_log(:fetch_multi, mapping.keys) do
213
- with do |connection|
214
- results = connection.get_multi(mapping.keys)
215
-
216
- connection.multi do
217
- mapping.inject({}) do |memo, (expanded, name)|
218
- memo[name] = results[expanded]
219
- if memo[name].nil?
220
- value = yield(name)
221
- memo[name] = value
222
- options = options.merge(:connection => connection)
223
- write_entry(expanded, value, options)
224
- end
225
-
226
- memo
227
- end
228
- end
229
- end
230
- end
231
- end
232
-
233
- # Increment a cached value. This method uses the memcached incr atomic
234
- # operator and can only be used on values written with the :raw option.
235
- # Calling it on a value not stored with :raw will fail.
236
- # :initial defaults to the amount passed in, as if the counter was initially zero.
237
- # memcached counters cannot hold negative values.
238
- def increment(name, amount = 1, options=nil)
239
- options ||= {}
240
- name = namespaced_key(name, options)
241
- initial = options.has_key?(:initial) ? options[:initial] : amount
242
- expires_in = options[:expires_in]
243
- instrument_with_log(:increment, name, :amount => amount) do
244
- with { |c| c.incr(name, amount, expires_in, initial) }
245
- end
246
- rescue Dalli::DalliError => e
247
- log_dalli_error(e)
248
- instrument_error(e) if instrument_errors?
249
- raise if raise_errors?
250
- nil
251
- end
252
-
253
- # Decrement a cached value. This method uses the memcached decr atomic
254
- # operator and can only be used on values written with the :raw option.
255
- # Calling it on a value not stored with :raw will fail.
256
- # :initial defaults to zero, as if the counter was initially zero.
257
- # memcached counters cannot hold negative values.
258
- def decrement(name, amount = 1, options=nil)
259
- options ||= {}
260
- name = namespaced_key(name, options)
261
- initial = options.has_key?(:initial) ? options[:initial] : 0
262
- expires_in = options[:expires_in]
263
- instrument_with_log(:decrement, name, :amount => amount) do
264
- with { |c| c.decr(name, amount, expires_in, initial) }
265
- end
266
- rescue Dalli::DalliError => e
267
- log_dalli_error(e)
268
- instrument_error(e) if instrument_errors?
269
- raise if raise_errors?
270
- nil
271
- end
272
-
273
- # Clear the entire cache on all memcached servers. This method should
274
- # be used with care when using a shared cache.
275
- def clear(options=nil)
276
- instrument_with_log(:clear, 'flushing all keys') do
277
- with { |c| c.flush_all }
278
- end
279
- rescue Dalli::DalliError => e
280
- log_dalli_error(e)
281
- instrument_error(e) if instrument_errors?
282
- raise if raise_errors?
283
- nil
284
- end
285
-
286
- # Clear any local cache
287
- def cleanup(options=nil)
288
- end
289
-
290
- # Get the statistics from the memcached servers.
291
- def stats
292
- with { |c| c.stats }
293
- end
294
-
295
- def reset
296
- with { |c| c.reset }
297
- end
298
-
299
- def logger
300
- Dalli.logger
301
- end
302
-
303
- def logger=(new_logger)
304
- Dalli.logger = new_logger
305
- end
306
-
307
- protected
308
-
309
- # Read an entry from the cache.
310
- def read_entry(key, options) # :nodoc:
311
- entry = with { |c| c.get(key, options) }
312
- # NB Backwards data compatibility, to be removed at some point
313
- entry.is_a?(ActiveSupport::Cache::Entry) ? entry.value : entry
314
- rescue Dalli::DalliError => e
315
- log_dalli_error(e)
316
- instrument_error(e) if instrument_errors?
317
- raise if raise_errors?
318
- nil
319
- end
320
-
321
- # Write an entry to the cache.
322
- def write_entry(key, value, options) # :nodoc:
323
- # cleanup LocalCache
324
- cleanup if options[:unless_exist]
325
- method = options[:unless_exist] ? :add : :set
326
- expires_in = options[:expires_in]
327
- connection = options.delete(:connection)
328
- connection.send(method, key, value, expires_in, options)
329
- rescue Dalli::DalliError => e
330
- log_dalli_error(e)
331
- instrument_error(e) if instrument_errors?
332
- raise if raise_errors?
333
- false
334
- end
335
-
336
- # Delete an entry from the cache.
337
- def delete_entry(key, options) # :nodoc:
338
- with { |c| c.delete(key) }
339
- rescue Dalli::DalliError => e
340
- log_dalli_error(e)
341
- instrument_error(e) if instrument_errors?
342
- raise if raise_errors?
343
- false
344
- end
345
-
346
- private
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.
363
- def expanded_key(key) # :nodoc:
364
- return key.cache_key_with_version.to_s if key.respond_to?(:cache_key_with_version)
365
- return key.cache_key.to_s if key.respond_to?(:cache_key)
366
-
367
- case key
368
- when Array
369
- if key.size > 1
370
- key = key.collect{|element| expanded_key(element)}
371
- else
372
- key = key.first
373
- end
374
- when Hash
375
- key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"}
376
- end
377
-
378
- key = key.to_param
379
- if key.respond_to? :force_encoding
380
- key = key.dup
381
- key.force_encoding('binary')
382
- end
383
- key
384
- end
385
-
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)
391
- log(operation, key, options)
392
-
393
- payload = { :key => key }
394
- payload.merge!(options) if options.is_a?(Hash)
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
406
- end
407
-
408
- def log(operation, key, options=nil)
409
- return unless logger && logger.debug? && !silence?
410
- logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}")
411
- end
412
-
413
- def raise_errors?
414
- !!@options[:raise_errors]
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
439
- end
440
- end
441
- end
data/lib/dalli/railtie.rb DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
- module Dalli
3
- class Railtie < ::Rails::Railtie
4
- config.before_configuration do
5
- config.cache_store = :dalli_store
6
- end
7
- end
8
- end