connection_pool 2.0.0 → 2.1.0
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.
- checksums.yaml +4 -4
- data/Changes.md +8 -0
- data/README.md +13 -0
- data/lib/connection_pool.rb +1 -1
- data/lib/connection_pool/timed_stack.rb +116 -12
- data/lib/connection_pool/version.rb +1 -1
- data/test/test_connection_pool.rb +5 -0
- data/test/test_connection_pool_timed_stack.rb +8 -0
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d46787d5f1cdf8901aff57ded2eb518418fea245
|
4
|
+
data.tar.gz: 0ffd3058f4269e9155070e901dd4eb29db2e81d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9adff3406500853bcf8fcd480cce510cab1cf03b3d31cf2429648e92973b012000ba9d4a8e252efbce486f38f00b7df86527073d9d3f0212e967d8624675fe03
|
7
|
+
data.tar.gz: 609a9f24d0472bf9df5989e6830118873a9ae779738945e80c7b5e7010aa205b545af949fc4fa2233ccb5bb4379e9b54d2118f42c4900ac81bb262e790b53a53
|
data/Changes.md
CHANGED
data/README.md
CHANGED
@@ -68,6 +68,19 @@ end
|
|
68
68
|
Once you've ported your entire system to use `with`, you can simply remove
|
69
69
|
`Wrapper` and use the simpler and faster `ConnectionPool`.
|
70
70
|
|
71
|
+
You can shut down a ConnectionPool instance once it should no longer be used.
|
72
|
+
Further checkout attempts will immediately raise an error but existing checkouts
|
73
|
+
will work.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
cp = ConnectionPool.new { Redis.new }
|
77
|
+
cp.shutdown { |conn| conn.close }
|
78
|
+
```
|
79
|
+
|
80
|
+
Shutting down a connection pool will block until all connections are checked in and closed.
|
81
|
+
Note that shutting down is completely optional; Ruby's garbage collector will reclaim
|
82
|
+
unreferenced pools under normal circumstances.
|
83
|
+
|
71
84
|
|
72
85
|
Notes
|
73
86
|
-----
|
data/lib/connection_pool.rb
CHANGED
@@ -1,10 +1,37 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'timeout'
|
3
3
|
|
4
|
+
##
|
5
|
+
# Raised when you attempt to retrieve a connection from a pool that has been
|
6
|
+
# shut down.
|
7
|
+
|
4
8
|
class ConnectionPool::PoolShuttingDownError < RuntimeError; end
|
5
9
|
|
10
|
+
##
|
11
|
+
# The TimedStack manages a pool of homogeneous connections (or any resource
|
12
|
+
# you wish to manage). Connections are created lazily up to a given maximum
|
13
|
+
# number.
|
14
|
+
|
15
|
+
# Examples:
|
16
|
+
#
|
17
|
+
# ts = TimedStack.new(1) { MyConnection.new }
|
18
|
+
#
|
19
|
+
# # fetch a connection
|
20
|
+
# conn = ts.pop
|
21
|
+
#
|
22
|
+
# # return a connection
|
23
|
+
# ts.push conn
|
24
|
+
#
|
25
|
+
# conn = ts.pop
|
26
|
+
# ts.pop timeout: 5
|
27
|
+
# #=> raises Timeout::Error after 5 seconds
|
28
|
+
|
6
29
|
class ConnectionPool::TimedStack
|
7
30
|
|
31
|
+
##
|
32
|
+
# Creates a new pool with +size+ connections that are created from the given
|
33
|
+
# +block+.
|
34
|
+
|
8
35
|
def initialize(size = 0, &block)
|
9
36
|
@create_block = block
|
10
37
|
@created = 0
|
@@ -15,12 +42,16 @@ class ConnectionPool::TimedStack
|
|
15
42
|
@shutdown_block = nil
|
16
43
|
end
|
17
44
|
|
18
|
-
|
45
|
+
##
|
46
|
+
# Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be
|
47
|
+
# used by subclasses that extend TimedStack.
|
48
|
+
|
49
|
+
def push(obj, options = {})
|
19
50
|
@mutex.synchronize do
|
20
51
|
if @shutdown_block
|
21
52
|
@shutdown_block.call(obj)
|
22
53
|
else
|
23
|
-
|
54
|
+
store_connection obj, options
|
24
55
|
end
|
25
56
|
|
26
57
|
@resource.broadcast
|
@@ -28,16 +59,28 @@ class ConnectionPool::TimedStack
|
|
28
59
|
end
|
29
60
|
alias_method :<<, :push
|
30
61
|
|
31
|
-
|
62
|
+
##
|
63
|
+
# Retrieves a connection from the stack. If a connection is available it is
|
64
|
+
# immediately returned. If no connection is available within the given
|
65
|
+
# timeout a Timeout::Error is raised.
|
66
|
+
#
|
67
|
+
# +:timeout+ is the only checked entry in +options+ and is preferred over
|
68
|
+
# the +timeout+ argument (which will be removed in a future release). Other
|
69
|
+
# options may be used by subclasses that extend TimedStack.
|
70
|
+
|
71
|
+
def pop(timeout = 0.5, options = {})
|
72
|
+
options, timeout = timeout, 0.5 if Hash === timeout
|
73
|
+
timeout = options.fetch :timeout, timeout
|
74
|
+
|
32
75
|
deadline = Time.now + timeout
|
33
76
|
@mutex.synchronize do
|
34
77
|
loop do
|
35
78
|
raise ConnectionPool::PoolShuttingDownError if @shutdown_block
|
36
|
-
return
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
79
|
+
return fetch_connection(options) if connection_stored?(options)
|
80
|
+
|
81
|
+
connection = try_create(options)
|
82
|
+
return connection if connection
|
83
|
+
|
41
84
|
to_wait = deadline - Time.now
|
42
85
|
raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0
|
43
86
|
@resource.wait(@mutex, to_wait)
|
@@ -45,6 +88,10 @@ class ConnectionPool::TimedStack
|
|
45
88
|
end
|
46
89
|
end
|
47
90
|
|
91
|
+
##
|
92
|
+
# Shuts down the TimedStack which prevents connections from being checked
|
93
|
+
# out. The +block+ is called once for each connection on the stack.
|
94
|
+
|
48
95
|
def shutdown(&block)
|
49
96
|
raise ArgumentError, "shutdown must receive a block" unless block_given?
|
50
97
|
|
@@ -52,18 +99,75 @@ class ConnectionPool::TimedStack
|
|
52
99
|
@shutdown_block = block
|
53
100
|
@resource.broadcast
|
54
101
|
|
55
|
-
|
56
|
-
conn = @que.pop
|
57
|
-
block.call(conn)
|
58
|
-
end
|
102
|
+
shutdown_connections
|
59
103
|
end
|
60
104
|
end
|
61
105
|
|
106
|
+
##
|
107
|
+
# Returns +true+ if there are no available connections.
|
108
|
+
|
62
109
|
def empty?
|
63
110
|
(@created - @que.length) >= @max
|
64
111
|
end
|
65
112
|
|
113
|
+
##
|
114
|
+
# The number of connections available on the stack.
|
115
|
+
|
66
116
|
def length
|
67
117
|
@max - @created + @que.length
|
68
118
|
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
##
|
123
|
+
# This is an extension point for TimedStack and is called with a mutex.
|
124
|
+
#
|
125
|
+
# This method must returns true if a connection is available on the stack.
|
126
|
+
|
127
|
+
def connection_stored?(options = nil)
|
128
|
+
!@que.empty?
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# This is an extension point for TimedStack and is called with a mutex.
|
133
|
+
#
|
134
|
+
# This method must return a connection from the stack.
|
135
|
+
|
136
|
+
def fetch_connection(options = nil)
|
137
|
+
@que.pop
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# This is an extension point for TimedStack and is called with a mutex.
|
142
|
+
#
|
143
|
+
# This method must shut down all connections on the stack.
|
144
|
+
|
145
|
+
def shutdown_connections(options = nil)
|
146
|
+
while connection_stored?(options)
|
147
|
+
conn = fetch_connection(options)
|
148
|
+
@shutdown_block.call(conn)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# This is an extension point for TimedStack and is called with a mutex.
|
154
|
+
#
|
155
|
+
# This method must return +obj+ to the stack.
|
156
|
+
|
157
|
+
def store_connection(obj, options = nil)
|
158
|
+
@que.push obj
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# This is an extension point for TimedStack and is called with a mutex.
|
163
|
+
#
|
164
|
+
# This method must create a connection if and only if the total number of
|
165
|
+
# connections allowed has not been met.
|
166
|
+
|
167
|
+
def try_create(options = nil)
|
168
|
+
unless @created == @max
|
169
|
+
@created += 1
|
170
|
+
@create_block.call
|
171
|
+
end
|
172
|
+
end
|
69
173
|
end
|
@@ -147,6 +147,11 @@ class TestConnectionPool < Minitest::Test
|
|
147
147
|
assert_same conn, t2.value
|
148
148
|
end
|
149
149
|
|
150
|
+
def test_returns_value
|
151
|
+
pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
|
152
|
+
assert_equal 1, pool.with {|o| 1 }
|
153
|
+
end
|
154
|
+
|
150
155
|
def test_checkin_never_checkout
|
151
156
|
pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
|
152
157
|
|
@@ -44,6 +44,14 @@ class TestConnectionPoolTimedStack < Minitest::Test
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_pop_empty
|
47
|
+
e = assert_raises Timeout::Error do
|
48
|
+
@stack.pop timeout: 0
|
49
|
+
end
|
50
|
+
|
51
|
+
assert_equal 'Waited 0 sec', e.message
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_pop_empty_2_0_compatibility
|
47
55
|
e = assert_raises Timeout::Error do
|
48
56
|
@stack.pop 0
|
49
57
|
end
|
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: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
@@ -9,34 +9,34 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: 5.0.0
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 5.0.0
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
description: Generic connection pool for Ruby
|
@@ -47,8 +47,8 @@ executables: []
|
|
47
47
|
extensions: []
|
48
48
|
extra_rdoc_files: []
|
49
49
|
files:
|
50
|
-
- .gitignore
|
51
|
-
- .travis.yml
|
50
|
+
- ".gitignore"
|
51
|
+
- ".travis.yml"
|
52
52
|
- Changes.md
|
53
53
|
- Gemfile
|
54
54
|
- LICENSE
|
@@ -71,17 +71,17 @@ require_paths:
|
|
71
71
|
- lib
|
72
72
|
required_ruby_version: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- -
|
74
|
+
- - ">="
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '0'
|
77
77
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
|
-
- -
|
79
|
+
- - ">="
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '0'
|
82
82
|
requirements: []
|
83
83
|
rubyforge_project:
|
84
|
-
rubygems_version: 2.
|
84
|
+
rubygems_version: 2.4.1
|
85
85
|
signing_key:
|
86
86
|
specification_version: 4
|
87
87
|
summary: Generic connection pool for Ruby
|