dalli 0.9.8 → 0.9.9

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/History.md CHANGED
@@ -1,6 +1,23 @@
1
1
  Dalli Changelog
2
2
  =====================
3
3
 
4
+ 0.9.9
5
+ ----
6
+
7
+ - Add support for *_multi operations for add, set, replace and delete. This implements
8
+ pipelined network operations; Dalli disables network replies so we're not limited by
9
+ latency, allowing for much higher throughput.
10
+
11
+ dc = Dalli::Client.new
12
+ dc.multi do
13
+ dc.set 'a', 1
14
+ dc.set 'b', 2
15
+ dc.set 'c', 3
16
+ dc.delete 'd'
17
+ end
18
+ - Minor fix to set the continuum sorted by value.
19
+ - Implement session store with Rails 2.3. Update docs.
20
+
4
21
  0.9.8
5
22
  -----
6
23
 
data/README.md CHANGED
@@ -61,6 +61,11 @@ A more comprehensive example (note that we are setting a reasonable default for
61
61
  config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com',
62
62
  :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true, :compress_threshold => 64.kilobytes
63
63
 
64
+ In `config/initializers/session_store.rb`:
65
+
66
+ require 'action_dispatch/middleware/session/dalli_store'
67
+ Rails.application.config.session_store :dalli_store, :key => ...
68
+
64
69
 
65
70
  Usage with Rails 2.3.x
66
71
  ----------------------------
@@ -71,9 +76,16 @@ In `config/environment.rb`:
71
76
 
72
77
  In `config/environments/production.rb`:
73
78
 
79
+ # Object cache
74
80
  require 'active_support/cache/dalli_store23'
75
81
  config.cache_store = :dalli_store
76
82
 
83
+ In `config/initializers/session_store.rb`:
84
+
85
+ # Session cache
86
+ require 'action_controller/session/dalli_store'
87
+ ActionController::Base.session_store = :dalli_store
88
+
77
89
 
78
90
  Usage with Passenger
79
91
  ------------------------
data/TODO.md CHANGED
@@ -2,6 +2,4 @@ TODO
2
2
  ========
3
3
 
4
4
  * More of the memcached instruction set. This will be done based on user demand. Email me if the API is missing a feature you'd like to use.
5
- * Better API documentation
6
- * Add noreply support for all commands
7
- * Better pipelining support
5
+ * Better API documentation
@@ -0,0 +1,57 @@
1
+ # Session store for Rails 2.3.x
2
+ # Tested against 2.3.9.
3
+ begin
4
+ require_library_or_gem 'dalli'
5
+
6
+ module ActionController
7
+ module Session
8
+ class DalliStore < AbstractStore
9
+ def initialize(app, options = {})
10
+ # Support old :expires option
11
+ options[:expire_after] ||= options[:expires]
12
+
13
+ super
14
+
15
+ @default_options = {
16
+ :namespace => 'rack:session',
17
+ :memcache_server => 'localhost:11211'
18
+ }.merge(@default_options)
19
+
20
+ @pool = Dalli::Client.new(@default_options[:memcache_server], @default_options)
21
+ super
22
+ end
23
+
24
+ private
25
+ def get_session(env, sid)
26
+ sid ||= generate_sid
27
+ begin
28
+ session = @pool.get(sid) || {}
29
+ rescue Dalli::DalliError
30
+ session = {}
31
+ end
32
+ [sid, session]
33
+ end
34
+
35
+ def set_session(env, sid, session_data)
36
+ options = env['rack.session.options']
37
+ expiry = options[:expire_after] || 0
38
+ @pool.set(sid, session_data, expiry)
39
+ return true
40
+ rescue Dalli::DalliError
41
+ return false
42
+ end
43
+
44
+ def destroy(env)
45
+ if sid = current_session_id(env)
46
+ @pool.delete(sid)
47
+ end
48
+ rescue Dalli::DalliError
49
+ false
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+ rescue LoadError
56
+ # Dalli wasn't available so neither can the store be
57
+ end
@@ -18,7 +18,6 @@ module ActionDispatch
18
18
  @default_options = {
19
19
  :namespace => 'rack:session',
20
20
  :memcache_server => 'localhost:11211',
21
- :expires_in => options[:expire_after]
22
21
  }.merge(@default_options)
23
22
 
24
23
  @pool = options[:cache] || begin
@@ -36,16 +35,11 @@ module ActionDispatch
36
35
 
37
36
  private
38
37
 
39
- def session_key(sid)
40
- # Dalli does not support namespaces directly so we have
41
- # to roll our own.
42
- @namespace ? "#{@namespace}:#{sid}" : sid
43
- end
44
-
45
38
  def get_session(env, sid)
39
+ sid ||= generate_sid
46
40
  begin
47
- session = @pool.get(session_key(sid)) || {}
48
- rescue Dalli::DalliError => de
41
+ session = @pool.get(sid) || {}
42
+ rescue Dalli::DalliError
49
43
  Rails.logger.warn("Session::DalliStore: #{$!.message}")
50
44
  session = {}
51
45
  end
@@ -55,7 +49,7 @@ module ActionDispatch
55
49
  def set_session(env, sid, session_data)
56
50
  options = env['rack.session.options']
57
51
  expiry = options[:expire_after] || 0
58
- @pool.set(session_key(sid), session_data, expiry)
52
+ @pool.set(sid, session_data, expiry)
59
53
  sid
60
54
  rescue Dalli::DalliError
61
55
  Rails.logger.warn("Session::DalliStore: #{$!.message}")
@@ -64,7 +58,7 @@ module ActionDispatch
64
58
 
65
59
  def destroy(env)
66
60
  if sid = current_session_id(env)
67
- @pool.delete(session_key(sid))
61
+ @pool.delete(sid)
68
62
  end
69
63
  rescue Dalli::DalliError
70
64
  Rails.logger.warn("Session::DalliStore: #{$!.message}")
data/lib/dalli/client.rb CHANGED
@@ -24,6 +24,18 @@ module Dalli
24
24
  # The standard memcached instruction set
25
25
  #
26
26
 
27
+ ##
28
+ # Turn on quiet aka noreply support.
29
+ # All relevant operations within this block with be effectively
30
+ # pipelined as Dalli will use 'quiet' operations where possible.
31
+ # Currently supports the set, add, replace and delete operations.
32
+ def multi
33
+ Thread.current[:multi] = true
34
+ yield
35
+ ensure
36
+ Thread.current[:multi] = nil
37
+ end
38
+
27
39
  def get(key, options=nil)
28
40
  resp = perform(:get, key)
29
41
  (!resp || resp == 'Not found') ? nil : deserialize(resp, options)
@@ -163,7 +175,7 @@ module Dalli
163
175
  # Chokepoint method for instrumentation
164
176
  def perform(op, *args)
165
177
  key = args.first
166
- if key.is_a?(Symbol)
178
+ if !key.is_a?(String)
167
179
  key = key.to_s
168
180
  args[0] = key
169
181
  end
data/lib/dalli/ring.rb CHANGED
@@ -20,8 +20,7 @@ module Dalli
20
20
  continuum << Dalli::Ring::Entry.new(value, server)
21
21
  end
22
22
  end
23
- continuum.sort { |a, b| a.value <=> b.value }
24
- @continuum = continuum
23
+ @continuum = continuum.sort { |a, b| a.value <=> b.value }
25
24
  end
26
25
 
27
26
  threadsafe! unless options[:threadsafe] == false
data/lib/dalli/server.rb CHANGED
@@ -73,6 +73,10 @@ module Dalli
73
73
  nil
74
74
  end
75
75
 
76
+ def multi?
77
+ Thread.current[:multi]
78
+ end
79
+
76
80
  ONE_MB = 1024 * 1024
77
81
 
78
82
  def get(key)
@@ -89,9 +93,9 @@ module Dalli
89
93
  def set(key, value, ttl)
90
94
  raise Dalli::DalliError, "Value too large, memcached can only store 1MB of data per key" if value.size > ONE_MB
91
95
 
92
- req = [REQUEST, OPCODES[:set], key.size, 8, 0, 0, value.size + key.size + 8, 0, 0, 0, ttl, key, value].pack(FORMAT[:set])
96
+ req = [REQUEST, OPCODES[multi? ? :setq : :set], key.size, 8, 0, 0, value.size + key.size + 8, 0, 0, 0, ttl, key, value].pack(FORMAT[:set])
93
97
  write(req)
94
- generic_response
98
+ generic_response unless multi?
95
99
  end
96
100
 
97
101
  def flush(ttl)
@@ -103,9 +107,9 @@ module Dalli
103
107
  def add(key, value, ttl, cas)
104
108
  raise Dalli::DalliError, "Value too large, memcached can only store 1MB of data per key" if value.size > ONE_MB
105
109
 
106
- req = [REQUEST, OPCODES[:add], key.size, 8, 0, 0, value.size + key.size + 8, 0, cas, 0, ttl, key, value].pack(FORMAT[:add])
110
+ req = [REQUEST, OPCODES[multi? ? :addq : :add], key.size, 8, 0, 0, value.size + key.size + 8, 0, cas, 0, ttl, key, value].pack(FORMAT[:add])
107
111
  write(req)
108
- generic_response
112
+ generic_response unless multi?
109
113
  end
110
114
 
111
115
  def append(key, value)
@@ -115,9 +119,9 @@ module Dalli
115
119
  end
116
120
 
117
121
  def delete(key)
118
- req = [REQUEST, OPCODES[:delete], key.size, 0, 0, 0, key.size, 0, 0, key].pack(FORMAT[:delete])
122
+ req = [REQUEST, OPCODES[multi? ? :deleteq : :delete], key.size, 0, 0, 0, key.size, 0, 0, key].pack(FORMAT[:delete])
119
123
  write(req)
120
- generic_response
124
+ generic_response unless multi?
121
125
  end
122
126
 
123
127
  def decr(key, count, ttl, default)
@@ -157,9 +161,9 @@ module Dalli
157
161
  end
158
162
 
159
163
  def replace(key, value, ttl)
160
- req = [REQUEST, OPCODES[:replace], key.size, 8, 0, 0, value.size + key.size + 8, 0, 0, 0, ttl, key, value].pack(FORMAT[:replace])
164
+ req = [REQUEST, OPCODES[multi? ? :replaceq : :replace], key.size, 8, 0, 0, value.size + key.size + 8, 0, 0, 0, ttl, key, value].pack(FORMAT[:replace])
161
165
  write(req)
162
- generic_response
166
+ generic_response unless multi?
163
167
  end
164
168
 
165
169
  def stats(info='')
@@ -351,6 +355,12 @@ module Dalli
351
355
  :append => 0x0E,
352
356
  :prepend => 0x0F,
353
357
  :stat => 0x10,
358
+ :setq => 0x11,
359
+ :addq => 0x12,
360
+ :replaceq => 0x13,
361
+ :deleteq => 0x14,
362
+ :incrq => 0x15,
363
+ :decrq => 0x16,
354
364
  :auth_negotiation => 0x20,
355
365
  :auth_request => 0x21,
356
366
  :auth_continue => 0x22,
data/lib/dalli/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dalli
2
- VERSION = '0.9.8'
2
+ VERSION = '0.9.9'
3
3
  end
@@ -40,6 +40,20 @@ class TestBenchmark < Test::Unit::TestCase
40
40
  end
41
41
  end
42
42
 
43
+ @m = Dalli::Client.new(@servers)
44
+ x.report("setq:plain:dalli") do
45
+ @m.multi do
46
+ n.times do
47
+ @m.set @key1, @marshalled, 0, :raw => true
48
+ @m.set @key2, @marshalled, 0, :raw => true
49
+ @m.set @key3, @marshalled, 0, :raw => true
50
+ @m.set @key1, @marshalled, 0, :raw => true
51
+ @m.set @key2, @marshalled, 0, :raw => true
52
+ @m.set @key3, @marshalled, 0, :raw => true
53
+ end
54
+ end
55
+ end
56
+
43
57
  @m = Dalli::Client.new(@servers)
44
58
  x.report("set:ruby:dalli") do
45
59
  n.times do
@@ -114,6 +128,29 @@ class TestBenchmark < Test::Unit::TestCase
114
128
  end
115
129
  end
116
130
 
131
+ @m = Dalli::Client.new(@servers)
132
+ x.report("mixedq:ruby:dalli") do
133
+ @m.multi do
134
+ n.times do
135
+ @m.set @key1, @value
136
+ @m.set @key2, @value
137
+ @m.set @key3, @value
138
+ @m.get @key1
139
+ @m.get @key2
140
+ @m.get @key3
141
+ @m.set @key1, @value
142
+ @m.get @key1
143
+ @m.set @key2, @value
144
+ @m.replace @key2, @value
145
+ @m.delete @key3
146
+ @m.add @key3, @value
147
+ @m.get @key2
148
+ @m.set @key3, @value
149
+ @m.get @key3
150
+ end
151
+ end
152
+ end
153
+
117
154
  @m = Dalli::Client.new(@servers)
118
155
  x.report("incr:ruby:dalli") do
119
156
  n.times do
data/test/test_dalli.rb CHANGED
@@ -26,6 +26,17 @@ class TestDalli < Test::Unit::TestCase
26
26
  assert_equal s2, s3
27
27
  end
28
28
 
29
+ should "have the continuum sorted by value" do
30
+ servers = [stub(:hostname => "localhost", :port => "11211", :weight => 1),
31
+ stub(:hostname => "localhost", :port => "9500", :weight => 1)]
32
+ ring = Dalli::Ring.new(servers, {})
33
+ previous_value = 0
34
+ ring.continuum.each do |entry|
35
+ assert entry.value > previous_value
36
+ previous_value = entry.value
37
+ end
38
+ end
39
+
29
40
  context 'using a live server' do
30
41
 
31
42
  should "support get/set" do
@@ -110,6 +121,19 @@ class TestDalli < Test::Unit::TestCase
110
121
  dc.set('c', %w(a b c))
111
122
  resp = dc.get_multi(%w(a b c d e f))
112
123
  assert_equal({ 'a' => 'foo', 'b' => 123, 'c' => %w(a b c) }, resp)
124
+
125
+ # Perform a huge multi-get with 10,000 elements.
126
+ arr = []
127
+ dc.multi do
128
+ 10_000.times do |idx|
129
+ dc.set idx, idx
130
+ arr << idx
131
+ end
132
+ end
133
+
134
+ result = dc.get_multi(arr)
135
+ assert_equal(10_000, result.size)
136
+ assert_equal(1000, result['1000'])
113
137
  end
114
138
  end
115
139
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 8
9
- version: 0.9.8
8
+ - 9
9
+ version: 0.9.9
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-09-29 00:00:00 -07:00
17
+ date: 2010-10-06 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -82,6 +82,7 @@ extensions: []
82
82
  extra_rdoc_files: []
83
83
 
84
84
  files:
85
+ - lib/action_controller/session/dalli_store.rb
85
86
  - lib/action_dispatch/middleware/session/dalli_store.rb
86
87
  - lib/active_support/cache/dalli_store.rb
87
88
  - lib/active_support/cache/dalli_store23.rb