connection_pool 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes.md +17 -0
- data/README.md +35 -13
- data/Rakefile +5 -2
- data/connection_pool.gemspec +1 -1
- data/lib/connection_pool.rb +23 -9
- data/lib/connection_pool/version.rb +1 -1
- data/lib/timed_queue.rb +1 -1
- data/test/helper.rb +4 -2
- data/test/test_connection_pool.rb +27 -2
- metadata +4 -4
data/Changes.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
0.9.3
|
2
|
+
--------
|
3
|
+
|
4
|
+
- `#with_connection` is now deprecated in favor of `#with`.
|
5
|
+
|
6
|
+
A warning will be issued in the 0.9 series and the method will be
|
7
|
+
removed in 1.0.
|
8
|
+
|
9
|
+
- We now reuse objects when possible.
|
10
|
+
|
11
|
+
This means that under no contention, the same object will be checked
|
12
|
+
out from the pool after subsequent calls to `ConnectionPool#with`.
|
13
|
+
|
14
|
+
This change should have no impact on end user performance. If
|
15
|
+
anything, it should be an improvement, depending on what objects you
|
16
|
+
are pooling.
|
17
|
+
|
1
18
|
0.9.2
|
2
19
|
--------
|
3
20
|
|
data/README.md
CHANGED
@@ -11,35 +11,57 @@ Install
|
|
11
11
|
|
12
12
|
gem install connection_pool
|
13
13
|
|
14
|
+
|
15
|
+
Notes
|
16
|
+
------------
|
17
|
+
|
18
|
+
- Connections are eager created when the pool is created.
|
19
|
+
- There is no provision for repairing or checking the health of a
|
20
|
+
connection; connections should be self-repairing. This is
|
21
|
+
true of the dalli and redis clients.
|
22
|
+
|
23
|
+
|
14
24
|
Usage
|
15
25
|
------------
|
16
26
|
|
17
27
|
Create a pool of objects to share amongst the fibers or threads in your Ruby application:
|
18
28
|
|
19
|
-
|
29
|
+
``` ruby
|
30
|
+
@memcached = ConnectionPool.new(:size => 5, :timeout => 5) { Dalli::Client.new }
|
31
|
+
```
|
20
32
|
|
21
33
|
Then use the pool in your application:
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
|
35
|
+
``` ruby
|
36
|
+
@memcached.with do |dalli|
|
37
|
+
dalli.get('some-count')
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
If all the objects in the connection pool are in use, `with` will block
|
42
|
+
until one becomes available. If no object is available within `:timeout` seconds,
|
43
|
+
`with` will raise a `Timeout::Error`.
|
26
44
|
|
27
45
|
You can use `ConnectionPool::Wrapper` to wrap a single global connection, making
|
28
46
|
it easier to port your connection code over time:
|
29
47
|
|
30
|
-
|
31
|
-
|
32
|
-
|
48
|
+
``` ruby
|
49
|
+
$redis = ConnectionPool::Wrapper.new(:size => 5, :timeout => 3) { Redis.connect }
|
50
|
+
$redis.sadd('foo', 1)
|
51
|
+
$redis.smembers('foo')
|
52
|
+
```
|
33
53
|
|
34
54
|
The Wrapper uses `method_missing` to checkout a connection, run the
|
35
55
|
requested method and then immediately check the connection back into the
|
36
56
|
pool. It's **not** high-performance so you'll want to port your
|
37
|
-
performance sensitive code to use `
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
57
|
+
performance sensitive code to use `with` as soon as possible.
|
58
|
+
|
59
|
+
``` ruby
|
60
|
+
$redis.with do |conn|
|
61
|
+
conn.sadd('foo', 1)
|
62
|
+
conn.smembers('foo')
|
63
|
+
end
|
64
|
+
```
|
43
65
|
|
44
66
|
Once you've ported your entire system to use `with`, you can simply
|
45
67
|
remove ::Wrapper and use a simple, fast ConnectionPool.
|
data/Rakefile
CHANGED
data/connection_pool.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Mike Perham"]
|
9
9
|
s.email = ["mperham@gmail.com"]
|
10
|
-
s.homepage = ""
|
10
|
+
s.homepage = "https://github.com/mperham/connection_pool"
|
11
11
|
s.description = s.summary = %q{Generic connection pool for Ruby}
|
12
12
|
|
13
13
|
s.files = `git ls-files`.split("\n")
|
data/lib/connection_pool.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'connection_pool/version'
|
2
|
+
require_relative 'timed_queue'
|
3
3
|
|
4
4
|
# Generic connection pool class for e.g. sharing a limited number of network connections
|
5
5
|
# among many threads. Note: Connections are eager created.
|
@@ -25,19 +25,19 @@ require 'timed_queue'
|
|
25
25
|
# - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds
|
26
26
|
#
|
27
27
|
class ConnectionPool
|
28
|
-
DEFAULTS = {
|
28
|
+
DEFAULTS = {size: 5, timeout: 5}
|
29
29
|
|
30
30
|
def self.wrap(options, &block)
|
31
31
|
Wrapper.new(options, &block)
|
32
32
|
end
|
33
33
|
|
34
|
-
def initialize(options={}, &block)
|
34
|
+
def initialize(options = {}, &block)
|
35
35
|
raise ArgumentError, 'Connection pool requires a block' unless block
|
36
36
|
|
37
37
|
options = DEFAULTS.merge(options)
|
38
38
|
|
39
|
-
@size = options
|
40
|
-
@timeout = options
|
39
|
+
@size = options.fetch(:size)
|
40
|
+
@timeout = options.fetch(:timeout)
|
41
41
|
|
42
42
|
@available = ::TimedQueue.new(@size, &block)
|
43
43
|
@key = :"current-#{@available.object_id}"
|
@@ -51,7 +51,11 @@ class ConnectionPool
|
|
51
51
|
checkin
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
|
+
def with_connection(&block)
|
56
|
+
warn("ConnectionPool#with_connection is deprecated and will be removed in version 1.0. Upgrade your code to use ConnectionPool#with instead. (in #{caller[0]})")
|
57
|
+
with(&block)
|
58
|
+
end
|
55
59
|
|
56
60
|
def checkout
|
57
61
|
stack = ::Thread.current[@key] ||= []
|
@@ -75,7 +79,9 @@ class ConnectionPool
|
|
75
79
|
nil
|
76
80
|
end
|
77
81
|
|
78
|
-
class Wrapper
|
82
|
+
class Wrapper < ::BasicObject
|
83
|
+
METHODS = [:with]
|
84
|
+
|
79
85
|
def initialize(options = {}, &block)
|
80
86
|
@pool = ::ConnectionPool.new(options, &block)
|
81
87
|
end
|
@@ -85,7 +91,15 @@ class ConnectionPool
|
|
85
91
|
ensure
|
86
92
|
@pool.checkin
|
87
93
|
end
|
88
|
-
|
94
|
+
|
95
|
+
def with_connection(&block)
|
96
|
+
warn("ConnectionPool::Wrapper#with_connection is deprecated and will be removed in version 1.0. Upgrade your code to use ConnectionPool::Wrapper#with instead. (in #{caller[0]})")
|
97
|
+
with(&block)
|
98
|
+
end
|
99
|
+
|
100
|
+
def respond_to?(id, *args)
|
101
|
+
METHODS.include?(id) || @pool.with { |c| c.respond_to?(id, *args) }
|
102
|
+
end
|
89
103
|
|
90
104
|
def method_missing(name, *args, &block)
|
91
105
|
@pool.with do |connection|
|
data/lib/timed_queue.rb
CHANGED
@@ -20,7 +20,7 @@ class TimedQueue
|
|
20
20
|
deadline = Time.now + timeout
|
21
21
|
@mutex.synchronize do
|
22
22
|
loop do
|
23
|
-
return @que.
|
23
|
+
return @que.pop unless @que.empty?
|
24
24
|
to_wait = deadline - Time.now
|
25
25
|
raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0
|
26
26
|
@resource.wait(@mutex, to_wait)
|
data/test/helper.rb
CHANGED
@@ -2,8 +2,6 @@ require 'rubygems'
|
|
2
2
|
require 'minitest/pride'
|
3
3
|
require 'minitest/autorun'
|
4
4
|
|
5
|
-
require 'connection_pool'
|
6
|
-
|
7
5
|
puts RUBY_DESCRIPTION
|
8
6
|
|
9
7
|
class MiniTest::Unit::TestCase
|
@@ -15,3 +13,7 @@ class MiniTest::Unit::TestCase
|
|
15
13
|
end
|
16
14
|
|
17
15
|
end
|
16
|
+
|
17
|
+
$VERBOSE = 1
|
18
|
+
|
19
|
+
require_relative '../lib/connection_pool'
|
@@ -7,19 +7,26 @@ class TestConnectionPool < MiniTest::Unit::TestCase
|
|
7
7
|
def initialize
|
8
8
|
@x = 0
|
9
9
|
end
|
10
|
+
|
10
11
|
def do_something
|
11
12
|
@x += 1
|
12
13
|
sleep 0.05
|
13
14
|
@x
|
14
15
|
end
|
16
|
+
|
15
17
|
def fast
|
16
18
|
@x += 1
|
17
19
|
end
|
20
|
+
|
18
21
|
def do_something_with_block
|
19
22
|
@x += yield
|
20
23
|
sleep 0.05
|
21
24
|
@x
|
22
25
|
end
|
26
|
+
|
27
|
+
def respond_to?(method_id, *args)
|
28
|
+
method_id == :do_magic || super(method_id, *args)
|
29
|
+
end
|
23
30
|
end
|
24
31
|
|
25
32
|
def test_basic_multithreaded_usage
|
@@ -27,7 +34,7 @@ class TestConnectionPool < MiniTest::Unit::TestCase
|
|
27
34
|
threads = []
|
28
35
|
15.times do
|
29
36
|
threads << Thread.new do
|
30
|
-
pool.
|
37
|
+
pool.with do |net|
|
31
38
|
net.do_something
|
32
39
|
end
|
33
40
|
end
|
@@ -67,9 +74,17 @@ class TestConnectionPool < MiniTest::Unit::TestCase
|
|
67
74
|
assert_equal 6, pool.with { |net| net.fast }
|
68
75
|
end
|
69
76
|
|
77
|
+
def test_passthru_respond_to
|
78
|
+
pool = ConnectionPool.wrap(:timeout => 0.1, :size => 1) { NetworkConnection.new }
|
79
|
+
assert pool.respond_to?(:with)
|
80
|
+
assert pool.respond_to?(:do_something)
|
81
|
+
assert pool.respond_to?(:do_magic)
|
82
|
+
refute pool.respond_to?(:do_lots_of_magic)
|
83
|
+
end
|
84
|
+
|
70
85
|
def test_return_value
|
71
86
|
pool = ConnectionPool.new(:timeout => 0.1, :size => 1) { NetworkConnection.new }
|
72
|
-
result = pool.
|
87
|
+
result = pool.with do |net|
|
73
88
|
net.fast
|
74
89
|
end
|
75
90
|
assert_equal 1, result
|
@@ -87,6 +102,16 @@ class TestConnectionPool < MiniTest::Unit::TestCase
|
|
87
102
|
sleep 0.5
|
88
103
|
end
|
89
104
|
|
105
|
+
def test_reuses_objects_when_pool_not_saturated
|
106
|
+
pool = ConnectionPool.new(:size => 5) { NetworkConnection.new }
|
107
|
+
|
108
|
+
ids = 10.times.map do
|
109
|
+
pool.with { |c| c.object_id }
|
110
|
+
end
|
111
|
+
|
112
|
+
assert_equal 1, ids.uniq.size
|
113
|
+
end
|
114
|
+
|
90
115
|
class Recorder
|
91
116
|
def initialize
|
92
117
|
@calls = []
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: connection_pool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3
|
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
|
+
date: 2012-12-19 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Generic connection pool for Ruby
|
15
15
|
email:
|
@@ -30,7 +30,7 @@ files:
|
|
30
30
|
- lib/timed_queue.rb
|
31
31
|
- test/helper.rb
|
32
32
|
- test/test_connection_pool.rb
|
33
|
-
homepage:
|
33
|
+
homepage: https://github.com/mperham/connection_pool
|
34
34
|
licenses: []
|
35
35
|
post_install_message:
|
36
36
|
rdoc_options: []
|
@@ -50,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
50
|
version: '0'
|
51
51
|
requirements: []
|
52
52
|
rubyforge_project:
|
53
|
-
rubygems_version: 1.8.
|
53
|
+
rubygems_version: 1.8.24
|
54
54
|
signing_key:
|
55
55
|
specification_version: 3
|
56
56
|
summary: Generic connection pool for Ruby
|