dalli 2.7.8 → 3.2.1

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.

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