dalli 2.7.6 → 3.2.2

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