dalli 0.9.0
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 +3 -0
- data/LICENSE +20 -0
- data/Performance.md +24 -0
- data/README.md +75 -0
- data/Rakefile +7 -0
- data/dalli.gemspec +30 -0
- data/lib/active_support/cache/dalli_store.rb +177 -0
- data/lib/dalli.rb +25 -0
- data/lib/dalli/client.rb +122 -0
- data/lib/dalli/options.rb +70 -0
- data/lib/dalli/ring.rb +99 -0
- data/lib/dalli/server.rb +303 -0
- data/lib/dalli/version.rb +3 -0
- data/test/helper.rb +12 -0
- data/test/memcached_mock.rb +45 -0
- data/test/test_active_support.rb +75 -0
- data/test/test_benchmark.rb +118 -0
- data/test/test_dalli.rb +97 -0
- data/test/test_network.rb +59 -0
- metadata +130 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
require 'dalli'
|
6
|
+
|
7
|
+
class Test::Unit::TestCase
|
8
|
+
def assert_error(error, regexp=nil, &block)
|
9
|
+
ex = assert_raise(error, &block)
|
10
|
+
assert_match(regexp, ex.message, "#{ex.class.name}: #{ex.message}\n#{ex.backtrace.join("\n\t")}")
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module MemcachedMock
|
4
|
+
def self.start(port=22122, &block)
|
5
|
+
server = TCPServer.new("localhost", port)
|
6
|
+
session = server.accept
|
7
|
+
block.call session
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.delayed_start(port=22122, wait=1, &block)
|
11
|
+
server = TCPServer.new("localhost", port)
|
12
|
+
sleep wait
|
13
|
+
# session = server.accept
|
14
|
+
block.call server
|
15
|
+
end
|
16
|
+
|
17
|
+
module Helper
|
18
|
+
# Forks the current process and starts a new mock Memcached server on
|
19
|
+
# port 22122.
|
20
|
+
#
|
21
|
+
# memcached_mock(lambda {|sock| socket.write('123') }) do
|
22
|
+
# assert_equal "PONG", Dalli::Client.new('localhost:22122').get('abc')
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
def memcached_mock(proc, meth = :start)
|
26
|
+
begin
|
27
|
+
pid = fork do
|
28
|
+
trap("TERM") { exit }
|
29
|
+
|
30
|
+
MemcachedMock.send(meth) do |*args|
|
31
|
+
proc.call(*args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
sleep 0.5 # Give time for the socket to start listening.
|
36
|
+
yield
|
37
|
+
ensure
|
38
|
+
if pid
|
39
|
+
Process.kill("TERM", pid)
|
40
|
+
Process.wait(pid)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'active_support/all'
|
3
|
+
require 'active_support/cache/dalli_store'
|
4
|
+
|
5
|
+
class TestDalli < Test::Unit::TestCase
|
6
|
+
context 'activesupport caching' do
|
7
|
+
setup do
|
8
|
+
@dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:11211', :expires_in => 10.seconds)
|
9
|
+
@mc = ActiveSupport::Cache.lookup_store(:mem_cache_store, 'localhost:11211', :expires_in => 10.seconds, :namespace => 'a')
|
10
|
+
@dalli.clear
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'support fetch' do
|
14
|
+
dvalue = @mc.fetch('some key with spaces', :expires_in => 1.second) { 123 }
|
15
|
+
mvalue = @dalli.fetch('some other key with spaces', :expires_in => 1.second) { 123 }
|
16
|
+
assert_equal mvalue, dvalue
|
17
|
+
|
18
|
+
o = Object.new
|
19
|
+
o.instance_variable_set :@foo, 'bar'
|
20
|
+
dvalue = @mc.fetch(rand_key, :raw => true) { o }
|
21
|
+
mvalue = @dalli.fetch(rand_key, :raw => true) { o }
|
22
|
+
assert_equal mvalue, dvalue
|
23
|
+
assert_equal o, dvalue
|
24
|
+
|
25
|
+
dvalue = @mc.fetch(rand_key) { o }
|
26
|
+
mvalue = @dalli.fetch(rand_key) { o }
|
27
|
+
assert_equal mvalue, dvalue
|
28
|
+
assert_equal o, dvalue
|
29
|
+
end
|
30
|
+
|
31
|
+
should 'support read_multi' do
|
32
|
+
x = rand_key
|
33
|
+
y = rand_key
|
34
|
+
assert_equal({}, @mc.read_multi(x, y))
|
35
|
+
assert_equal({}, @dalli.read_multi(x, y))
|
36
|
+
@dalli.write(x, '123')
|
37
|
+
@dalli.write(y, 123)
|
38
|
+
@mc.write(x, '123')
|
39
|
+
@mc.write(y, 123)
|
40
|
+
assert_equal({ x => '123', y => 123 }, @dalli.read_multi(x, y))
|
41
|
+
assert_equal({ x => '123', y => 123 }, @mc.read_multi(x, y))
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'support read, write and delete' do
|
45
|
+
x = rand_key
|
46
|
+
y = rand_key
|
47
|
+
assert_nil @mc.read(x)
|
48
|
+
assert_nil @dalli.read(y)
|
49
|
+
mres = @mc.write(x, 123)
|
50
|
+
dres = @dalli.write(y, 123)
|
51
|
+
assert_equal mres, dres
|
52
|
+
|
53
|
+
mres = @mc.read(x)
|
54
|
+
dres = @dalli.read(y)
|
55
|
+
assert_equal mres, dres
|
56
|
+
assert_equal 123, dres
|
57
|
+
|
58
|
+
mres = @mc.delete(x)
|
59
|
+
dres = @dalli.delete(y)
|
60
|
+
assert_equal mres, dres
|
61
|
+
assert_equal true, dres
|
62
|
+
end
|
63
|
+
|
64
|
+
should 'support other esoteric commands' do
|
65
|
+
ms = @mc.stats
|
66
|
+
ds = @dalli.stats
|
67
|
+
assert_equal ms.keys.sort, ds.keys.sort
|
68
|
+
assert_equal ms[ms.keys.first].keys.sort, ds[ds.keys.first].keys.sort
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def rand_key
|
73
|
+
rand(1_000_000_000)
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
class TestBenchmark < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
puts "Testing #{Dalli::VERSION} with #{RUBY_DESCRIPTION}"
|
8
|
+
# We'll use a simple @value to try to avoid spending time in Marshal,
|
9
|
+
# which is a constant penalty that both clients have to pay
|
10
|
+
@value = []
|
11
|
+
@marshalled = Marshal.dump(@value)
|
12
|
+
|
13
|
+
@servers = ['127.0.0.1:11211', 'localhost:11211']
|
14
|
+
@key1 = "Short"
|
15
|
+
@key2 = "Sym1-2-3::45"*8
|
16
|
+
@key3 = "Long"*40
|
17
|
+
@key4 = "Medium"*8
|
18
|
+
# 5 and 6 are only used for multiget miss test
|
19
|
+
@key5 = "Medium2"*8
|
20
|
+
@key6 = "Long3"*40
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_benchmark
|
24
|
+
Benchmark.bm(31) do |x|
|
25
|
+
|
26
|
+
n = 2500
|
27
|
+
|
28
|
+
@m = Dalli::Client.new(@servers, :marshal => false)
|
29
|
+
x.report("set:plain:dalli") do
|
30
|
+
n.times do
|
31
|
+
@m.set @key1, @marshalled
|
32
|
+
@m.set @key2, @marshalled
|
33
|
+
@m.set @key3, @marshalled
|
34
|
+
@m.set @key1, @marshalled
|
35
|
+
@m.set @key2, @marshalled
|
36
|
+
@m.set @key3, @marshalled
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@m = Dalli::Client.new(@servers)
|
41
|
+
x.report("set:ruby:dalli") do
|
42
|
+
n.times do
|
43
|
+
@m.set @key1, @value
|
44
|
+
@m.set @key2, @value
|
45
|
+
@m.set @key3, @value
|
46
|
+
@m.set @key1, @value
|
47
|
+
@m.set @key2, @value
|
48
|
+
@m.set @key3, @value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@m = Dalli::Client.new(@servers, :marshal => false)
|
53
|
+
x.report("get:plain:dalli") do
|
54
|
+
n.times do
|
55
|
+
@m.get @key1
|
56
|
+
@m.get @key2
|
57
|
+
@m.get @key3
|
58
|
+
@m.get @key1
|
59
|
+
@m.get @key2
|
60
|
+
@m.get @key3
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
@m = Dalli::Client.new(@servers)
|
65
|
+
x.report("get:ruby:dalli") do
|
66
|
+
n.times do
|
67
|
+
@m.get @key1
|
68
|
+
@m.get @key2
|
69
|
+
@m.get @key3
|
70
|
+
@m.get @key1
|
71
|
+
@m.get @key2
|
72
|
+
@m.get @key3
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@m = Dalli::Client.new(@servers)
|
77
|
+
x.report("multiget:ruby:dalli") do
|
78
|
+
n.times do
|
79
|
+
# We don't use the keys array because splat is slow
|
80
|
+
@m.get_multi @key1, @key2, @key3, @key4, @key5, @key6
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
@m = Dalli::Client.new(@servers)
|
85
|
+
x.report("missing:ruby:dalli") do
|
86
|
+
n.times do
|
87
|
+
begin @m.delete @key1; rescue; end
|
88
|
+
begin @m.get @key1; rescue; end
|
89
|
+
begin @m.delete @key2; rescue; end
|
90
|
+
begin @m.get @key2; rescue; end
|
91
|
+
begin @m.delete @key3; rescue; end
|
92
|
+
begin @m.get @key3; rescue; end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
@m = Dalli::Client.new(@servers)
|
97
|
+
x.report("mixed:ruby:dalli") do
|
98
|
+
n.times do
|
99
|
+
@m.set @key1, @value
|
100
|
+
@m.set @key2, @value
|
101
|
+
@m.set @key3, @value
|
102
|
+
@m.get @key1
|
103
|
+
@m.get @key2
|
104
|
+
@m.get @key3
|
105
|
+
@m.set @key1, @value
|
106
|
+
@m.get @key1
|
107
|
+
@m.set @key2, @value
|
108
|
+
@m.get @key2
|
109
|
+
@m.set @key3, @value
|
110
|
+
@m.get @key3
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
assert true
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
data/test/test_dalli.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestDalli < Test::Unit::TestCase
|
4
|
+
context 'using a live server' do
|
5
|
+
setup do
|
6
|
+
begin
|
7
|
+
TCPSocket.new('localhost', 11211)
|
8
|
+
rescue => ex
|
9
|
+
$skip = true
|
10
|
+
puts "Skipping live test as memcached is not running at localhost:11211. Start it with 'memcached -d'"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
should "support huge get/set" do
|
15
|
+
return if $skip
|
16
|
+
dc = Dalli::Client.new('localhost:11211')
|
17
|
+
dc.flush
|
18
|
+
|
19
|
+
val1 = "1234567890"*105000
|
20
|
+
assert_error Dalli::DalliError, /too large/ do
|
21
|
+
dc.set('a', val1)
|
22
|
+
val2 = dc.get('a')
|
23
|
+
assert_equal val1, val2
|
24
|
+
end
|
25
|
+
|
26
|
+
val1 = "1234567890"*100000
|
27
|
+
dc.set('a', val1)
|
28
|
+
val2 = dc.get('a')
|
29
|
+
assert_equal val1, val2
|
30
|
+
end
|
31
|
+
|
32
|
+
should "support multi-get" do
|
33
|
+
return if $skip
|
34
|
+
dc = Dalli::Client.new(['localhost:11211', '127.0.0.1'])
|
35
|
+
dc.flush
|
36
|
+
resp = dc.get_multi(%w(a b c d e f))
|
37
|
+
assert_equal({}, resp)
|
38
|
+
|
39
|
+
dc.set('a', 'foo')
|
40
|
+
dc.set('b', 123)
|
41
|
+
dc.set('c', %w(a b c))
|
42
|
+
resp = dc.get_multi(%w(a b c d e f))
|
43
|
+
assert_equal({ 'a' => 'foo', 'b' => 123, 'c' => %w(a b c) }, resp)
|
44
|
+
end
|
45
|
+
|
46
|
+
should "pass a simple smoke test" do
|
47
|
+
return if $skip
|
48
|
+
|
49
|
+
dc = Dalli::Client.new('localhost:11211')
|
50
|
+
resp = dc.flush
|
51
|
+
assert_not_nil resp
|
52
|
+
assert_equal [true], resp
|
53
|
+
|
54
|
+
resp = dc.get('123')
|
55
|
+
assert_equal nil, resp
|
56
|
+
|
57
|
+
resp = dc.set('123', 'xyz')
|
58
|
+
assert_equal true, resp
|
59
|
+
|
60
|
+
resp = dc.get('123')
|
61
|
+
assert_equal 'xyz', resp
|
62
|
+
|
63
|
+
resp = dc.set('123', 'abc')
|
64
|
+
assert_equal true, resp
|
65
|
+
|
66
|
+
assert_raises Dalli::DalliError do
|
67
|
+
dc.prepend('123', '0')
|
68
|
+
end
|
69
|
+
|
70
|
+
assert_raises Dalli::DalliError do
|
71
|
+
dc.append('123', '0')
|
72
|
+
end
|
73
|
+
|
74
|
+
resp = dc.get('123')
|
75
|
+
assert_equal 'abc', resp
|
76
|
+
dc.close
|
77
|
+
dc = nil
|
78
|
+
|
79
|
+
dc = Dalli::Client.new('localhost:11211', :marshal => false)
|
80
|
+
|
81
|
+
resp = dc.set('456', 'xyz')
|
82
|
+
assert_equal true, resp
|
83
|
+
|
84
|
+
resp = dc.prepend '456', '0'
|
85
|
+
assert_equal true, resp
|
86
|
+
|
87
|
+
resp = dc.append '456', '9'
|
88
|
+
assert_equal true, resp
|
89
|
+
|
90
|
+
resp = dc.get('456')
|
91
|
+
assert_equal '0xyz9', resp
|
92
|
+
|
93
|
+
resp = dc.stats
|
94
|
+
assert_equal Hash, resp.class
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'memcached_mock'
|
3
|
+
|
4
|
+
class TestNetwork < Test::Unit::TestCase
|
5
|
+
|
6
|
+
include MemcachedMock::Helper
|
7
|
+
|
8
|
+
context 'assuming a bad network' do
|
9
|
+
|
10
|
+
should 'handle connection refused' do
|
11
|
+
assert_raise Dalli::NetworkError do
|
12
|
+
dc = Dalli::Client.new 'localhost:19122'
|
13
|
+
dc.get 'foo'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with a fake server' do
|
18
|
+
|
19
|
+
should 'handle connection reset' do
|
20
|
+
memcached_mock(lambda {|sock| sock.close }) do
|
21
|
+
assert_error Dalli::NetworkError, /ECONNRESET/ do
|
22
|
+
dc = Dalli::Client.new('localhost:22122')
|
23
|
+
dc.get('abc')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'handle malformed response' do
|
29
|
+
memcached_mock(lambda {|sock| sock.write('123') }) do
|
30
|
+
assert_error Dalli::NetworkError, /EOFError/ do
|
31
|
+
dc = Dalli::Client.new('localhost:22122')
|
32
|
+
dc.get('abc')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
should 'handle connect timeouts' do
|
38
|
+
memcached_mock(lambda {|sock| sleep(0.6); sock.close }, :delayed_start) do
|
39
|
+
assert_error Dalli::NetworkError, /Timeout::Error/ do
|
40
|
+
dc = Dalli::Client.new('localhost:22122')
|
41
|
+
dc.get('abc')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
should 'handle read timeouts' do
|
48
|
+
memcached_mock(lambda {|sock| sleep(0.6); sock.write('giraffe') }) do
|
49
|
+
assert_error Dalli::NetworkError, /Timeout::Error/ do
|
50
|
+
dc = Dalli::Client.new('localhost:22122')
|
51
|
+
dc.get('abc')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dalli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 9
|
8
|
+
- 0
|
9
|
+
version: 0.9.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Mike Perham
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-08-19 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: shoulda
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :development
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rails
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 3
|
43
|
+
- 0
|
44
|
+
- 0
|
45
|
+
- rc
|
46
|
+
version: 3.0.0.rc
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: memcache-client
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 1
|
59
|
+
- 8
|
60
|
+
- 5
|
61
|
+
version: 1.8.5
|
62
|
+
type: :development
|
63
|
+
version_requirements: *id003
|
64
|
+
description: High performance memcached client for Ruby
|
65
|
+
email: mperham@gmail.com
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- lib/active_support/cache/dalli_store.rb
|
74
|
+
- lib/dalli/client.rb
|
75
|
+
- lib/dalli/options.rb
|
76
|
+
- lib/dalli/ring.rb
|
77
|
+
- lib/dalli/server.rb
|
78
|
+
- lib/dalli/version.rb
|
79
|
+
- lib/dalli.rb
|
80
|
+
- LICENSE
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- Gemfile
|
84
|
+
- dalli.gemspec
|
85
|
+
- Performance.md
|
86
|
+
- test/helper.rb
|
87
|
+
- test/memcached_mock.rb
|
88
|
+
- test/test_active_support.rb
|
89
|
+
- test/test_benchmark.rb
|
90
|
+
- test/test_dalli.rb
|
91
|
+
- test/test_network.rb
|
92
|
+
has_rdoc: true
|
93
|
+
homepage: http://github.com/mperham/dalli
|
94
|
+
licenses: []
|
95
|
+
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options:
|
98
|
+
- --charset=UTF-8
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
requirements: []
|
118
|
+
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 1.3.7
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: High performance memcached client for Ruby
|
124
|
+
test_files:
|
125
|
+
- test/helper.rb
|
126
|
+
- test/memcached_mock.rb
|
127
|
+
- test/test_active_support.rb
|
128
|
+
- test/test_benchmark.rb
|
129
|
+
- test/test_dalli.rb
|
130
|
+
- test/test_network.rb
|