dalli 2.7.4 → 2.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dalli might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/Gemfile +0 -7
 - data/History.md +15 -0
 - data/LICENSE +1 -1
 - data/README.md +14 -6
 - data/lib/active_support/cache/dalli_store.rb +39 -9
 - data/lib/dalli/client.rb +40 -27
 - data/lib/dalli/server.rb +33 -18
 - data/lib/dalli/socket.rb +14 -4
 - data/lib/dalli/version.rb +1 -1
 - metadata +79 -43
 - data/Performance.md +0 -42
 - data/Rakefile +0 -43
 - data/dalli.gemspec +0 -29
 - data/test/benchmark_test.rb +0 -243
 - data/test/helper.rb +0 -56
 - data/test/memcached_mock.rb +0 -201
 - data/test/sasl/memcached.conf +0 -1
 - data/test/sasl/sasldb +0 -1
 - data/test/test_active_support.rb +0 -541
 - data/test/test_cas_client.rb +0 -107
 - data/test/test_compressor.rb +0 -52
 - data/test/test_dalli.rb +0 -682
 - data/test/test_encoding.rb +0 -32
 - data/test/test_failover.rb +0 -137
 - data/test/test_network.rb +0 -64
 - data/test/test_rack_session.rb +0 -341
 - data/test/test_ring.rb +0 -85
 - data/test/test_sasl.rb +0 -105
 - data/test/test_serializer.rb +0 -29
 - data/test/test_server.rb +0 -110
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 29b86664473df52d0ca07fbf21015a39260962a1
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 5061af271bef6e1db864d5e6de4f9464412e0c67
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 7ccec720347f06a142f74d1a500948390f0dcd3520c73922363267c393d99067cb3682f4c2577cc2cbbd99a18a93f800041eaec7570303c73d5e7ab451b9396e
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a68483e89e28c82d52852d73c921aa40578abad55a2f3ec9106b01f1fd5dfc6f98104e9b2f8ab0006306685a4b3ecafca3d768ebf81223c213171482ee00d1f1
         
     | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/History.md
    CHANGED
    
    | 
         @@ -1,6 +1,21 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Dalli Changelog
         
     | 
| 
       2 
2 
     | 
    
         
             
            =====================
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
      
 4 
     | 
    
         
            +
            2.7.5
         
     | 
| 
      
 5 
     | 
    
         
            +
            ==========
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            - Support rcvbuff and sndbuff byte configuration. (btatnall)
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Add `:cache_nils` option to support nil values in `DalliStore#fetch` and `Dalli::Client#fetch` (wjordan, #559)
         
     | 
| 
      
 9 
     | 
    
         
            +
            - Log retryable server errors with 'warn' instead of 'info' (phrinx)
         
     | 
| 
      
 10 
     | 
    
         
            +
            - Fix timeout issue with Dalli::Client#get_multi_yielder (dspeterson)
         
     | 
| 
      
 11 
     | 
    
         
            +
            - Escape namespaces with special regexp characters (Steven Peckins)
         
     | 
| 
      
 12 
     | 
    
         
            +
            - Ensure LocalCache supports the `:raw` option and Entry unwrapping (sj26)
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Ensure bad ttl values don't cause Dalli::RingError (eagletmt, petergoldstein)
         
     | 
| 
      
 14 
     | 
    
         
            +
            - Always pass namespaced key to instrumentation API (kaorimatz)
         
     | 
| 
      
 15 
     | 
    
         
            +
            - Replace use of deprecated TimeoutError with Timeout::Error (eagletmt)
         
     | 
| 
      
 16 
     | 
    
         
            +
            - Clean up gemspec, and use Bundler for loading (grosser)
         
     | 
| 
      
 17 
     | 
    
         
            +
            - Dry up local cache testing (grosser)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       4 
19 
     | 
    
         
             
            2.7.4
         
     | 
| 
       5 
20 
     | 
    
         
             
            ==========
         
     | 
| 
       6 
21 
     | 
    
         | 
    
        data/LICENSE
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            Dalli [](http://travis-ci.org/petergoldstein/dalli) [](https://gemnasium.com/petergoldstein/dalli) [](https://codeclimate.com/github/petergoldstein/dalli)
         
     | 
| 
       2 
2 
     | 
    
         
             
            =====
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            Dalli is a high performance pure Ruby client for accessing memcached servers.  It works with memcached 1.4+ only as it uses the newer binary protocol.  It should be considered a replacement for the memcache-client gem.
         
     | 
| 
         @@ -13,7 +13,7 @@ Dalli's initial development was sponsored by [CouchBase](http://www.couchbase.co 
     | 
|
| 
       13 
13 
     | 
    
         
             
            Design
         
     | 
| 
       14 
14 
     | 
    
         
             
            ------------
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
            Mike Perham decided to write Dalli after maintaining memcache-client for two years for a few specific reasons:
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
             0. The code is mostly old and gross.  The bulk of the code is a single 1000 line .rb file.
         
     | 
| 
       19 
19 
     | 
    
         
             
             1. It has a lot of options that are infrequently used which complicate the codebase.
         
     | 
| 
         @@ -186,6 +186,12 @@ If serving compressed data using nginx's HttpMemcachedModule, set `memcached_gzi 
     | 
|
| 
       186 
186 
     | 
    
         | 
| 
       187 
187 
     | 
    
         
             
            **password**: The password to use for authenticating this client instance against a SASL-enabled memcached server.  Heroku users should not need to use this normally.
         
     | 
| 
       188 
188 
     | 
    
         | 
| 
      
 189 
     | 
    
         
            +
            **sndbuf**: In bytes, set the socket SO_SNDBUF. Defaults to operating system default.
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
            **rcvbuf**: In bytes, set the socket SO_RCVBUF. Defaults to operating system default.
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
            **cache_nils**: Boolean. If true Dalli will not treat cached `nil` values as 'not found' for `#fetch` operations. Default is false.
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
       189 
195 
     | 
    
         
             
            Features and Changes
         
     | 
| 
       190 
196 
     | 
    
         
             
            ------------------------
         
     | 
| 
       191 
197 
     | 
    
         | 
| 
         @@ -209,20 +215,22 @@ We're not accepting new compressors. They are trivial to add in an initializer. 
     | 
|
| 
       209 
215 
     | 
    
         
             
            Thanks
         
     | 
| 
       210 
216 
     | 
    
         
             
            ------------
         
     | 
| 
       211 
217 
     | 
    
         | 
| 
      
 218 
     | 
    
         
            +
            Mike Perham - for originally authoring the Dalli project and serving as maintainer and primary contributor
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
       212 
220 
     | 
    
         
             
            Eric Wong - for help using his [kgio](http://bogomips.org/kgio/) library.
         
     | 
| 
       213 
221 
     | 
    
         | 
| 
       214 
222 
     | 
    
         
             
            Brian Mitchell - for his remix-stash project which was helpful when implementing and testing the binary protocol support.
         
     | 
| 
       215 
223 
     | 
    
         | 
| 
       216 
224 
     | 
    
         
             
            [CouchBase](http://couchbase.com) - for their project sponsorship
         
     | 
| 
       217 
225 
     | 
    
         | 
| 
       218 
     | 
    
         
            -
             
     | 
| 
       219 
     | 
    
         
            -
            Author
         
     | 
| 
      
 226 
     | 
    
         
            +
            Authors
         
     | 
| 
       220 
227 
     | 
    
         
             
            ----------
         
     | 
| 
       221 
228 
     | 
    
         | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
      
 229 
     | 
    
         
            +
            * [Peter M. Goldstein](https://github.com/petergoldstein) - current maintainer
         
     | 
| 
      
 230 
     | 
    
         
            +
            * [Mike Perham](https://github.com/mperham) and contributors
         
     | 
| 
       223 
231 
     | 
    
         | 
| 
       224 
232 
     | 
    
         | 
| 
       225 
233 
     | 
    
         
             
            Copyright
         
     | 
| 
       226 
234 
     | 
    
         
             
            -----------
         
     | 
| 
       227 
235 
     | 
    
         | 
| 
       228 
     | 
    
         
            -
            Copyright (c) Mike Perham. See LICENSE for details.
         
     | 
| 
      
 236 
     | 
    
         
            +
            Copyright (c) Mike Perham, Peter M. Goldstein. See LICENSE for details.
         
     | 
| 
         @@ -68,6 +68,7 @@ module ActiveSupport 
     | 
|
| 
       68 
68 
     | 
    
         
             
                    end
         
     | 
| 
       69 
69 
     | 
    
         | 
| 
       70 
70 
     | 
    
         
             
                    extend Strategy::LocalCache
         
     | 
| 
      
 71 
     | 
    
         
            +
                    extend LocalCacheEntryUnwrapAndRaw
         
     | 
| 
       71 
72 
     | 
    
         
             
                  end
         
     | 
| 
       72 
73 
     | 
    
         | 
| 
       73 
74 
     | 
    
         
             
                  ##
         
     | 
| 
         @@ -81,31 +82,41 @@ module ActiveSupport 
     | 
|
| 
       81 
82 
     | 
    
         
             
                    @data.with(&block)
         
     | 
| 
       82 
83 
     | 
    
         
             
                  end
         
     | 
| 
       83 
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.
         
     | 
| 
       84 
93 
     | 
    
         
             
                  def fetch(name, options=nil)
         
     | 
| 
       85 
94 
     | 
    
         
             
                    options ||= {}
         
     | 
| 
      
 95 
     | 
    
         
            +
                    options[:cache_nils] = true if @options[:cache_nils]
         
     | 
| 
       86 
96 
     | 
    
         
             
                    namespaced_name = namespaced_key(name, options)
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
      
 97 
     | 
    
         
            +
                    not_found = options[:cache_nils] ? Dalli::Server::NOT_FOUND : nil
         
     | 
| 
       88 
98 
     | 
    
         
             
                    if block_given?
         
     | 
| 
      
 99 
     | 
    
         
            +
                      entry = not_found
         
     | 
| 
       89 
100 
     | 
    
         
             
                      unless options[:force]
         
     | 
| 
       90 
101 
     | 
    
         
             
                        entry = instrument(:read, namespaced_name, options) do |payload|
         
     | 
| 
       91 
102 
     | 
    
         
             
                          read_entry(namespaced_name, options).tap do |result|
         
     | 
| 
       92 
103 
     | 
    
         
             
                            if payload
         
     | 
| 
       93 
104 
     | 
    
         
             
                              payload[:super_operation] = :fetch
         
     | 
| 
       94 
     | 
    
         
            -
                              payload[:hit] =  
     | 
| 
      
 105 
     | 
    
         
            +
                              payload[:hit] = result != not_found
         
     | 
| 
       95 
106 
     | 
    
         
             
                            end
         
     | 
| 
       96 
107 
     | 
    
         
             
                          end
         
     | 
| 
       97 
108 
     | 
    
         
             
                        end
         
     | 
| 
       98 
109 
     | 
    
         
             
                      end
         
     | 
| 
       99 
110 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
                      if  
     | 
| 
       101 
     | 
    
         
            -
                        instrument(: 
     | 
| 
       102 
     | 
    
         
            -
                        entry
         
     | 
| 
       103 
     | 
    
         
            -
                      else
         
     | 
| 
       104 
     | 
    
         
            -
                        result = instrument(:generate, name, options) do |payload|
         
     | 
| 
      
 111 
     | 
    
         
            +
                      if entry == not_found
         
     | 
| 
      
 112 
     | 
    
         
            +
                        result = instrument(:generate, namespaced_name, options) do |payload|
         
     | 
| 
       105 
113 
     | 
    
         
             
                          yield
         
     | 
| 
       106 
114 
     | 
    
         
             
                        end
         
     | 
| 
       107 
115 
     | 
    
         
             
                        write(name, result, options)
         
     | 
| 
       108 
116 
     | 
    
         
             
                        result
         
     | 
| 
      
 117 
     | 
    
         
            +
                      else
         
     | 
| 
      
 118 
     | 
    
         
            +
                        instrument(:fetch_hit, namespaced_name, options) { |payload| }
         
     | 
| 
      
 119 
     | 
    
         
            +
                        entry
         
     | 
| 
       109 
120 
     | 
    
         
             
                      end
         
     | 
| 
       110 
121 
     | 
    
         
             
                    else
         
     | 
| 
       111 
122 
     | 
    
         
             
                      read(name, options)
         
     | 
| 
         @@ -157,7 +168,7 @@ module ActiveSupport 
     | 
|
| 
       157 
168 
     | 
    
         
             
                  def read_multi(*names)
         
     | 
| 
       158 
169 
     | 
    
         
             
                    options  = names.extract_options!
         
     | 
| 
       159 
170 
     | 
    
         
             
                    mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
         
     | 
| 
       160 
     | 
    
         
            -
                    instrument(:read_multi,  
     | 
| 
      
 171 
     | 
    
         
            +
                    instrument(:read_multi, mapping.keys) do
         
     | 
| 
       161 
172 
     | 
    
         
             
                      results = {}
         
     | 
| 
       162 
173 
     | 
    
         
             
                      if local_cache
         
     | 
| 
       163 
174 
     | 
    
         
             
                        mapping.each_key do |key|
         
     | 
| 
         @@ -188,7 +199,7 @@ module ActiveSupport 
     | 
|
| 
       188 
199 
     | 
    
         
             
                    options = names.extract_options!
         
     | 
| 
       189 
200 
     | 
    
         
             
                    mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
         
     | 
| 
       190 
201 
     | 
    
         | 
| 
       191 
     | 
    
         
            -
                    instrument(:fetch_multi,  
     | 
| 
      
 202 
     | 
    
         
            +
                    instrument(:fetch_multi, mapping.keys) do
         
     | 
| 
       192 
203 
     | 
    
         
             
                      with do |connection|
         
     | 
| 
       193 
204 
     | 
    
         
             
                        results = connection.get_multi(mapping.keys)
         
     | 
| 
       194 
205 
     | 
    
         | 
| 
         @@ -367,6 +378,25 @@ module ActiveSupport 
     | 
|
| 
       367 
378 
     | 
    
         
             
                  def raise_errors?
         
     | 
| 
       368 
379 
     | 
    
         
             
                    !!@options[:raise_errors]
         
     | 
| 
       369 
380 
     | 
    
         
             
                  end
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
                  # Make sure LocalCache is giving raw values, not `Entry`s, and
         
     | 
| 
      
 383 
     | 
    
         
            +
                  # respect `raw` option.
         
     | 
| 
      
 384 
     | 
    
         
            +
                  module LocalCacheEntryUnwrapAndRaw # :nodoc:
         
     | 
| 
      
 385 
     | 
    
         
            +
                    protected
         
     | 
| 
      
 386 
     | 
    
         
            +
                      def read_entry(key, options)
         
     | 
| 
      
 387 
     | 
    
         
            +
                        retval = super
         
     | 
| 
      
 388 
     | 
    
         
            +
                        if retval.is_a? ActiveSupport::Cache::Entry
         
     | 
| 
      
 389 
     | 
    
         
            +
                          # Must have come from LocalStore, unwrap it
         
     | 
| 
      
 390 
     | 
    
         
            +
                          if options[:raw]
         
     | 
| 
      
 391 
     | 
    
         
            +
                            retval.value.to_s
         
     | 
| 
      
 392 
     | 
    
         
            +
                          else
         
     | 
| 
      
 393 
     | 
    
         
            +
                            retval.value
         
     | 
| 
      
 394 
     | 
    
         
            +
                          end
         
     | 
| 
      
 395 
     | 
    
         
            +
                        else
         
     | 
| 
      
 396 
     | 
    
         
            +
                          retval
         
     | 
| 
      
 397 
     | 
    
         
            +
                        end
         
     | 
| 
      
 398 
     | 
    
         
            +
                      end
         
     | 
| 
      
 399 
     | 
    
         
            +
                  end
         
     | 
| 
       370 
400 
     | 
    
         
             
                end
         
     | 
| 
       371 
401 
     | 
    
         
             
              end
         
     | 
| 
       372 
402 
     | 
    
         
             
            end
         
     | 
    
        data/lib/dalli/client.rb
    CHANGED
    
    | 
         @@ -27,6 +27,7 @@ module Dalli 
     | 
|
| 
       27 
27 
     | 
    
         
             
                # - :compress - defaults to false, if true Dalli will compress values larger than 1024 bytes before sending them to memcached.
         
     | 
| 
       28 
28 
     | 
    
         
             
                # - :serializer - defaults to Marshal
         
     | 
| 
       29 
29 
     | 
    
         
             
                # - :compressor - defaults to zlib
         
     | 
| 
      
 30 
     | 
    
         
            +
                # - :cache_nils - defaults to false, if true Dalli will not treat cached nil values as 'not found' for #fetch operations.
         
     | 
| 
       30 
31 
     | 
    
         
             
                #
         
     | 
| 
       31 
32 
     | 
    
         
             
                def initialize(servers=nil, options={})
         
     | 
| 
       32 
33 
     | 
    
         
             
                  @servers = normalize_servers(servers || ENV["MEMCACHE_SERVERS"] || '127.0.0.1:11211')
         
     | 
| 
         @@ -52,8 +53,9 @@ module Dalli 
     | 
|
| 
       52 
53 
     | 
    
         | 
| 
       53 
54 
     | 
    
         
             
                ##
         
     | 
| 
       54 
55 
     | 
    
         
             
                # Get the value associated with the key.
         
     | 
| 
      
 56 
     | 
    
         
            +
                # If a value is not found, then +nil+ is returned.
         
     | 
| 
       55 
57 
     | 
    
         
             
                def get(key, options=nil)
         
     | 
| 
       56 
     | 
    
         
            -
                  perform(:get, key)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  perform(:get, key, options)
         
     | 
| 
       57 
59 
     | 
    
         
             
                end
         
     | 
| 
       58 
60 
     | 
    
         | 
| 
       59 
61 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -71,12 +73,25 @@ module Dalli 
     | 
|
| 
       71 
73 
     | 
    
         
             
                  end
         
     | 
| 
       72 
74 
     | 
    
         
             
                end
         
     | 
| 
       73 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                CACHE_NILS = {cache_nils: true}.freeze
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                # Fetch the value associated with the key.
         
     | 
| 
      
 79 
     | 
    
         
            +
                # If a value is found, then it is returned.
         
     | 
| 
      
 80 
     | 
    
         
            +
                #
         
     | 
| 
      
 81 
     | 
    
         
            +
                # If a value is not found and no block is given, then nil is returned.
         
     | 
| 
      
 82 
     | 
    
         
            +
                #
         
     | 
| 
      
 83 
     | 
    
         
            +
                # If a value is not found (or if the found value is nil and :cache_nils is false)
         
     | 
| 
      
 84 
     | 
    
         
            +
                # and a block is given, the block will be invoked and its return value
         
     | 
| 
      
 85 
     | 
    
         
            +
                # written to the cache and returned.
         
     | 
| 
       74 
86 
     | 
    
         
             
                def fetch(key, ttl=nil, options=nil)
         
     | 
| 
       75 
     | 
    
         
            -
                   
     | 
| 
      
 87 
     | 
    
         
            +
                  options = options.nil? ? CACHE_NILS : options.merge(CACHE_NILS) if @options[:cache_nils]
         
     | 
| 
       76 
88 
     | 
    
         
             
                  val = get(key, options)
         
     | 
| 
       77 
     | 
    
         
            -
                   
     | 
| 
      
 89 
     | 
    
         
            +
                  not_found = @options[:cache_nils] ?
         
     | 
| 
      
 90 
     | 
    
         
            +
                    val == Dalli::Server::NOT_FOUND :
         
     | 
| 
      
 91 
     | 
    
         
            +
                    val.nil?
         
     | 
| 
      
 92 
     | 
    
         
            +
                  if not_found && block_given?
         
     | 
| 
       78 
93 
     | 
    
         
             
                    val = yield
         
     | 
| 
       79 
     | 
    
         
            -
                    add(key, val, ttl, options)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    add(key, val, ttl_or_default(ttl), options)
         
     | 
| 
       80 
95 
     | 
    
         
             
                  end
         
     | 
| 
       81 
96 
     | 
    
         
             
                  val
         
     | 
| 
       82 
97 
     | 
    
         
             
                end
         
     | 
| 
         @@ -93,34 +108,30 @@ module Dalli 
     | 
|
| 
       93 
108 
     | 
    
         
             
                # - false if the value was changed by someone else.
         
     | 
| 
       94 
109 
     | 
    
         
             
                # - true if the value was successfully updated.
         
     | 
| 
       95 
110 
     | 
    
         
             
                def cas(key, ttl=nil, options=nil)
         
     | 
| 
       96 
     | 
    
         
            -
                  ttl ||= @options[:expires_in].to_i
         
     | 
| 
       97 
111 
     | 
    
         
             
                  (value, cas) = perform(:cas, key)
         
     | 
| 
       98 
112 
     | 
    
         
             
                  value = (!value || value == 'Not found') ? nil : value
         
     | 
| 
       99 
113 
     | 
    
         
             
                  if value
         
     | 
| 
       100 
114 
     | 
    
         
             
                    newvalue = yield(value)
         
     | 
| 
       101 
     | 
    
         
            -
                    perform(:set, key, newvalue, ttl, cas, options)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    perform(:set, key, newvalue, ttl_or_default(ttl), cas, options)
         
     | 
| 
       102 
116 
     | 
    
         
             
                  end
         
     | 
| 
       103 
117 
     | 
    
         
             
                end
         
     | 
| 
       104 
118 
     | 
    
         | 
| 
       105 
119 
     | 
    
         
             
                def set(key, value, ttl=nil, options=nil)
         
     | 
| 
       106 
     | 
    
         
            -
                  ttl  
     | 
| 
       107 
     | 
    
         
            -
                  perform(:set, key, value, ttl, 0, options)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  perform(:set, key, value, ttl_or_default(ttl), 0, options)
         
     | 
| 
       108 
121 
     | 
    
         
             
                end
         
     | 
| 
       109 
122 
     | 
    
         | 
| 
       110 
123 
     | 
    
         
             
                ##
         
     | 
| 
       111 
124 
     | 
    
         
             
                # Conditionally add a key/value pair, if the key does not already exist
         
     | 
| 
       112 
125 
     | 
    
         
             
                # on the server.  Returns truthy if the operation succeeded.
         
     | 
| 
       113 
126 
     | 
    
         
             
                def add(key, value, ttl=nil, options=nil)
         
     | 
| 
       114 
     | 
    
         
            -
                  ttl  
     | 
| 
       115 
     | 
    
         
            -
                  perform(:add, key, value, ttl, options)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  perform(:add, key, value, ttl_or_default(ttl), options)
         
     | 
| 
       116 
128 
     | 
    
         
             
                end
         
     | 
| 
       117 
129 
     | 
    
         | 
| 
       118 
130 
     | 
    
         
             
                ##
         
     | 
| 
       119 
131 
     | 
    
         
             
                # Conditionally add a key/value pair, only if the key already exists
         
     | 
| 
       120 
132 
     | 
    
         
             
                # on the server.  Returns truthy if the operation succeeded.
         
     | 
| 
       121 
133 
     | 
    
         
             
                def replace(key, value, ttl=nil, options=nil)
         
     | 
| 
       122 
     | 
    
         
            -
                  ttl  
     | 
| 
       123 
     | 
    
         
            -
                  perform(:replace, key, value, ttl, 0, options)
         
     | 
| 
      
 134 
     | 
    
         
            +
                  perform(:replace, key, value, ttl_or_default(ttl), 0, options)
         
     | 
| 
       124 
135 
     | 
    
         
             
                end
         
     | 
| 
       125 
136 
     | 
    
         | 
| 
       126 
137 
     | 
    
         
             
                def delete(key)
         
     | 
| 
         @@ -161,8 +172,7 @@ module Dalli 
     | 
|
| 
       161 
172 
     | 
    
         
             
                # #cas.
         
     | 
| 
       162 
173 
     | 
    
         
             
                def incr(key, amt=1, ttl=nil, default=nil)
         
     | 
| 
       163 
174 
     | 
    
         
             
                  raise ArgumentError, "Positive values only: #{amt}" if amt < 0
         
     | 
| 
       164 
     | 
    
         
            -
                   
     | 
| 
       165 
     | 
    
         
            -
                  perform(:incr, key, amt.to_i, ttl, default)
         
     | 
| 
      
 175 
     | 
    
         
            +
                  perform(:incr, key, amt.to_i, ttl_or_default(ttl), default)
         
     | 
| 
       166 
176 
     | 
    
         
             
                end
         
     | 
| 
       167 
177 
     | 
    
         | 
| 
       168 
178 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -181,8 +191,7 @@ module Dalli 
     | 
|
| 
       181 
191 
     | 
    
         
             
                # #cas.
         
     | 
| 
       182 
192 
     | 
    
         
             
                def decr(key, amt=1, ttl=nil, default=nil)
         
     | 
| 
       183 
193 
     | 
    
         
             
                  raise ArgumentError, "Positive values only: #{amt}" if amt < 0
         
     | 
| 
       184 
     | 
    
         
            -
                   
     | 
| 
       185 
     | 
    
         
            -
                  perform(:decr, key, amt.to_i, ttl, default)
         
     | 
| 
      
 194 
     | 
    
         
            +
                  perform(:decr, key, amt.to_i, ttl_or_default(ttl), default)
         
     | 
| 
       186 
195 
     | 
    
         
             
                end
         
     | 
| 
       187 
196 
     | 
    
         | 
| 
       188 
197 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -190,8 +199,7 @@ module Dalli 
     | 
|
| 
       190 
199 
     | 
    
         
             
                #
         
     | 
| 
       191 
200 
     | 
    
         
             
                # Returns true if key exists, otherwise nil.
         
     | 
| 
       192 
201 
     | 
    
         
             
                def touch(key, ttl=nil)
         
     | 
| 
       193 
     | 
    
         
            -
                   
     | 
| 
       194 
     | 
    
         
            -
                  resp = perform(:touch, key, ttl)
         
     | 
| 
      
 202 
     | 
    
         
            +
                  resp = perform(:touch, key, ttl_or_default(ttl))
         
     | 
| 
       195 
203 
     | 
    
         
             
                  resp.nil? ? nil : true
         
     | 
| 
       196 
204 
     | 
    
         
             
                end
         
     | 
| 
       197 
205 
     | 
    
         | 
| 
         @@ -250,6 +258,12 @@ module Dalli 
     | 
|
| 
       250 
258 
     | 
    
         | 
| 
       251 
259 
     | 
    
         
             
                private
         
     | 
| 
       252 
260 
     | 
    
         | 
| 
      
 261 
     | 
    
         
            +
                def ttl_or_default(ttl)
         
     | 
| 
      
 262 
     | 
    
         
            +
                  (ttl || @options[:expires_in]).to_i
         
     | 
| 
      
 263 
     | 
    
         
            +
                rescue NoMethodError
         
     | 
| 
      
 264 
     | 
    
         
            +
                  raise ArgumentError, "Cannot convert ttl (#{ttl}) to an integer"
         
     | 
| 
      
 265 
     | 
    
         
            +
                end
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
       253 
267 
     | 
    
         
             
                def groups_for_keys(*keys)
         
     | 
| 
       254 
268 
     | 
    
         
             
                  groups = mapped_keys(keys).flatten.group_by do |key|
         
     | 
| 
       255 
269 
     | 
    
         
             
                    begin
         
     | 
| 
         @@ -296,8 +310,9 @@ module Dalli 
     | 
|
| 
       296 
310 
     | 
    
         
             
                end
         
     | 
| 
       297 
311 
     | 
    
         | 
| 
       298 
312 
     | 
    
         
             
                ##
         
     | 
| 
       299 
     | 
    
         
            -
                # Normalizes the argument into an array of servers. 
     | 
| 
       300 
     | 
    
         
            -
                # the  
     | 
| 
      
 313 
     | 
    
         
            +
                # Normalizes the argument into an array of servers.
         
     | 
| 
      
 314 
     | 
    
         
            +
                # If the argument is a string, it's expected that the URIs are comma separated e.g.
         
     | 
| 
      
 315 
     | 
    
         
            +
                # "memcache1.example.com:11211,memcache2.example.com:11211,memcache3.example.com:11211"
         
     | 
| 
       301 
316 
     | 
    
         
             
                def normalize_servers(servers)
         
     | 
| 
       302 
317 
     | 
    
         
             
                  if servers.is_a? String
         
     | 
| 
       303 
318 
     | 
    
         
             
                    return servers.split(",")
         
     | 
| 
         @@ -354,7 +369,7 @@ module Dalli 
     | 
|
| 
       354 
369 
     | 
    
         
             
                end
         
     | 
| 
       355 
370 
     | 
    
         | 
| 
       356 
371 
     | 
    
         
             
                def key_without_namespace(key)
         
     | 
| 
       357 
     | 
    
         
            -
                  (ns = namespace) ? key.sub(%r(\A#{ns}:), '') : key
         
     | 
| 
      
 372 
     | 
    
         
            +
                  (ns = namespace) ? key.sub(%r(\A#{Regexp.escape ns}:), '') : key
         
     | 
| 
       358 
373 
     | 
    
         
             
                end
         
     | 
| 
       359 
374 
     | 
    
         | 
| 
       360 
375 
     | 
    
         
             
                def namespace
         
     | 
| 
         @@ -401,12 +416,10 @@ module Dalli 
     | 
|
| 
       401 
416 
     | 
    
         
             
                          # calculate remaining timeout
         
     | 
| 
       402 
417 
     | 
    
         
             
                          elapsed = Time.now - start
         
     | 
| 
       403 
418 
     | 
    
         
             
                          timeout = servers.first.options[:socket_timeout]
         
     | 
| 
       404 
     | 
    
         
            -
                           
     | 
| 
       405 
     | 
    
         
            -
             
     | 
| 
       406 
     | 
    
         
            -
                           
     | 
| 
       407 
     | 
    
         
            -
             
     | 
| 
       408 
     | 
    
         
            -
                            readable, _ = IO.select(sockets, nil, nil, timeout - elapsed)
         
     | 
| 
       409 
     | 
    
         
            -
                          end
         
     | 
| 
      
 419 
     | 
    
         
            +
                          time_left = (elapsed > timeout) ? 0 : timeout - elapsed
         
     | 
| 
      
 420 
     | 
    
         
            +
             
     | 
| 
      
 421 
     | 
    
         
            +
                          sockets = servers.map(&:sock)
         
     | 
| 
      
 422 
     | 
    
         
            +
                          readable, _ = IO.select(sockets, nil, nil, time_left)
         
     | 
| 
       410 
423 
     | 
    
         | 
| 
       411 
424 
     | 
    
         
             
                          if readable.nil?
         
     | 
| 
       412 
425 
     | 
    
         
             
                            # no response within timeout; abort pending connections
         
     | 
    
        data/lib/dalli/server.rb
    CHANGED
    
    | 
         @@ -31,7 +31,11 @@ module Dalli 
     | 
|
| 
       31 
31 
     | 
    
         
             
                  :serializer => Marshal,
         
     | 
| 
       32 
32 
     | 
    
         
             
                  :username => nil,
         
     | 
| 
       33 
33 
     | 
    
         
             
                  :password => nil,
         
     | 
| 
       34 
     | 
    
         
            -
                  :keepalive => true
         
     | 
| 
      
 34 
     | 
    
         
            +
                  :keepalive => true,
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # max byte size for SO_SNDBUF
         
     | 
| 
      
 36 
     | 
    
         
            +
                  :sndbuf => nil,
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # max byte size for SO_RCVBUF
         
     | 
| 
      
 38 
     | 
    
         
            +
                  :rcvbuf => nil
         
     | 
| 
       35 
39 
     | 
    
         
             
                }
         
     | 
| 
       36 
40 
     | 
    
         | 
| 
       37 
41 
     | 
    
         
             
                def initialize(attribs, options = {})
         
     | 
| 
         @@ -203,20 +207,28 @@ module Dalli 
     | 
|
| 
       203 
207 
     | 
    
         | 
| 
       204 
208 
     | 
    
         
             
                def verify_state
         
     | 
| 
       205 
209 
     | 
    
         
             
                  failure!(RuntimeError.new('Already writing to socket')) if @inprogress
         
     | 
| 
       206 
     | 
    
         
            -
                   
     | 
| 
      
 210 
     | 
    
         
            +
                  if @pid && @pid != Process.pid
         
     | 
| 
      
 211 
     | 
    
         
            +
                    message = 'Fork detected, re-connecting child process...'
         
     | 
| 
      
 212 
     | 
    
         
            +
                    Dalli.logger.info { message }
         
     | 
| 
      
 213 
     | 
    
         
            +
                    reconnect! message
         
     | 
| 
      
 214 
     | 
    
         
            +
                  end
         
     | 
| 
      
 215 
     | 
    
         
            +
                end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                def reconnect!(message)
         
     | 
| 
      
 218 
     | 
    
         
            +
                  close
         
     | 
| 
      
 219 
     | 
    
         
            +
                  sleep(options[:socket_failure_delay]) if options[:socket_failure_delay]
         
     | 
| 
      
 220 
     | 
    
         
            +
                  raise Dalli::NetworkError, message
         
     | 
| 
       207 
221 
     | 
    
         
             
                end
         
     | 
| 
       208 
222 
     | 
    
         | 
| 
       209 
223 
     | 
    
         
             
                def failure!(exception)
         
     | 
| 
       210 
224 
     | 
    
         
             
                  message = "#{name} failed (count: #{@fail_count}) #{exception.class}: #{exception.message}"
         
     | 
| 
       211 
     | 
    
         
            -
                  Dalli.logger. 
     | 
| 
      
 225 
     | 
    
         
            +
                  Dalli.logger.warn { message }
         
     | 
| 
       212 
226 
     | 
    
         | 
| 
       213 
227 
     | 
    
         
             
                  @fail_count += 1
         
     | 
| 
       214 
228 
     | 
    
         
             
                  if @fail_count >= options[:socket_max_failures]
         
     | 
| 
       215 
229 
     | 
    
         
             
                    down!
         
     | 
| 
       216 
230 
     | 
    
         
             
                  else
         
     | 
| 
       217 
     | 
    
         
            -
                     
     | 
| 
       218 
     | 
    
         
            -
                    sleep(options[:socket_failure_delay]) if options[:socket_failure_delay]
         
     | 
| 
       219 
     | 
    
         
            -
                    raise Dalli::NetworkError, "Socket operation failed, retrying..."
         
     | 
| 
      
 231 
     | 
    
         
            +
                    reconnect! 'Socket operation failed, retrying...'
         
     | 
| 
       220 
232 
     | 
    
         
             
                  end
         
     | 
| 
       221 
233 
     | 
    
         
             
                end
         
     | 
| 
       222 
234 
     | 
    
         | 
| 
         @@ -255,10 +267,10 @@ module Dalli 
     | 
|
| 
       255 
267 
     | 
    
         
             
                  Thread.current[:dalli_multi]
         
     | 
| 
       256 
268 
     | 
    
         
             
                end
         
     | 
| 
       257 
269 
     | 
    
         | 
| 
       258 
     | 
    
         
            -
                def get(key)
         
     | 
| 
      
 270 
     | 
    
         
            +
                def get(key, options=nil)
         
     | 
| 
       259 
271 
     | 
    
         
             
                  req = [REQUEST, OPCODES[:get], key.bytesize, 0, 0, 0, key.bytesize, 0, 0, key].pack(FORMAT[:get])
         
     | 
| 
       260 
272 
     | 
    
         
             
                  write(req)
         
     | 
| 
       261 
     | 
    
         
            -
                  generic_response(true)
         
     | 
| 
      
 273 
     | 
    
         
            +
                  generic_response(true, !!(options && options.is_a?(Hash) && options[:cache_nils]))
         
     | 
| 
       262 
274 
     | 
    
         
             
                end
         
     | 
| 
       263 
275 
     | 
    
         | 
| 
       264 
276 
     | 
    
         
             
                def send_multiget(keys)
         
     | 
| 
         @@ -400,7 +412,7 @@ module Dalli 
     | 
|
| 
       400 
412 
     | 
    
         
             
                    marshalled = true
         
     | 
| 
       401 
413 
     | 
    
         
             
                    begin
         
     | 
| 
       402 
414 
     | 
    
         
             
                      self.serializer.dump(value)
         
     | 
| 
       403 
     | 
    
         
            -
                    rescue  
     | 
| 
      
 415 
     | 
    
         
            +
                    rescue Timeout::Error => e
         
     | 
| 
       404 
416 
     | 
    
         
             
                      raise e
         
     | 
| 
       405 
417 
     | 
    
         
             
                    rescue => ex
         
     | 
| 
       406 
418 
     | 
    
         
             
                      # Marshalling can throw several different types of generic Ruby exceptions.
         
     | 
| 
         @@ -413,7 +425,8 @@ module Dalli 
     | 
|
| 
       413 
425 
     | 
    
         
             
                    value.to_s
         
     | 
| 
       414 
426 
     | 
    
         
             
                  end
         
     | 
| 
       415 
427 
     | 
    
         
             
                  compressed = false
         
     | 
| 
       416 
     | 
    
         
            -
                  if  
     | 
| 
      
 428 
     | 
    
         
            +
                  set_compress_option = true if options && options[:compress]
         
     | 
| 
      
 429 
     | 
    
         
            +
                  if (@options[:compress] || set_compress_option) && value.bytesize >= @options[:compression_min_size] &&
         
     | 
| 
       417 
430 
     | 
    
         
             
                    (!@options[:compression_max_size] || value.bytesize <= @options[:compression_max_size])
         
     | 
| 
       418 
431 
     | 
    
         
             
                    value = self.compressor.compress(value)
         
     | 
| 
       419 
432 
     | 
    
         
             
                    compressed = true
         
     | 
| 
         @@ -471,19 +484,21 @@ module Dalli 
     | 
|
| 
       471 
484 
     | 
    
         
             
                # > An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a unix timestamp of an exact date.
         
     | 
| 
       472 
485 
     | 
    
         
             
                MAX_ACCEPTABLE_EXPIRATION_INTERVAL = 30*24*60*60 # 30 days
         
     | 
| 
       473 
486 
     | 
    
         
             
                def sanitize_ttl(ttl)
         
     | 
| 
       474 
     | 
    
         
            -
                   
     | 
| 
       475 
     | 
    
         
            -
             
     | 
| 
       476 
     | 
    
         
            -
             
     | 
| 
       477 
     | 
    
         
            -
                   
     | 
| 
       478 
     | 
    
         
            -
                    ttl.to_i
         
     | 
| 
       479 
     | 
    
         
            -
                  end
         
     | 
| 
      
 487 
     | 
    
         
            +
                  ttl_as_i = ttl.to_i
         
     | 
| 
      
 488 
     | 
    
         
            +
                  return ttl_as_i if ttl_as_i <= MAX_ACCEPTABLE_EXPIRATION_INTERVAL
         
     | 
| 
      
 489 
     | 
    
         
            +
                  Dalli.logger.debug "Expiration interval (#{ttl_as_i}) too long for Memcached, converting to an expiration timestamp"
         
     | 
| 
      
 490 
     | 
    
         
            +
                  Time.now.to_i + ttl_as_i
         
     | 
| 
       480 
491 
     | 
    
         
             
                end
         
     | 
| 
       481 
492 
     | 
    
         | 
| 
       482 
     | 
    
         
            -
                 
     | 
| 
      
 493 
     | 
    
         
            +
                # Implements the NullObject pattern to store an application-defined value for 'Key not found' responses.
         
     | 
| 
      
 494 
     | 
    
         
            +
                class NilObject; end
         
     | 
| 
      
 495 
     | 
    
         
            +
                NOT_FOUND = NilObject.new
         
     | 
| 
      
 496 
     | 
    
         
            +
             
     | 
| 
      
 497 
     | 
    
         
            +
                def generic_response(unpack=false, cache_nils=false)
         
     | 
| 
       483 
498 
     | 
    
         
             
                  (extras, _, status, count) = read_header.unpack(NORMAL_HEADER)
         
     | 
| 
       484 
499 
     | 
    
         
             
                  data = read(count) if count > 0
         
     | 
| 
       485 
500 
     | 
    
         
             
                  if status == 1
         
     | 
| 
       486 
     | 
    
         
            -
                    nil
         
     | 
| 
      
 501 
     | 
    
         
            +
                    cache_nils ? NOT_FOUND : nil
         
     | 
| 
       487 
502 
     | 
    
         
             
                  elsif status == 2 || status == 5
         
     | 
| 
       488 
503 
     | 
    
         
             
                    false # Not stored, normal status for add operation
         
     | 
| 
       489 
504 
     | 
    
         
             
                  elsif status != 0
         
     |