connection_pool 0.9.2 → 0.9.3
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.
- 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
|