dalli 0.10.1 → 0.11.0
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.
- data/History.md +14 -0
 - data/README.md +0 -2
 - data/dalli.gemspec +1 -1
 - data/lib/dalli.rb +1 -1
 - data/lib/dalli/client.rb +40 -26
 - data/lib/dalli/server.rb +106 -54
 - data/lib/dalli/version.rb +1 -1
 - data/test/test_dalli.rb +54 -5
 - data/test/test_encoding.rb +1 -1
 - data/test/test_network.rb +4 -4
 - metadata +6 -6
 
    
        data/History.md
    CHANGED
    
    | 
         @@ -1,6 +1,20 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Dalli Changelog
         
     | 
| 
       2 
2 
     | 
    
         
             
            =====================
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
      
 4 
     | 
    
         
            +
            0.11.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            ======
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Warning: this release changes how Dalli marshals data.  I do not guarantee compatibility until 1.0 but I will increment the minor version every time a release breaks compatibility until 1.0.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            IT IS HIGHLY RECOMMENDED YOU FLUSH YOUR CACHE BEFORE UPGRADING.
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
             - multi() now works reentrantly.
         
     | 
| 
      
 12 
     | 
    
         
            +
             - Added new Dalli::Client option for default TTLs, :expires_in, defaults to 0 (aka forever).
         
     | 
| 
      
 13 
     | 
    
         
            +
             - Added new Dalli::Client option, :compression, to enable auto-compression of values.
         
     | 
| 
      
 14 
     | 
    
         
            +
             - Refactor how Dalli stores data on the server.  Values are now tagged
         
     | 
| 
      
 15 
     | 
    
         
            +
               as "marshalled" or "compressed" so they can be automatically deserialized
         
     | 
| 
      
 16 
     | 
    
         
            +
               without the client having to know how they were stored.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       4 
18 
     | 
    
         
             
            0.10.1
         
     | 
| 
       5 
19 
     | 
    
         
             
            ======
         
     | 
| 
       6 
20 
     | 
    
         | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -113,8 +113,6 @@ Features and Changes 
     | 
|
| 
       113 
113 
     | 
    
         | 
| 
       114 
114 
     | 
    
         
             
            Dalli is **NOT** 100% API compatible with memcache-client.  If you have code which uses the MemCache API directly, it will likely need small tweaks.  Method parameters and return values changed slightly.  See Upgrade.md for more detail.
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
     | 
    
         
            -
            I've removed support for key namespaces and automatic pruning of keys longer than 250 characters.  ActiveSupport::Cache implements these features so there is little need for Dalli to reinvent them.
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
116 
     | 
    
         
             
            By default, Dalli is thread-safe.  Disable thread-safety at your own peril.
         
     | 
| 
       119 
117 
     | 
    
         | 
| 
       120 
118 
     | 
    
         
             
            Note that Dalli does not require ActiveSupport or Rails.  You can safely use it in your own Ruby projects.
         
     | 
    
        data/dalli.gemspec
    CHANGED
    
    | 
         @@ -28,7 +28,7 @@ Gem::Specification.new do |s| 
     | 
|
| 
       28 
28 
     | 
    
         
             
              s.test_files = Dir.glob("test/**/*")
         
     | 
| 
       29 
29 
     | 
    
         
             
              s.add_development_dependency(%q<shoulda>, [">= 0"])
         
     | 
| 
       30 
30 
     | 
    
         
             
              s.add_development_dependency(%q<mocha>, [">= 0"])
         
     | 
| 
       31 
     | 
    
         
            -
              s.add_development_dependency(%q<rails>, [">= 3.0. 
     | 
| 
      
 31 
     | 
    
         
            +
              s.add_development_dependency(%q<rails>, [">= 3.0.1"])
         
     | 
| 
       32 
32 
     | 
    
         
             
              s.add_development_dependency(%q<memcache-client>, [">= 1.8.5"])
         
     | 
| 
       33 
33 
     | 
    
         
             
            end
         
     | 
| 
       34 
34 
     | 
    
         | 
    
        data/lib/dalli.rb
    CHANGED
    
    
    
        data/lib/dalli/client.rb
    CHANGED
    
    | 
         @@ -4,20 +4,25 @@ module Dalli 
     | 
|
| 
       4 
4 
     | 
    
         
             
                ##
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Dalli::Client is the main class which developers will use to interact with
         
     | 
| 
       6 
6 
     | 
    
         
             
                # the memcached server.  Usage:
         
     | 
| 
       7 
     | 
    
         
            -
                #  
     | 
| 
       8 
     | 
    
         
            -
                # 
     | 
| 
       9 
     | 
    
         
            -
                #                   :threadsafe => true, :failover => true)
         
     | 
| 
       10 
     | 
    
         
            -
                #  
     | 
| 
      
 7 
     | 
    
         
            +
                # 
         
     | 
| 
      
 8 
     | 
    
         
            +
                #   Dalli::Client.new(['localhost:11211:10', 'cache-2.example.com:11211:5', '192.168.0.1:22122:5'], 
         
     | 
| 
      
 9 
     | 
    
         
            +
                #                   :threadsafe => true, :failover => true, :expires_in => 300)
         
     | 
| 
      
 10 
     | 
    
         
            +
                # 
         
     | 
| 
       11 
11 
     | 
    
         
             
                # servers is an Array of "host:port:weight" where weight allows you to distribute cache unevenly.
         
     | 
| 
       12 
     | 
    
         
            -
                # Both weight and port are optional.
         
     | 
| 
      
 12 
     | 
    
         
            +
                # Both weight and port are optional.  If you pass in nil, Dalli will default to 'localhost:11211'.
         
     | 
| 
      
 13 
     | 
    
         
            +
                # Note that the <tt>MEMCACHE_SERVERS</tt> environment variable will override the servers parameter for use
         
     | 
| 
      
 14 
     | 
    
         
            +
                # in managed environments like Heroku.
         
     | 
| 
       13 
15 
     | 
    
         
             
                #
         
     | 
| 
       14 
16 
     | 
    
         
             
                # Options:
         
     | 
| 
       15 
     | 
    
         
            -
                # 
     | 
| 
       16 
     | 
    
         
            -
                # 
     | 
| 
      
 17 
     | 
    
         
            +
                # - :failover - if a server is down, look for and store values on another server in the ring.  Default: true.
         
     | 
| 
      
 18 
     | 
    
         
            +
                # - :threadsafe - ensure that only one thread is actively using a socket at a time. Default: true.
         
     | 
| 
      
 19 
     | 
    
         
            +
                # - :expires_in - default TTL in seconds if you do not pass TTL as a parameter to an individual operation, defaults to 0 or forever
         
     | 
| 
      
 20 
     | 
    
         
            +
                # - :compression - defaults to false, if true Dalli will compress values larger than 100 bytes before
         
     | 
| 
      
 21 
     | 
    
         
            +
                #    sending them to memcached.
         
     | 
| 
       17 
22 
     | 
    
         
             
                #
         
     | 
| 
       18 
23 
     | 
    
         
             
                def initialize(servers=nil, options={})
         
     | 
| 
       19 
24 
     | 
    
         
             
                  @servers = env_servers || servers || 'localhost:11211'
         
     | 
| 
       20 
     | 
    
         
            -
                  @options = options
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @options = { :expires_in => 0 }.merge(options)
         
     | 
| 
       21 
26 
     | 
    
         
             
                end
         
     | 
| 
       22 
27 
     | 
    
         | 
| 
       23 
28 
     | 
    
         
             
                #
         
     | 
| 
         @@ -30,10 +35,10 @@ module Dalli 
     | 
|
| 
       30 
35 
     | 
    
         
             
                # pipelined as Dalli will use 'quiet' operations where possible.
         
     | 
| 
       31 
36 
     | 
    
         
             
                # Currently supports the set, add, replace and delete operations.
         
     | 
| 
       32 
37 
     | 
    
         
             
                def multi
         
     | 
| 
       33 
     | 
    
         
            -
                  Thread.current[: 
     | 
| 
      
 38 
     | 
    
         
            +
                  old, Thread.current[:dalli_multi] = Thread.current[:dalli_multi], true
         
     | 
| 
       34 
39 
     | 
    
         
             
                  yield
         
     | 
| 
       35 
40 
     | 
    
         
             
                ensure
         
     | 
| 
       36 
     | 
    
         
            -
                  Thread.current[: 
     | 
| 
      
 41 
     | 
    
         
            +
                  Thread.current[:dalli_multi] = old
         
     | 
| 
       37 
42 
     | 
    
         
             
                end
         
     | 
| 
       38 
43 
     | 
    
         | 
| 
       39 
44 
     | 
    
         
             
                def get(key, options=nil)
         
     | 
| 
         @@ -54,7 +59,8 @@ module Dalli 
     | 
|
| 
       54 
59 
     | 
    
         
             
                  end
         
     | 
| 
       55 
60 
     | 
    
         
             
                end
         
     | 
| 
       56 
61 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                def fetch(key, ttl= 
     | 
| 
      
 62 
     | 
    
         
            +
                def fetch(key, ttl=nil, options=nil)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  ttl ||= @options[:expires_in]
         
     | 
| 
       58 
64 
     | 
    
         
             
                  val = get(key, options)
         
     | 
| 
       59 
65 
     | 
    
         
             
                  if val.nil? && block_given?
         
     | 
| 
       60 
66 
     | 
    
         
             
                    val = yield
         
     | 
| 
         @@ -63,25 +69,29 @@ module Dalli 
     | 
|
| 
       63 
69 
     | 
    
         
             
                  val
         
     | 
| 
       64 
70 
     | 
    
         
             
                end
         
     | 
| 
       65 
71 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
                def cas(key, ttl= 
     | 
| 
      
 72 
     | 
    
         
            +
                def cas(key, ttl=nil, options=nil, &block)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  ttl ||= @options[:expires_in]
         
     | 
| 
       67 
74 
     | 
    
         
             
                  (value, cas) = perform(:cas, key)
         
     | 
| 
       68 
75 
     | 
    
         
             
                  value = (!value || value == 'Not found') ? nil : deserialize(value, options)
         
     | 
| 
       69 
76 
     | 
    
         
             
                  if value
         
     | 
| 
       70 
77 
     | 
    
         
             
                    newvalue = block.call(value)
         
     | 
| 
       71 
     | 
    
         
            -
                    perform(:add, key, serialize(newvalue, options), ttl, cas)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    perform(:add, key, serialize(newvalue, options), ttl, cas, options)
         
     | 
| 
       72 
79 
     | 
    
         
             
                  end
         
     | 
| 
       73 
80 
     | 
    
         
             
                end
         
     | 
| 
       74 
81 
     | 
    
         | 
| 
       75 
     | 
    
         
            -
                def set(key, value, ttl= 
     | 
| 
       76 
     | 
    
         
            -
                   
     | 
| 
      
 82 
     | 
    
         
            +
                def set(key, value, ttl=nil, options=nil)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  ttl ||= @options[:expires_in]
         
     | 
| 
      
 84 
     | 
    
         
            +
                  perform(:set, key, serialize(value, options), ttl, options)
         
     | 
| 
       77 
85 
     | 
    
         
             
                end
         
     | 
| 
       78 
86 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
                def add(key, value, ttl= 
     | 
| 
       80 
     | 
    
         
            -
                   
     | 
| 
      
 87 
     | 
    
         
            +
                def add(key, value, ttl=nil, options=nil)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  ttl ||= @options[:expires_in]
         
     | 
| 
      
 89 
     | 
    
         
            +
                  perform(:add, key, serialize(value, options), ttl, 0, options)
         
     | 
| 
       81 
90 
     | 
    
         
             
                end
         
     | 
| 
       82 
91 
     | 
    
         | 
| 
       83 
     | 
    
         
            -
                def replace(key, value, ttl= 
     | 
| 
       84 
     | 
    
         
            -
                   
     | 
| 
      
 92 
     | 
    
         
            +
                def replace(key, value, ttl=nil, options=nil)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  ttl ||= @options[:expires_in]
         
     | 
| 
      
 94 
     | 
    
         
            +
                  perform(:replace, key, serialize(value, options), ttl, options)
         
     | 
| 
       85 
95 
     | 
    
         
             
                end
         
     | 
| 
       86 
96 
     | 
    
         | 
| 
       87 
97 
     | 
    
         
             
                def delete(key)
         
     | 
| 
         @@ -116,8 +126,9 @@ module Dalli 
     | 
|
| 
       116 
126 
     | 
    
         
             
                # If default is nil, the counter must already exist or the operation
         
     | 
| 
       117 
127 
     | 
    
         
             
                # will fail and will return nil.  Otherwise this method will return
         
     | 
| 
       118 
128 
     | 
    
         
             
                # the new value for the counter.
         
     | 
| 
       119 
     | 
    
         
            -
                def incr(key, amt=1, ttl= 
     | 
| 
      
 129 
     | 
    
         
            +
                def incr(key, amt=1, ttl=nil, default=nil)
         
     | 
| 
       120 
130 
     | 
    
         
             
                  raise ArgumentError, "Positive values only: #{amt}" if amt < 0
         
     | 
| 
      
 131 
     | 
    
         
            +
                  ttl ||= @options[:expires_in]
         
     | 
| 
       121 
132 
     | 
    
         
             
                  perform(:incr, key, amt, ttl, default)
         
     | 
| 
       122 
133 
     | 
    
         
             
                end
         
     | 
| 
       123 
134 
     | 
    
         | 
| 
         @@ -131,8 +142,9 @@ module Dalli 
     | 
|
| 
       131 
142 
     | 
    
         
             
                # If default is nil, the counter must already exist or the operation
         
     | 
| 
       132 
143 
     | 
    
         
             
                # will fail and will return nil.  Otherwise this method will return
         
     | 
| 
       133 
144 
     | 
    
         
             
                # the new value for the counter.
         
     | 
| 
       134 
     | 
    
         
            -
                def decr(key, amt=1, ttl= 
     | 
| 
      
 145 
     | 
    
         
            +
                def decr(key, amt=1, ttl=nil, default=nil)
         
     | 
| 
       135 
146 
     | 
    
         
             
                  raise ArgumentError, "Positive values only: #{amt}" if amt < 0
         
     | 
| 
      
 147 
     | 
    
         
            +
                  ttl ||= @options[:expires_in]
         
     | 
| 
       136 
148 
     | 
    
         
             
                  perform(:decr, key, amt, ttl, default)
         
     | 
| 
       137 
149 
     | 
    
         
             
                end
         
     | 
| 
       138 
150 
     | 
    
         | 
| 
         @@ -153,19 +165,21 @@ module Dalli 
     | 
|
| 
       153 
165 
     | 
    
         
             
                def ring
         
     | 
| 
       154 
166 
     | 
    
         
             
                  @ring ||= Dalli::Ring.new(
         
     | 
| 
       155 
167 
     | 
    
         
             
                    Array(@servers).map do |s|
         
     | 
| 
       156 
     | 
    
         
            -
                      Dalli::Server.new(s)
         
     | 
| 
      
 168 
     | 
    
         
            +
                      Dalli::Server.new(s, @options)
         
     | 
| 
       157 
169 
     | 
    
         
             
                    end, @options
         
     | 
| 
       158 
170 
     | 
    
         
             
                  )
         
     | 
| 
       159 
171 
     | 
    
         
             
                end
         
     | 
| 
       160 
172 
     | 
    
         | 
| 
       161 
173 
     | 
    
         
             
                def serialize(value, options)
         
     | 
| 
       162 
     | 
    
         
            -
                   
     | 
| 
      
 174 
     | 
    
         
            +
                  value
         
     | 
| 
      
 175 
     | 
    
         
            +
            #      options && options[:raw] ? value.to_s : ::Marshal.dump(value)
         
     | 
| 
       163 
176 
     | 
    
         
             
                end
         
     | 
| 
       164 
177 
     | 
    
         | 
| 
       165 
178 
     | 
    
         
             
                def deserialize(value, options)
         
     | 
| 
       166 
     | 
    
         
            -
                   
     | 
| 
       167 
     | 
    
         
            -
                 
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
      
 179 
     | 
    
         
            +
                  value
         
     | 
| 
      
 180 
     | 
    
         
            +
                #   options && options[:raw] ? value : ::Marshal.load(value)
         
     | 
| 
      
 181 
     | 
    
         
            +
                # rescue TypeError
         
     | 
| 
      
 182 
     | 
    
         
            +
                #   raise Dalli::DalliError, "Invalid marshalled data in memcached: #{value}"
         
     | 
| 
       169 
183 
     | 
    
         
             
                end
         
     | 
| 
       170 
184 
     | 
    
         | 
| 
       171 
185 
     | 
    
         
             
                def env_servers
         
     | 
    
        data/lib/dalli/server.rb
    CHANGED
    
    | 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'socket'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'timeout'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'zlib'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
       4 
5 
     | 
    
         
             
            module Dalli
         
     | 
| 
       5 
6 
     | 
    
         
             
              class Server
         
     | 
| 
         @@ -7,7 +8,7 @@ module Dalli 
     | 
|
| 
       7 
8 
     | 
    
         
             
                attr_accessor :port
         
     | 
| 
       8 
9 
     | 
    
         
             
                attr_accessor :weight
         
     | 
| 
       9 
10 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                def initialize(attribs)
         
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize(attribs, options=nil)
         
     | 
| 
       11 
12 
     | 
    
         
             
                  (@hostname, @port, @weight) = attribs.split(':')
         
     | 
| 
       12 
13 
     | 
    
         
             
                  @port ||= 11211
         
     | 
| 
       13 
14 
     | 
    
         
             
                  @port = Integer(@port)
         
     | 
| 
         @@ -15,6 +16,7 @@ module Dalli 
     | 
|
| 
       15 
16 
     | 
    
         
             
                  @weight = Integer(@weight)
         
     | 
| 
       16 
17 
     | 
    
         
             
                  @down_at = nil
         
     | 
| 
       17 
18 
     | 
    
         
             
                  @version = detect_memcached_version
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @options = options
         
     | 
| 
       18 
20 
     | 
    
         
             
                  Dalli.logger.debug { "#{@hostname}:#{@port} running memcached v#{@version}" }
         
     | 
| 
       19 
21 
     | 
    
         
             
                end
         
     | 
| 
       20 
22 
     | 
    
         | 
| 
         @@ -28,8 +30,9 @@ module Dalli 
     | 
|
| 
       28 
30 
     | 
    
         
             
                    raise
         
     | 
| 
       29 
31 
     | 
    
         
             
                  rescue Exception => ex
         
     | 
| 
       30 
32 
     | 
    
         
             
                    Dalli.logger.error "Unexpected exception in Dalli: #{ex.class.name}: #{ex.message}"
         
     | 
| 
      
 33 
     | 
    
         
            +
                    Dalli.logger.error "This is a bug in Dalli, please enter an issue in Github if it does not already exist."
         
     | 
| 
       31 
34 
     | 
    
         
             
                    Dalli.logger.error ex.backtrace.join("\n\t")
         
     | 
| 
       32 
     | 
    
         
            -
                    down!
         
     | 
| 
      
 35 
     | 
    
         
            +
                    down!(true)
         
     | 
| 
       33 
36 
     | 
    
         
             
                  end
         
     | 
| 
       34 
37 
     | 
    
         
             
                end
         
     | 
| 
       35 
38 
     | 
    
         | 
| 
         @@ -42,8 +45,8 @@ module Dalli 
     | 
|
| 
       42 
45 
     | 
    
         
             
                    connection
         
     | 
| 
       43 
46 
     | 
    
         
             
                    true
         
     | 
| 
       44 
47 
     | 
    
         
             
                  rescue Dalli::NetworkError => dne
         
     | 
| 
       45 
     | 
    
         
            -
                    Dalli.logger.info( 
     | 
| 
       46 
     | 
    
         
            -
                     
     | 
| 
      
 48 
     | 
    
         
            +
                    Dalli.logger.info(dne.message)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    false
         
     | 
| 
       47 
50 
     | 
    
         
             
                  end
         
     | 
| 
       48 
51 
     | 
    
         
             
                end
         
     | 
| 
       49 
52 
     | 
    
         | 
| 
         @@ -85,15 +88,21 @@ module Dalli 
     | 
|
| 
       85 
88 
     | 
    
         
             
                  end
         
     | 
| 
       86 
89 
     | 
    
         
             
                end
         
     | 
| 
       87 
90 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
                def down!
         
     | 
| 
      
 91 
     | 
    
         
            +
                def down!(toss_exception=false)
         
     | 
| 
       89 
92 
     | 
    
         
             
                  close
         
     | 
| 
       90 
93 
     | 
    
         
             
                  @down_at = Time.now.to_i
         
     | 
| 
       91 
     | 
    
         
            -
                  @msg = $!.message
         
     | 
| 
      
 94 
     | 
    
         
            +
                  @msg = @msg || ($! && $!.message) || ''
         
     | 
| 
      
 95 
     | 
    
         
            +
                  raise Dalli::NetworkError, "#{self.hostname}:#{self.port} is currently down: #{@msg}" if toss_exception
         
     | 
| 
       92 
96 
     | 
    
         
             
                  nil
         
     | 
| 
       93 
97 
     | 
    
         
             
                end
         
     | 
| 
       94 
98 
     | 
    
         | 
| 
      
 99 
     | 
    
         
            +
                def up!
         
     | 
| 
      
 100 
     | 
    
         
            +
                  @down_at = nil
         
     | 
| 
      
 101 
     | 
    
         
            +
                  @msg = nil
         
     | 
| 
      
 102 
     | 
    
         
            +
                end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
       95 
104 
     | 
    
         
             
                def multi?
         
     | 
| 
       96 
     | 
    
         
            -
                  Thread.current[: 
     | 
| 
      
 105 
     | 
    
         
            +
                  Thread.current[:dalli_multi]
         
     | 
| 
       97 
106 
     | 
    
         
             
                end
         
     | 
| 
       98 
107 
     | 
    
         | 
| 
       99 
108 
     | 
    
         
             
                ONE_MB = 1024 * 1024
         
     | 
| 
         @@ -101,7 +110,7 @@ module Dalli 
     | 
|
| 
       101 
110 
     | 
    
         
             
                def get(key)
         
     | 
| 
       102 
111 
     | 
    
         
             
                  req = [REQUEST, OPCODES[:get], key.bytesize, 0, 0, 0, key.bytesize, 0, 0, key].pack(FORMAT[:get])
         
     | 
| 
       103 
112 
     | 
    
         
             
                  write(req)
         
     | 
| 
       104 
     | 
    
         
            -
                  generic_response
         
     | 
| 
      
 113 
     | 
    
         
            +
                  generic_response(true)
         
     | 
| 
       105 
114 
     | 
    
         
             
                end
         
     | 
| 
       106 
115 
     | 
    
         | 
| 
       107 
116 
     | 
    
         
             
                def getkq(key)
         
     | 
| 
         @@ -109,40 +118,41 @@ module Dalli 
     | 
|
| 
       109 
118 
     | 
    
         
             
                  write(req)
         
     | 
| 
       110 
119 
     | 
    
         
             
                end
         
     | 
| 
       111 
120 
     | 
    
         | 
| 
       112 
     | 
    
         
            -
                def set(key, value, ttl)
         
     | 
| 
       113 
     | 
    
         
            -
                   
     | 
| 
      
 121 
     | 
    
         
            +
                def set(key, value, ttl, options)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  (value, flags) = serialize(value, options)
         
     | 
| 
       114 
123 
     | 
    
         | 
| 
       115 
     | 
    
         
            -
                  req = [REQUEST, OPCODES[multi? ? :setq : :set], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, 0,  
     | 
| 
      
 124 
     | 
    
         
            +
                  req = [REQUEST, OPCODES[multi? ? :setq : :set], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, 0, flags, ttl, key, value].pack(FORMAT[:set])
         
     | 
| 
       116 
125 
     | 
    
         
             
                  write(req)
         
     | 
| 
       117 
126 
     | 
    
         
             
                  generic_response unless multi?
         
     | 
| 
       118 
127 
     | 
    
         
             
                end
         
     | 
| 
       119 
128 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
                def  
     | 
| 
       121 
     | 
    
         
            -
                   
     | 
| 
       122 
     | 
    
         
            -
                  write(req)
         
     | 
| 
       123 
     | 
    
         
            -
                  generic_response
         
     | 
| 
       124 
     | 
    
         
            -
                end
         
     | 
| 
      
 129 
     | 
    
         
            +
                def add(key, value, ttl, cas, options)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  (value, flags) = serialize(value, options)
         
     | 
| 
       125 
131 
     | 
    
         | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
                  raise Dalli::DalliError, "Value too large, memcached can only store 1MB of data per key" if value.bytesize > ONE_MB
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
                  req = [REQUEST, OPCODES[multi? ? :addq : :add], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, cas, 0, ttl, key, value].pack(FORMAT[:add])
         
     | 
| 
      
 132 
     | 
    
         
            +
                  req = [REQUEST, OPCODES[multi? ? :addq : :add], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, cas, flags, ttl, key, value].pack(FORMAT[:add])
         
     | 
| 
       130 
133 
     | 
    
         
             
                  write(req)
         
     | 
| 
       131 
134 
     | 
    
         
             
                  generic_response unless multi?
         
     | 
| 
       132 
135 
     | 
    
         
             
                end
         
     | 
| 
       133 
136 
     | 
    
         | 
| 
       134 
     | 
    
         
            -
                def  
     | 
| 
       135 
     | 
    
         
            -
                   
     | 
| 
      
 137 
     | 
    
         
            +
                def replace(key, value, ttl, options)
         
     | 
| 
      
 138 
     | 
    
         
            +
                  (value, flags) = serialize(value, options)
         
     | 
| 
      
 139 
     | 
    
         
            +
                  req = [REQUEST, OPCODES[multi? ? :replaceq : :replace], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, 0, flags, ttl, key, value].pack(FORMAT[:replace])
         
     | 
| 
       136 
140 
     | 
    
         
             
                  write(req)
         
     | 
| 
       137 
     | 
    
         
            -
                  generic_response
         
     | 
| 
      
 141 
     | 
    
         
            +
                  generic_response unless multi?
         
     | 
| 
       138 
142 
     | 
    
         
             
                end
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
       140 
144 
     | 
    
         
             
                def delete(key)
         
     | 
| 
       141 
145 
     | 
    
         
             
                  req = [REQUEST, OPCODES[multi? ? :deleteq : :delete], key.bytesize, 0, 0, 0, key.bytesize, 0, 0, key].pack(FORMAT[:delete])
         
     | 
| 
       142 
146 
     | 
    
         
             
                  write(req)
         
     | 
| 
       143 
147 
     | 
    
         
             
                  generic_response unless multi?
         
     | 
| 
       144 
148 
     | 
    
         
             
                end
         
     | 
| 
       145 
149 
     | 
    
         | 
| 
      
 150 
     | 
    
         
            +
                def flush(ttl)
         
     | 
| 
      
 151 
     | 
    
         
            +
                  req = [REQUEST, OPCODES[:flush], 0, 4, 0, 0, 4, 0, 0, 0].pack(FORMAT[:flush])
         
     | 
| 
      
 152 
     | 
    
         
            +
                  write(req)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  generic_response
         
     | 
| 
      
 154 
     | 
    
         
            +
                end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
       146 
156 
     | 
    
         
             
                def decr(key, count, ttl, default)
         
     | 
| 
       147 
157 
     | 
    
         
             
                  expiry = default ? ttl : 0xFFFFFFFF
         
     | 
| 
       148 
158 
     | 
    
         
             
                  default ||= 0
         
     | 
| 
         @@ -173,16 +183,16 @@ module Dalli 
     | 
|
| 
       173 
183 
     | 
    
         
             
                  multi_response
         
     | 
| 
       174 
184 
     | 
    
         
             
                end
         
     | 
| 
       175 
185 
     | 
    
         | 
| 
       176 
     | 
    
         
            -
                def  
     | 
| 
       177 
     | 
    
         
            -
                  req = [REQUEST, OPCODES[: 
     | 
| 
      
 186 
     | 
    
         
            +
                def append(key, value)
         
     | 
| 
      
 187 
     | 
    
         
            +
                  req = [REQUEST, OPCODES[:append], key.bytesize, 0, 0, 0, value.bytesize + key.bytesize, 0, 0, key, value].pack(FORMAT[:append])
         
     | 
| 
       178 
188 
     | 
    
         
             
                  write(req)
         
     | 
| 
       179 
189 
     | 
    
         
             
                  generic_response
         
     | 
| 
       180 
190 
     | 
    
         
             
                end
         
     | 
| 
       181 
191 
     | 
    
         | 
| 
       182 
     | 
    
         
            -
                def  
     | 
| 
       183 
     | 
    
         
            -
                  req = [REQUEST, OPCODES[ 
     | 
| 
      
 192 
     | 
    
         
            +
                def prepend(key, value)
         
     | 
| 
      
 193 
     | 
    
         
            +
                  req = [REQUEST, OPCODES[:prepend], key.bytesize, 0, 0, 0, value.bytesize + key.bytesize, 0, 0, key, value].pack(FORMAT[:prepend])
         
     | 
| 
       184 
194 
     | 
    
         
             
                  write(req)
         
     | 
| 
       185 
     | 
    
         
            -
                  generic_response 
     | 
| 
      
 195 
     | 
    
         
            +
                  generic_response
         
     | 
| 
       186 
196 
     | 
    
         
             
                end
         
     | 
| 
       187 
197 
     | 
    
         | 
| 
       188 
198 
     | 
    
         
             
                def stats(info='')
         
     | 
| 
         @@ -209,6 +219,44 @@ module Dalli 
     | 
|
| 
       209 
219 
     | 
    
         
             
                  generic_response
         
     | 
| 
       210 
220 
     | 
    
         
             
                end
         
     | 
| 
       211 
221 
     | 
    
         | 
| 
      
 222 
     | 
    
         
            +
                COMPRESSION_MIN_SIZE = 100
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                # http://www.hjp.at/zettel/m/memcached_flags.rxml
         
     | 
| 
      
 225 
     | 
    
         
            +
                # Looks like most clients use bit 0 to indicate native language serialization
         
     | 
| 
      
 226 
     | 
    
         
            +
                # and bit 1 to indicate gzip compression.
         
     | 
| 
      
 227 
     | 
    
         
            +
                FLAG_MARSHALLED = 0x1
         
     | 
| 
      
 228 
     | 
    
         
            +
                FLAG_COMPRESSED = 0x2
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                def serialize(value, options=nil)
         
     | 
| 
      
 231 
     | 
    
         
            +
                  marshalled = false
         
     | 
| 
      
 232 
     | 
    
         
            +
                  value = unless options && options[:raw]
         
     | 
| 
      
 233 
     | 
    
         
            +
                    marshalled = true
         
     | 
| 
      
 234 
     | 
    
         
            +
                    Marshal.dump(value)
         
     | 
| 
      
 235 
     | 
    
         
            +
                  else
         
     | 
| 
      
 236 
     | 
    
         
            +
                    value.to_s
         
     | 
| 
      
 237 
     | 
    
         
            +
                  end
         
     | 
| 
      
 238 
     | 
    
         
            +
                  compressed = false
         
     | 
| 
      
 239 
     | 
    
         
            +
                  if @options[:compression] && value.bytesize >= COMPRESSION_MIN_SIZE
         
     | 
| 
      
 240 
     | 
    
         
            +
                    value = Zlib::Deflate.deflate(value)
         
     | 
| 
      
 241 
     | 
    
         
            +
                    compressed = true
         
     | 
| 
      
 242 
     | 
    
         
            +
                  end
         
     | 
| 
      
 243 
     | 
    
         
            +
                  raise Dalli::DalliError, "Value too large, memcached can only store 1MB of data per key" if value.bytesize > ONE_MB
         
     | 
| 
      
 244 
     | 
    
         
            +
                  flags = 0
         
     | 
| 
      
 245 
     | 
    
         
            +
                  flags |= FLAG_COMPRESSED if compressed
         
     | 
| 
      
 246 
     | 
    
         
            +
                  flags |= FLAG_MARSHALLED if marshalled
         
     | 
| 
      
 247 
     | 
    
         
            +
                  [value, flags]
         
     | 
| 
      
 248 
     | 
    
         
            +
                end
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                def deserialize(value, flags)
         
     | 
| 
      
 251 
     | 
    
         
            +
                  value = Zlib::Inflate.inflate(value) if (flags & FLAG_COMPRESSED) != 0
         
     | 
| 
      
 252 
     | 
    
         
            +
                  value = Marshal.load(value) if (flags & FLAG_MARSHALLED) != 0
         
     | 
| 
      
 253 
     | 
    
         
            +
                  value
         
     | 
| 
      
 254 
     | 
    
         
            +
                rescue TypeError
         
     | 
| 
      
 255 
     | 
    
         
            +
                  raise DalliError, "Unable to unmarshal value: '#{value}'"
         
     | 
| 
      
 256 
     | 
    
         
            +
                rescue Zlib::Error
         
     | 
| 
      
 257 
     | 
    
         
            +
                  raise DalliError, "Unable to uncompress value: '#{value}'"      
         
     | 
| 
      
 258 
     | 
    
         
            +
                end
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
       212 
260 
     | 
    
         
             
                def cas_response
         
     | 
| 
       213 
261 
     | 
    
         
             
                  header = read(24)
         
     | 
| 
       214 
262 
     | 
    
         
             
                  raise Dalli::NetworkError, 'No response' if !header
         
     | 
| 
         @@ -219,12 +267,18 @@ module Dalli 
     | 
|
| 
       219 
267 
     | 
    
         
             
                  elsif status != 0
         
     | 
| 
       220 
268 
     | 
    
         
             
                    raise Dalli::DalliError, "Response error #{status}: #{RESPONSE_CODES[status]}"
         
     | 
| 
       221 
269 
     | 
    
         
             
                  elsif data
         
     | 
| 
       222 
     | 
    
         
            -
                     
     | 
| 
      
 270 
     | 
    
         
            +
                    flags = data[0...extras].unpack('N')[0]
         
     | 
| 
      
 271 
     | 
    
         
            +
                    value = data[extras..-1]
         
     | 
| 
      
 272 
     | 
    
         
            +
                    data = deserialize(value, flags)
         
     | 
| 
       223 
273 
     | 
    
         
             
                  end
         
     | 
| 
       224 
274 
     | 
    
         
             
                  [data, cas]
         
     | 
| 
       225 
275 
     | 
    
         
             
                end
         
     | 
| 
       226 
276 
     | 
    
         | 
| 
       227 
     | 
    
         
            -
                 
     | 
| 
      
 277 
     | 
    
         
            +
                CAS_HEADER = '@4CCnNNQ'
         
     | 
| 
      
 278 
     | 
    
         
            +
                NORMAL_HEADER = '@4CCnN'
         
     | 
| 
      
 279 
     | 
    
         
            +
                KV_HEADER = '@2n@6nN'
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
                def generic_response(unpack=false)
         
     | 
| 
       228 
282 
     | 
    
         
             
                  header = read(24)
         
     | 
| 
       229 
283 
     | 
    
         
             
                  raise Dalli::NetworkError, 'No response' if !header
         
     | 
| 
       230 
284 
     | 
    
         
             
                  (extras, type, status, count) = header.unpack(NORMAL_HEADER)
         
     | 
| 
         @@ -236,7 +290,9 @@ module Dalli 
     | 
|
| 
       236 
290 
     | 
    
         
             
                  elsif status != 0
         
     | 
| 
       237 
291 
     | 
    
         
             
                    raise Dalli::DalliError, "Response error #{status}: #{RESPONSE_CODES[status]}"
         
     | 
| 
       238 
292 
     | 
    
         
             
                  elsif data
         
     | 
| 
       239 
     | 
    
         
            -
                     
     | 
| 
      
 293 
     | 
    
         
            +
                    flags = data[0...extras].unpack('N')[0]
         
     | 
| 
      
 294 
     | 
    
         
            +
                    value = data[extras..-1]
         
     | 
| 
      
 295 
     | 
    
         
            +
                    unpack ? deserialize(value, flags) : value
         
     | 
| 
       240 
296 
     | 
    
         
             
                  else
         
     | 
| 
       241 
297 
     | 
    
         
             
                    true
         
     | 
| 
       242 
298 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -262,10 +318,10 @@ module Dalli 
     | 
|
| 
       262 
318 
     | 
    
         
             
                    raise Dalli::NetworkError, 'No response' if !header
         
     | 
| 
       263 
319 
     | 
    
         
             
                    (key_length, status, body_length) = header.unpack(KV_HEADER)
         
     | 
| 
       264 
320 
     | 
    
         
             
                    return hash if key_length == 0
         
     | 
| 
       265 
     | 
    
         
            -
                    read(4)
         
     | 
| 
      
 321 
     | 
    
         
            +
                    flags = read(4).unpack('N')[0]
         
     | 
| 
       266 
322 
     | 
    
         
             
                    key = read(key_length)
         
     | 
| 
       267 
323 
     | 
    
         
             
                    value = read(body_length - key_length - 4) if body_length - key_length - 4 > 0
         
     | 
| 
       268 
     | 
    
         
            -
                    hash[key] = value
         
     | 
| 
      
 324 
     | 
    
         
            +
                    hash[key] = deserialize(value, flags)
         
     | 
| 
       269 
325 
     | 
    
         
             
                  end
         
     | 
| 
       270 
326 
     | 
    
         
             
                end
         
     | 
| 
       271 
327 
     | 
    
         | 
| 
         @@ -278,24 +334,26 @@ module Dalli 
     | 
|
| 
       278 
334 
     | 
    
         
             
                    end
         
     | 
| 
       279 
335 
     | 
    
         | 
| 
       280 
336 
     | 
    
         
             
                    # All this ugly code to ensure proper Socket connect timeout
         
     | 
| 
       281 
     | 
    
         
            -
                    addr = Socket.getaddrinfo(self.hostname, nil)
         
     | 
| 
       282 
     | 
    
         
            -
                    sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
         
     | 
| 
       283 
337 
     | 
    
         
             
                    begin
         
     | 
| 
       284 
     | 
    
         
            -
                       
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
     | 
    
         
            -
                      resp = IO.select(nil, [sock], nil, TIMEOUT)
         
     | 
| 
      
 338 
     | 
    
         
            +
                      addr = Socket.getaddrinfo(self.hostname, nil)
         
     | 
| 
      
 339 
     | 
    
         
            +
                      sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
         
     | 
| 
       287 
340 
     | 
    
         
             
                      begin
         
     | 
| 
       288 
341 
     | 
    
         
             
                        sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
         
     | 
| 
       289 
     | 
    
         
            -
                      rescue Errno:: 
     | 
| 
       290 
     | 
    
         
            -
                         
     | 
| 
       291 
     | 
    
         
            -
             
     | 
| 
       292 
     | 
    
         
            -
             
     | 
| 
      
 342 
     | 
    
         
            +
                      rescue Errno::EINPROGRESS
         
     | 
| 
      
 343 
     | 
    
         
            +
                        resp = IO.select(nil, [sock], nil, TIMEOUT)
         
     | 
| 
      
 344 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 345 
     | 
    
         
            +
                          sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
         
     | 
| 
      
 346 
     | 
    
         
            +
                        rescue Errno::EISCONN
         
     | 
| 
      
 347 
     | 
    
         
            +
                        end
         
     | 
| 
       293 
348 
     | 
    
         
             
                      end
         
     | 
| 
      
 349 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 350 
     | 
    
         
            +
                      down!(true)
         
     | 
| 
       294 
351 
     | 
    
         
             
                    end
         
     | 
| 
       295 
352 
     | 
    
         
             
                    # end ugly code
         
     | 
| 
       296 
353 
     | 
    
         | 
| 
       297 
354 
     | 
    
         
             
                    sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
         
     | 
| 
       298 
355 
     | 
    
         
             
                    sasl_authentication(sock) if Dalli::Server.need_auth?
         
     | 
| 
      
 356 
     | 
    
         
            +
                    up!
         
     | 
| 
       299 
357 
     | 
    
         
             
                    sock
         
     | 
| 
       300 
358 
     | 
    
         
             
                  end
         
     | 
| 
       301 
359 
     | 
    
         
             
                end
         
     | 
| 
         @@ -303,9 +361,8 @@ module Dalli 
     | 
|
| 
       303 
361 
     | 
    
         
             
                def write(bytes)
         
     | 
| 
       304 
362 
     | 
    
         
             
                  begin
         
     | 
| 
       305 
363 
     | 
    
         
             
                    connection.write(bytes)
         
     | 
| 
       306 
     | 
    
         
            -
                  rescue  
     | 
| 
       307 
     | 
    
         
            -
                    down!
         
     | 
| 
       308 
     | 
    
         
            -
                    raise Dalli::NetworkError, $!.class.name
         
     | 
| 
      
 364 
     | 
    
         
            +
                  rescue SystemCallError
         
     | 
| 
      
 365 
     | 
    
         
            +
                    down!(true)
         
     | 
| 
       309 
366 
     | 
    
         
             
                  end
         
     | 
| 
       310 
367 
     | 
    
         
             
                end
         
     | 
| 
       311 
368 
     | 
    
         | 
| 
         @@ -325,9 +382,8 @@ module Dalli 
     | 
|
| 
       325 
382 
     | 
    
         
             
                      end
         
     | 
| 
       326 
383 
     | 
    
         
             
                    end
         
     | 
| 
       327 
384 
     | 
    
         
             
                    value
         
     | 
| 
       328 
     | 
    
         
            -
                  rescue  
     | 
| 
       329 
     | 
    
         
            -
                    down!
         
     | 
| 
       330 
     | 
    
         
            -
                    raise Dalli::NetworkError, "#{$!.class.name}: #{$!.message}"
         
     | 
| 
      
 385 
     | 
    
         
            +
                  rescue SystemCallError, Timeout::Error, EOFError
         
     | 
| 
      
 386 
     | 
    
         
            +
                    down!(true)
         
     | 
| 
       331 
387 
     | 
    
         
             
                  end
         
     | 
| 
       332 
388 
     | 
    
         
             
                end
         
     | 
| 
       333 
389 
     | 
    
         | 
| 
         @@ -339,10 +395,6 @@ module Dalli 
     | 
|
| 
       339 
395 
     | 
    
         
             
                  (a << 32) | b
         
     | 
| 
       340 
396 
     | 
    
         
             
                end
         
     | 
| 
       341 
397 
     | 
    
         | 
| 
       342 
     | 
    
         
            -
                CAS_HEADER = '@4CCnNNQ'
         
     | 
| 
       343 
     | 
    
         
            -
                NORMAL_HEADER = '@4CCnN'
         
     | 
| 
       344 
     | 
    
         
            -
                KV_HEADER = '@2n@6nN'
         
     | 
| 
       345 
     | 
    
         
            -
             
     | 
| 
       346 
398 
     | 
    
         
             
                REQUEST = 0x80
         
     | 
| 
       347 
399 
     | 
    
         
             
                RESPONSE = 0x81
         
     | 
| 
       348 
400 
     | 
    
         | 
| 
         @@ -465,4 +517,4 @@ module Dalli 
     | 
|
| 
       465 
517 
     | 
    
         
             
                  # raise Dalli::NetworkError, "Authentication failed" if sasl.failed? || step != 'response'
         
     | 
| 
       466 
518 
     | 
    
         
             
                end
         
     | 
| 
       467 
519 
     | 
    
         
             
              end
         
     | 
| 
       468 
     | 
    
         
            -
            end
         
     | 
| 
      
 520 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/dalli/version.rb
    CHANGED
    
    
    
        data/test/test_dalli.rb
    CHANGED
    
    | 
         @@ -222,10 +222,7 @@ class TestDalli < Test::Unit::TestCase 
     | 
|
| 
       222 
222 
     | 
    
         
             
                    assert_equal true, dc.prepend('456', '0')
         
     | 
| 
       223 
223 
     | 
    
         
             
                    assert_equal true, dc.append('456', '9')
         
     | 
| 
       224 
224 
     | 
    
         
             
                    assert_equal '0xyz9', dc.get('456', :raw => true)
         
     | 
| 
       225 
     | 
    
         
            -
             
     | 
| 
       226 
     | 
    
         
            -
                    assert_raises Dalli::DalliError do
         
     | 
| 
       227 
     | 
    
         
            -
                      assert_equal '0xyz9', dc.get('456')
         
     | 
| 
       228 
     | 
    
         
            -
                    end
         
     | 
| 
      
 225 
     | 
    
         
            +
                    assert_equal '0xyz9', dc.get('456')
         
     | 
| 
       229 
226 
     | 
    
         | 
| 
       230 
227 
     | 
    
         
             
                    assert_equal false, dc.append('nonexist', 'abc')
         
     | 
| 
       231 
228 
     | 
    
         
             
                    assert_equal false, dc.prepend('nonexist', 'abc')
         
     | 
| 
         @@ -323,7 +320,6 @@ class TestDalli < Test::Unit::TestCase 
     | 
|
| 
       323 
320 
     | 
    
         
             
                  end
         
     | 
| 
       324 
321 
     | 
    
         
             
                end
         
     | 
| 
       325 
322 
     | 
    
         | 
| 
       326 
     | 
    
         
            -
             
     | 
| 
       327 
323 
     | 
    
         
             
                should "handle namespaced keys" do
         
     | 
| 
       328 
324 
     | 
    
         
             
                  memcached do |dc|
         
     | 
| 
       329 
325 
     | 
    
         
             
                    dc = Dalli::Client.new('localhost:19122', :namespace => 'a')
         
     | 
| 
         @@ -335,6 +331,20 @@ class TestDalli < Test::Unit::TestCase 
     | 
|
| 
       335 
331 
     | 
    
         
             
                  end
         
     | 
| 
       336 
332 
     | 
    
         
             
                end
         
     | 
| 
       337 
333 
     | 
    
         | 
| 
      
 334 
     | 
    
         
            +
                context 'with compression' do
         
     | 
| 
      
 335 
     | 
    
         
            +
                  should 'allow large values' do
         
     | 
| 
      
 336 
     | 
    
         
            +
                    memcached do |dc|
         
     | 
| 
      
 337 
     | 
    
         
            +
                      dalli = Dalli::Client.new(dc.instance_variable_get(:@servers), :compression => true)
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
      
 339 
     | 
    
         
            +
                      value = "0"*1024*1024
         
     | 
| 
      
 340 
     | 
    
         
            +
                      assert_raise Dalli::DalliError, /too large/ do
         
     | 
| 
      
 341 
     | 
    
         
            +
                        dc.set('verylarge', value)
         
     | 
| 
      
 342 
     | 
    
         
            +
                      end
         
     | 
| 
      
 343 
     | 
    
         
            +
                      dalli.set('verylarge', value)
         
     | 
| 
      
 344 
     | 
    
         
            +
                    end
         
     | 
| 
      
 345 
     | 
    
         
            +
                  end
         
     | 
| 
      
 346 
     | 
    
         
            +
                end
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
       338 
348 
     | 
    
         
             
                context 'without authentication credentials' do
         
     | 
| 
       339 
349 
     | 
    
         
             
                  setup do
         
     | 
| 
       340 
350 
     | 
    
         
             
                    ENV['MEMCACHE_USERNAME'] = 'testuser'
         
     | 
| 
         @@ -382,5 +392,44 @@ class TestDalli < Test::Unit::TestCase 
     | 
|
| 
       382 
392 
     | 
    
         
             
                  end
         
     | 
| 
       383 
393 
     | 
    
         
             
                end
         
     | 
| 
       384 
394 
     | 
    
         | 
| 
      
 395 
     | 
    
         
            +
                context 'in low memory conditions' do
         
     | 
| 
      
 396 
     | 
    
         
            +
             
     | 
| 
      
 397 
     | 
    
         
            +
                  should 'handle error response correctly' do
         
     | 
| 
      
 398 
     | 
    
         
            +
                    memcached(19125, '-m 1 -M') do |dc|
         
     | 
| 
      
 399 
     | 
    
         
            +
                      failed = false
         
     | 
| 
      
 400 
     | 
    
         
            +
                      value = "1234567890"*100
         
     | 
| 
      
 401 
     | 
    
         
            +
                      1_000.times do |idx|
         
     | 
| 
      
 402 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 403 
     | 
    
         
            +
                          assert_equal true, dc.set(idx, value)
         
     | 
| 
      
 404 
     | 
    
         
            +
                        rescue Dalli::DalliError
         
     | 
| 
      
 405 
     | 
    
         
            +
                          failed = true
         
     | 
| 
      
 406 
     | 
    
         
            +
                          assert((800..900).include?(idx), "unexpected failure on iteration #{idx}")
         
     | 
| 
      
 407 
     | 
    
         
            +
                          break
         
     | 
| 
      
 408 
     | 
    
         
            +
                        end
         
     | 
| 
      
 409 
     | 
    
         
            +
                      end
         
     | 
| 
      
 410 
     | 
    
         
            +
                      assert failed, 'did not fail under low memory conditions'
         
     | 
| 
      
 411 
     | 
    
         
            +
                    end
         
     | 
| 
      
 412 
     | 
    
         
            +
                  end
         
     | 
| 
      
 413 
     | 
    
         
            +
             
     | 
| 
      
 414 
     | 
    
         
            +
                  should 'fit more values with compression' do
         
     | 
| 
      
 415 
     | 
    
         
            +
                    memcached(19126, '-m 1 -M') do |dc|
         
     | 
| 
      
 416 
     | 
    
         
            +
                      dalli = Dalli::Client.new('localhost:19126', :compression => true)
         
     | 
| 
      
 417 
     | 
    
         
            +
                      failed = false
         
     | 
| 
      
 418 
     | 
    
         
            +
                      value = "1234567890"*1000
         
     | 
| 
      
 419 
     | 
    
         
            +
                      10_000.times do |idx|
         
     | 
| 
      
 420 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 421 
     | 
    
         
            +
                          assert_equal true, dalli.set(idx, value)
         
     | 
| 
      
 422 
     | 
    
         
            +
                        rescue Dalli::DalliError
         
     | 
| 
      
 423 
     | 
    
         
            +
                          failed = true
         
     | 
| 
      
 424 
     | 
    
         
            +
                          assert((6000..7000).include?(idx), "unexpected failure on iteration #{idx}")
         
     | 
| 
      
 425 
     | 
    
         
            +
                          break
         
     | 
| 
      
 426 
     | 
    
         
            +
                        end
         
     | 
| 
      
 427 
     | 
    
         
            +
                      end
         
     | 
| 
      
 428 
     | 
    
         
            +
                      assert failed, 'did not fail under low memory conditions'
         
     | 
| 
      
 429 
     | 
    
         
            +
                    end
         
     | 
| 
      
 430 
     | 
    
         
            +
                  end
         
     | 
| 
      
 431 
     | 
    
         
            +
             
     | 
| 
      
 432 
     | 
    
         
            +
                end
         
     | 
| 
      
 433 
     | 
    
         
            +
             
     | 
| 
       385 
434 
     | 
    
         
             
              end
         
     | 
| 
       386 
435 
     | 
    
         
             
            end
         
     | 
    
        data/test/test_encoding.rb
    CHANGED
    
    
    
        data/test/test_network.rb
    CHANGED
    
    | 
         @@ -18,7 +18,7 @@ class TestNetwork < Test::Unit::TestCase 
     | 
|
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                  should 'handle connection reset' do
         
     | 
| 
       20 
20 
     | 
    
         
             
                    memcached_mock(lambda {|sock| sock.close }) do
         
     | 
| 
       21 
     | 
    
         
            -
                      assert_error Dalli::NetworkError, / 
     | 
| 
      
 21 
     | 
    
         
            +
                      assert_error Dalli::NetworkError, /Connection reset|end of file/ do
         
     | 
| 
       22 
22 
     | 
    
         
             
                        dc = Dalli::Client.new('localhost:19123')
         
     | 
| 
       23 
23 
     | 
    
         
             
                        dc.get('abc')
         
     | 
| 
       24 
24 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -27,7 +27,7 @@ class TestNetwork < Test::Unit::TestCase 
     | 
|
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
                  should 'handle malformed response' do
         
     | 
| 
       29 
29 
     | 
    
         
             
                    memcached_mock(lambda {|sock| sock.write('123') }) do
         
     | 
| 
       30 
     | 
    
         
            -
                      assert_error Dalli::NetworkError, / 
     | 
| 
      
 30 
     | 
    
         
            +
                      assert_error Dalli::NetworkError, /end of file/ do
         
     | 
| 
       31 
31 
     | 
    
         
             
                        dc = Dalli::Client.new('localhost:19123')
         
     | 
| 
       32 
32 
     | 
    
         
             
                        dc.get('abc')
         
     | 
| 
       33 
33 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -36,7 +36,7 @@ class TestNetwork < Test::Unit::TestCase 
     | 
|
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
                  should 'handle connect timeouts' do
         
     | 
| 
       38 
38 
     | 
    
         
             
                    memcached_mock(lambda {|sock| sleep(0.6); sock.close }, :delayed_start) do
         
     | 
| 
       39 
     | 
    
         
            -
                      assert_error Dalli::NetworkError, / 
     | 
| 
      
 39 
     | 
    
         
            +
                      assert_error Dalli::NetworkError, /IO timeout/ do
         
     | 
| 
       40 
40 
     | 
    
         
             
                        dc = Dalli::Client.new('localhost:19123')
         
     | 
| 
       41 
41 
     | 
    
         
             
                        dc.get('abc')
         
     | 
| 
       42 
42 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -45,7 +45,7 @@ class TestNetwork < Test::Unit::TestCase 
     | 
|
| 
       45 
45 
     | 
    
         | 
| 
       46 
46 
     | 
    
         
             
                  should 'handle read timeouts' do
         
     | 
| 
       47 
47 
     | 
    
         
             
                    memcached_mock(lambda {|sock| sleep(0.6); sock.write('giraffe') }) do
         
     | 
| 
       48 
     | 
    
         
            -
                      assert_error Dalli::NetworkError, / 
     | 
| 
      
 48 
     | 
    
         
            +
                      assert_error Dalli::NetworkError, /IO timeout/ do
         
     | 
| 
       49 
49 
     | 
    
         
             
                        dc = Dalli::Client.new('localhost:19123')
         
     | 
| 
       50 
50 
     | 
    
         
             
                        dc.get('abc')
         
     | 
| 
       51 
51 
     | 
    
         
             
                      end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version 
     | 
|
| 
       4 
4 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       5 
5 
     | 
    
         
             
              segments: 
         
     | 
| 
       6 
6 
     | 
    
         
             
              - 0
         
     | 
| 
       7 
     | 
    
         
            -
              -  
     | 
| 
       8 
     | 
    
         
            -
              -  
     | 
| 
       9 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 7 
     | 
    
         
            +
              - 11
         
     | 
| 
      
 8 
     | 
    
         
            +
              - 0
         
     | 
| 
      
 9 
     | 
    
         
            +
              version: 0.11.0
         
     | 
| 
       10 
10 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       11 
11 
     | 
    
         
             
            authors: 
         
     | 
| 
       12 
12 
     | 
    
         
             
            - Mike Perham
         
     | 
| 
         @@ -14,7 +14,7 @@ autorequire: 
     | 
|
| 
       14 
14 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       15 
15 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
            date: 2010- 
     | 
| 
      
 17 
     | 
    
         
            +
            date: 2010-11-03 00:00:00 -07:00
         
     | 
| 
       18 
18 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       19 
19 
     | 
    
         
             
            dependencies: 
         
     | 
| 
       20 
20 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     | 
| 
         @@ -54,8 +54,8 @@ dependencies: 
     | 
|
| 
       54 
54 
     | 
    
         
             
                    segments: 
         
     | 
| 
       55 
55 
     | 
    
         
             
                    - 3
         
     | 
| 
       56 
56 
     | 
    
         
             
                    - 0
         
     | 
| 
       57 
     | 
    
         
            -
                    -  
     | 
| 
       58 
     | 
    
         
            -
                    version: 3.0. 
     | 
| 
      
 57 
     | 
    
         
            +
                    - 1
         
     | 
| 
      
 58 
     | 
    
         
            +
                    version: 3.0.1
         
     | 
| 
       59 
59 
     | 
    
         
             
              type: :development
         
     | 
| 
       60 
60 
     | 
    
         
             
              version_requirements: *id003
         
     | 
| 
       61 
61 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     |