dalli 2.6.0 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of dalli might be problematic. Click here for more details.

data/Gemfile CHANGED
@@ -4,6 +4,7 @@ gemspec
4
4
 
5
5
  gem 'rake'
6
6
  gem 'kgio', :platform => :mri
7
+ gem 'RubyInline', :platform => :mri
7
8
 
8
9
  group :test do
9
10
  gem 'simplecov'
data/History.md CHANGED
@@ -1,6 +1,19 @@
1
1
  Dalli Changelog
2
2
  =====================
3
3
 
4
+ 2.6.1
5
+ =======
6
+
7
+ - Add optional native C binary search for ring, add:
8
+
9
+ gem 'RubyInline'
10
+
11
+ to your Gemfile to get a 10% speedup when using many servers.
12
+ You will see no improvement if you are only using one server.
13
+
14
+ - More get_multi performance optimization [xaop, #315]
15
+ - Add lambda support for cache namespaces [joshwlewis, #311]
16
+
4
17
  2.6.0
5
18
  =======
6
19
 
data/README.md CHANGED
@@ -55,12 +55,14 @@ On Ubuntu you can install it by running:
55
55
 
56
56
  You can verify your installation using this piece of code:
57
57
 
58
- gem install dalli
58
+ ```ruby
59
+ gem install dalli
59
60
 
60
- require 'dalli'
61
- dc = Dalli::Client.new('localhost:11211')
62
- dc.set('abc', 123)
63
- value = dc.get('abc')
61
+ require 'dalli'
62
+ dc = Dalli::Client.new('localhost:11211')
63
+ dc.set('abc', 123)
64
+ value = dc.get('abc')
65
+ ```
64
66
 
65
67
  The test suite requires memcached 1.4.3+ with SASL enabled (brew install memcached --enable-sasl ; mv /usr/bin/memcached /usr/bin/memcached.old). Currently only supports the PLAIN mechanism.
66
68
 
@@ -73,27 +75,37 @@ Usage with Rails 3.x
73
75
 
74
76
  In your Gemfile:
75
77
 
76
- gem 'dalli'
78
+ ```ruby
79
+ gem 'dalli'
80
+ ```
77
81
 
78
82
  In `config/environments/production.rb`:
79
83
 
80
- config.cache_store = :dalli_store
84
+ ```ruby
85
+ config.cache_store = :dalli_store
86
+ ```
81
87
 
82
88
  Here's a more comprehensive example that sets a reasonable default for maximum cache entry lifetime (one day), enables compression for large values and namespaces all entries for this rails app. Remove the namespace if you have multiple apps which share cached values.
83
89
 
84
- config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com',
85
- { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
90
+ ```ruby
91
+ config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com',
92
+ { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
93
+ ```
86
94
 
87
95
  To use Dalli for Rails session storage that times out after 20 minutes, in `config/initializers/session_store.rb`:
88
96
 
89
97
  For Rails >= 3.2.4:
90
98
 
91
- Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 20.minutes
99
+ ```ruby
100
+ Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 20.minutes
101
+ ```
92
102
 
93
103
  For Rails 3.x:
94
104
 
95
- require 'action_dispatch/middleware/session/dalli_store'
96
- Rails.application.config.session_store :dalli_store, :memcache_server => ['host1', 'host2'], :namespace => 'sessions', :key => '_foundation_session', :expire_after => 20.minutes
105
+ ```ruby
106
+ require 'action_dispatch/middleware/session/dalli_store'
107
+ Rails.application.config.session_store :dalli_store, :memcache_server => ['host1', 'host2'], :namespace => 'sessions', :key => '_foundation_session', :expire_after => 20.minutes
108
+ ```
97
109
 
98
110
  Dalli does not support Rails 2.x.
99
111
 
@@ -146,6 +158,7 @@ socket.
146
158
 
147
159
  Note that Dalli does not require ActiveSupport or Rails. You can safely use it in your own Ruby projects.
148
160
 
161
+ ![View the API](http://www.ruby-doc.org/gems/docs/d/dalli-2.5.0/Dalli/Client.html)
149
162
 
150
163
  Helping Out
151
164
  -------------
@@ -340,19 +340,22 @@ module Dalli
340
340
  raise ArgumentError, "key cannot be blank" if !key || key.length == 0
341
341
  key = key_with_namespace(key)
342
342
  if key.length > 250
343
- namespace_length = @options[:namespace] ? @options[:namespace].size : 0
344
- max_length_before_namespace = 212 - namespace_length
343
+ max_length_before_namespace = 212 - (namespace || '').size
345
344
  key = "#{key[0, max_length_before_namespace]}:md5:#{Digest::MD5.hexdigest(key)}"
346
345
  end
347
346
  return key
348
347
  end
349
348
 
350
349
  def key_with_namespace(key)
351
- @options[:namespace] ? "#{@options[:namespace]}:#{key}" : key
350
+ (ns = namespace) ? "#{ns}:#{key}" : key
352
351
  end
353
352
 
354
353
  def key_without_namespace(key)
355
- @options[:namespace] ? key.sub(%r(\A#{@options[:namespace]}:), '') : key
354
+ (ns = namespace) ? key.sub(%r(\A#{ns}:), '') : key
355
+ end
356
+
357
+ def namespace
358
+ @options[:namespace].is_a?(Proc) ? @options[:namespace].call : @options[:namespace]
356
359
  end
357
360
 
358
361
  def normalize_options(opts)
@@ -31,7 +31,7 @@ module Dalli
31
31
  if @continuum
32
32
  hkey = hash_for(key)
33
33
  20.times do |try|
34
- entryidx = self.class.binary_search(@continuum, hkey)
34
+ entryidx = binary_search(@continuum, hkey)
35
35
  server = @continuum[entryidx].server
36
36
  return server if server.alive?
37
37
  break unless @failover
@@ -70,25 +70,60 @@ module Dalli
70
70
  ((total_servers * POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor
71
71
  end
72
72
 
73
- # Find the closest index in the Ring with value <= the given value
74
- def self.binary_search(ary, value)
75
- upper = ary.size - 1
76
- lower = 0
77
- idx = 0
78
-
79
- while (lower <= upper) do
80
- idx = (lower + upper) / 2
81
- comp = ary[idx].value <=> value
82
-
83
- if comp == 0
84
- return idx
85
- elsif comp > 0
86
- upper = idx - 1
87
- else
88
- lower = idx + 1
73
+ # Native extension to perform the binary search within the continuum
74
+ # space. Fallback to a pure Ruby version if the compilation doesn't work.
75
+ # optional for performance and only necessary if you are using multiple
76
+ # memcached servers.
77
+ begin
78
+ require 'inline'
79
+ inline do |builder|
80
+ builder.c <<-EOM
81
+ int binary_search(VALUE ary, unsigned int r) {
82
+ int upper = RARRAY_LEN(ary) - 1;
83
+ int lower = 0;
84
+ int idx = 0;
85
+ ID value = rb_intern("value");
86
+
87
+ while (lower <= upper) {
88
+ idx = (lower + upper) / 2;
89
+
90
+ VALUE continuumValue = rb_funcall(RARRAY_PTR(ary)[idx], value, 0);
91
+ unsigned int l = NUM2UINT(continuumValue);
92
+ if (l == r) {
93
+ return idx;
94
+ }
95
+ else if (l > r) {
96
+ upper = idx - 1;
97
+ }
98
+ else {
99
+ lower = idx + 1;
100
+ }
101
+ }
102
+ return upper;
103
+ }
104
+ EOM
105
+ end
106
+ rescue
107
+ # Find the closest index in the Ring with value <= the given value
108
+ def binary_search(ary, value)
109
+ upper = ary.size - 1
110
+ lower = 0
111
+ idx = 0
112
+
113
+ while (lower <= upper) do
114
+ idx = (lower + upper) / 2
115
+ comp = ary[idx].value <=> value
116
+
117
+ if comp == 0
118
+ return idx
119
+ elsif comp > 0
120
+ upper = idx - 1
121
+ else
122
+ lower = idx + 1
123
+ end
89
124
  end
125
+ return upper
90
126
  end
91
- return upper
92
127
  end
93
128
 
94
129
  class Entry
@@ -116,6 +116,7 @@ module Dalli
116
116
  verify_state
117
117
  write_noop
118
118
  @multi_buffer = ''
119
+ @position = 0
119
120
  @inprogress = true
120
121
  end
121
122
 
@@ -135,23 +136,26 @@ module Dalli
135
136
 
136
137
  @multi_buffer << @sock.read_available
137
138
  buf = @multi_buffer
139
+ pos = @position
138
140
  values = {}
139
141
 
140
- while buf.bytesize >= 24
141
- header = buf.slice(0, 24)
142
+ while buf.bytesize - pos >= 24
143
+ header = buf.slice(pos, 24)
142
144
  (key_length, _, body_length) = header.unpack(KV_HEADER)
143
145
 
144
146
  if key_length == 0
145
147
  # all done!
146
148
  @multi_buffer = nil
149
+ @position = nil
147
150
  @inprogress = false
148
151
  break
149
152
 
150
- elsif buf.bytesize >= (24 + body_length)
151
- buf.slice!(0, 24)
152
- flags = buf.slice!(0, 4).unpack('N')[0]
153
- key = buf.slice!(0, key_length)
154
- value = buf.slice!(0, body_length - key_length - 4) if body_length - key_length - 4 > 0
153
+ elsif buf.bytesize - pos >= 24 + body_length
154
+ flags = buf.slice(pos + 24, 4).unpack('N')[0]
155
+ key = buf.slice(pos + 24 + 4, key_length)
156
+ value = buf.slice(pos + 24 + 4 + key_length, body_length - key_length - 4) if body_length - key_length - 4 > 0
157
+
158
+ pos = pos + 24 + body_length
155
159
 
156
160
  begin
157
161
  values[key] = deserialize(value, flags)
@@ -163,6 +167,7 @@ module Dalli
163
167
  break
164
168
  end
165
169
  end
170
+ @position = pos
166
171
 
167
172
  values
168
173
  rescue SystemCallError, Timeout::Error, EOFError
@@ -176,6 +181,7 @@ module Dalli
176
181
  # Returns nothing.
177
182
  def multi_response_abort
178
183
  @multi_buffer = nil
184
+ @position = nil
179
185
  @inprogress = false
180
186
  failure!
181
187
  rescue NetworkError
@@ -1,3 +1,3 @@
1
1
  module Dalli
2
- VERSION = '2.6.0'
2
+ VERSION = '2.6.1'
3
3
  end
@@ -329,7 +329,7 @@ describe 'ActiveSupport' do
329
329
  end
330
330
 
331
331
  def connect
332
- @dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => 'x')
332
+ @dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => lambda{33.to_s(36)})
333
333
  @dalli.clear
334
334
  end
335
335
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dalli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.0
4
+ version: 2.6.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-15 00:00:00.000000000 Z
12
+ date: 2013-01-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mini_shoulda